'panel-dispositivos' y 'panel-switcher' en conflicto
@mickeyDominic colocas todos los paneles por defecto bajo el mismo objeto '''js Paneles: { Valores predeterminados: [{ id: 'capas', EL: '.panelright', // ... id: 'conmutador de panel', EL: '.panelswitcher', }] }
Lee la respuesta completa abajo ↓Pregunta
Versión GrapesJS
- Confirmo que se debe usar la última versión de GrapesJS
¿Qué navegador usas?
Versión de Chrome 103.0.5060.114
Enlace de demo reproducible
https://codepen.io/Dominic_M/pen/eYMgqyw
Describe el bicho
¿Cómo reproducir el bicho?
- Sigue GrapesJS "Comenzando" >> https://grapesjs.com/docs/getting-started.html
- Continúa con el tutorial hasta "Plantillas Responsive (https://grapesjs.com/docs/getting-started.html#responsive-templates)", donde te darás cuenta de que tras añadir un panel para cambiar entre la vista móvil y la de escritorio, un panel reemplaza al otro.
¿Cuál es el comportamiento esperado? 'panel-dispositivos' y 'panel-switcher' deberían aparecer uno al lado del otro sin fallos
¿Cuál es el comportamiento actual? 'panel-dispositivos' y 'panel-switcher' NO deberían aparecer uno al lado del otro sin fallos
Si es necesario ejecutar algo de código para reproducir el error, pégalo aquí abajo: '''html Tu código aquí
<!DOCTYPE html> <html> <head> <title>CMS...</title> <meta charset="UTF-8"> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <link rel="stylesheet" href="https://unpkg.com/grapesjs/dist/css/grapes.min.css">
<script src="https://unpkg.com/[email protected]/dist/grapes.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="panel__top">
<div class="panel__basic-actions"></div>
<div class="panel__devices"></div>
<div class="panel__switcher"></div>
</div>
<div class="editor-row">
<div class="editor-canvas">
<div id="gjs"><h1>¡Hola Componente Mundial!</h1></div>
</div>
<div class="panel__right">
<div class="layers-container"></div>
<div class="styles-container"></div>
<div class="traits-container"></div>
</div>
</div>
<div id="bloques"></div>
<script src="script.js"></script>
</body>
</html>
'''css
Tu código aquí
/* Resaltemos los límites del lienzo */
#gjs {
borde: 3px sólido #444;
}
/* Reiniciar algo de estilo predeterminado */
.gjs-cv-canvas {
arriba: 0;
ancho: 100%;
altura: 100%;
}
.gjs-block {
Ancho: Auto;
Altura: Auto;
Altura mínima: Auto;
}
.panel__top {
relleno: 0;
ancho: 100%;
pantalla: flex;
posición: inicial;
justificar-contenido: centro;
justificar-contenido: espacio-entre;
}
.panel__basic-acciones {
posición: inicial;
}
.editor-row {
pantalla: flex;
Justificar-contenido: Inicio flexible;
Alinear-ítems: estiramiento;
Flex-wrap: sin wrap;
Altura: 300px;
}
.editor-canvas {
flex-grow: 1;
}
.panel__right {
Base flexible: 230px;
posición: relativa;
desbordamiento: auto;
}
.panel__switcher {
posición: inicial;
}
.panel__devices {
posición: inicial;
}
'''js Tu código aquí const editor = grapesjs.init({ Indica dónde iniciar el editor en el editor. También puedes aprobar un HTMLElement Contenedor: '#gjs', Consigue el contenido del lienzo directamente del elemento Como alternativa, podríamos usar: 'components: '<h1>¡Hello World Component!</h1>' `, fromElement: cierto, Tamaño del editor Altura: '300px', Ancho: 'Auto', Desactiva el gestor de almacenamiento por el momento storageManager: false, /// Evita cualquier panel por defecto paneles: { predeterminados: [] },/ blockManager: { appendTo: '#blocks', Bloqueos: [ { ID: 'Sección', // ID es obligatorio label: '<b>Section</b>', // Puedes usar HTML/SVG dentro de las etiquetas atributos: { Class:'GJS-Block-section' }, contenido: '<section><h1>Este es un título sencillo</h1><div>Esto es solo un texto de Lolorem: Lorem ipsum dolor sit amet</div></section>', }, { id: 'texto', etiqueta: 'Texto', contenido: '<div data-gjs-type="text">Inserta tu texto aquí</div>', }, { id: 'imagen', etiqueta: 'Image', Selecciona el componente una vez que se haya soltado select: cierto, Puedes pasar componentes como JSON en lugar de una simple cadena HTML, En este caso también usamos un tipo de componente definido llamado 'imagen' Contenido: { Tipo: 'Imagen' }, Esto activa un evento 'activo' en componentes caídos y en la 'imagen' reacciona abriendo el AssetManager ACTIVAR: Cierto, } ] }, layerManager: { appendTo: '.layers-container' }, deviceManager: { dispositivos: [{ nombre: 'Escritorio', Ancho: '', // tamaño por defecto }, { nombre: 'Mobile', Ancho: '320px', // Este valor se usará en el ancho del lienzo widthMedia: '480px', // este valor se usará en CSS @media }] }, Definimos un panel por defecto como una barra lateral para contener capas Paneles: { Valores predeterminados: [{ id: 'capas', EL: '.panel__right', Haz que el panel sea redimensionable Redimensionable: { maxDim: 350, minDim: 200, TC: 0, // Mejor manejador cl: 1, // Manejador izquierdo cr: 0, // Manejador derecho bc: 0, // Manipulador de abajo Siendo un hijo flexible, necesitamos cambiar la propiedad de 'flex-base' en lugar del 'ancho' (por defecto) keyWidth: 'flex-base', }, id: 'conmutador de panel', EL: '.panel__switcher', botones: [ { id: 'capas de exhibición', ACTIVO: Cierto, etiqueta: 'Layers', Orden: 'Mostrar capas', Una vez activada, desactiva la posibilidad de desactivarlo Activable: falso, }, { id: 'estilo de espectáculo', ACTIVO: Cierto, etiqueta: 'Styles', Orden: 'Estilos de Exhibición', Activable: falso, }, { id: 'Rasgos de exhibición', ACTIVO: Cierto, etiqueta: 'Rasgos', Orden: 'Mostrar Rasgos', Activable: falso, } ], id: 'panel-dispositivos', EL: '.panel__devices', botones: [{ id: 'dispositivo-escritorio', etiqueta: 'D', comando: 'establecer-dispositivo-escritorio', ACTIVO: Cierto, Activable: falso, }, { id: 'dispositivo-móvil', etiqueta: 'M', comando: 'establecer-dispositivo-móvil', Activable: falso, }], }] }, traitManager: { append To: '.rasgos-contenedor', }, El Selector Manager permite asignar clases y diferentes estados (por ejemplo: hundir) en los componentes. Generalmente, se usa junto con Style Manager Pero no es obligatorio selectorManager: { appendTo: '.estilos-contenedor' }, StyleManager: { append To: '.estilos-contenedor', Sectores: [{ nombre: 'Dimension', abierto: falso, Uso de propiedades integradas buildProps: ['ancho', 'min-height', 'acolchado'], Usa 'propiedades' para definir o anular una sola propiedad Propiedades: [ { Tipo de entrada, opciones: entero | Radio | select | color | deslizador | archivo | compuesto | Stack tipo: 'entero', nombre: 'El ancho', // Etiqueta para la propiedad propiedad: 'width', // propiedad CSS (si buildProps la incluye, se extenderá) unidades: ['px', '%'], // Unidades, disponibles solo para tipos 'enteros' valores por defecto: 'auto', // Valor por defecto min: 0, // Valor mínimo, disponible solo para tipos 'enteros' } ] },{ nombre: 'Extra', abierto: falso, buildProps: ['color de fondo', 'sombra de caja', 'prop personalizado'], Propiedades: [{ ID: 'Atrezzo personalizado', nombre: 'Custom Label', Propiedad: 'tamaño de fuente', tipo: 'select', Valores predeterminados: '32px', Lista de opciones, disponibles solo para tipos 'select' y 'radio' Opciones: [ { valor: '12px', nombre: 'Tiny' }, { valor: '18px', nombre: 'Medium' }, { valor: '32px', nombre: 'Big' }, ], }] }] }, });
editor. Panels.addPanel({ id: 'panel-top', EL: '.panel__top', }); editor. Panels.addPanel({ id: 'Acciones-básicas', EL: '.panel__basic-acciones', botones: [ { Id: 'visibilidad', activo: true, // activo por defecto NombreClase: 'btn-toggle-borders', etiqueta: '<u>B</u>', comando: 'sw-visibility', // Comando incorporado }, { id: 'exportar', NombreClase: 'btn-open-export', etiqueta: 'Exp', comando: 'export-plantilla', contexto: 'export-plantilla', // Para agrupar el contexto de botones del mismo panel }, { id: 'show-json', NombreClase: 'btn-show-json', etiqueta: 'JSON', Contexto: 'show-json', comando(editor) { editor. Modal.setTitle('Components JSON') .setContent('<textarea style="width:100%; height: 250px;"> ${JSON.stringify(editor.getComponents())} ')</textarea> .open(); }, } ], });
Definir comandos editor. Commands.add('show-layers', { getRowEl(editor) { return editor.getContainer().closest('.editor-row'); }, getLayersEl(row) { return row.querySelector('.layers-container') },
run(editor, sendero) { const lmEl = this.getLayersEl(this.getRowEl(editor)); lmEl.style.display = ''; }, stop(editor, remitente) { const lmEl = this.getLayersEl(this.getRowEl(editor)); lmEl.style.display = 'ninguno'; }, }); editor. Commands.add('show-styles', { getRowEl(editor) { return editor.getContainer().closest('.editor-row'); }, getStyleEl(row) { return row.querySelector('.styles-container') },
run(editor, sendero) { const smEl = this.getStyleEl(this.getRowEl(editor)); smEl.style.display = ''; }, stop(editor, remitente) { const smEl = this.getStyleEl(this.getRowEl(editor)); smEl.style.display = 'ninguno'; }, }); editor. Commands.add('show-traits', { getTraitsEl(editor) { const row = editor.getContainer().closest('.editor-row'); return row.querySelector('.traits-container'); }, run(editor, sendero) { this.getTraitsEl(editor).style.display = ''; }, stop(editor, remitente) { this.getTraitsEl(editor).style.display = 'ninguno'; }, }); editor. Commands.add('set-device-desktop', { run: editor => editor.setDevice('Desktop') }); editor. Commands.add('set-device-mobile', { run: editor => editor.setDevice('Mobile') });
Esto es lo que se espera
! [GJS esperado](https://user-images.githubusercontent.com/60381147/179505665-95e222a1-25a8-4e91-9b63-e6bb861f7f42.PNG)
Y este es el resultado actual
! [resultado GJS](https://user-images.githubusercontent.com/60381147/179505875-0444a4a1-8d9a-43a4-8a2a-d4c827bdad33.PNG)
### Código de conducta
- [X] Acepto seguir el Código de Conducta de este proyecto
Respuestas (3)
@mickeyDominic colocas todos los paneles por defecto bajo el mismo objeto '''js Paneles: { Valores predeterminados: [{ id: 'capas', EL: '.panel__right', // ... id: 'conmutador de panel', EL: '.panel__switcher', }] }
Donde debería haber un objeto por panel
'''js
Paneles: {
Valores por defecto: [
{
id: 'capas',
EL: '.panel__right',
// ...
}, {
id: 'conmutador de panel',
EL: '.panel__switcher',
// ...
}
]
}
Gracias, @artf.
Qué tonta :)
Gracias por informar de esto, @mickeyDominic.
Buena pregunta sobre 'panel-dispositivos' y 'panel-switcher' que están en conflicto. El enfoque recomendado con ProseMirror es usar la API orientada a eventos.
Empieza aquí:
- Consulta la documentación de GrapesJS de tu módulo específico
- Busca el método del oyente de eventos 'on()'
- La mayoría de las operaciones se pueden realizar escuchando eventos del editor y de los componentes
Patrones comunes: '''javascript Prestad atención a los cambios editor.on('Change', () => console.log('Something Changed'));
Ciclo de vida de los componentes editor.on('component:mount', (c) => console.log('component ready', c)); editor.on('component:update', (c) => console.log('component updated', c));
**Si sigues atascado:**
- Compartir una reproducción mínima de CodeSandbox
- Incluye lo que ya has probado
- Menciona tu versión GrapesJS
- ¡La comunidad está aquí para ayudar!
Preguntas y respuestas relacionadas
Continúa investigando con debates sobre temas similares.
Issue #4447
El responsable de estilo no refleja con precisión el color heredado
Versión GrapesJS [X] Confirmo que se debe usar la última versión de GrapesJS ¿Qué navegador usas? 103.0.5060.114 Enlace de demo reproducibl...
Issue #5460
Cargando 'component' y 'styles' desde 'pageManager'
Versión GrapesJS[X] Confirmo que se debe usar la última versión de GrapesJS¿Qué navegador usas? Chrome v117.0.5938.149Enlace de demo reprod...
Issue #5175
El método de movimiento no funciona como se espera
Versión GrapesJS [X] Confirmo que se debe usar la última versión de GrapesJS ¿Qué navegador usas? Chrome Enlace de demo reproducible https:...
Issue #4371
Todos los editores se rompieron tras la última actualización que rompió el administrador de almacenamiento.
Versión GrapesJS [X] Confirmo que se debe usar la última versión de GrapesJS ¿Qué navegador usas? Chrome Enlace de demo reproducible https:...
Plugins de pago que cumplen con este problema
Seleccionado por temas clave y relevancia de etiquetas para ayudarte a enviar más rápido.
Cargando recomendaciones de plugins de pago...
Consulta los plugins de código abierto de GrapesJS en GitHub O haz una búsqueda rápida en nuestro catálogo gratuito.
Explora plugins gratuitos →Los plugins premium incluyen soporte, actualizaciones regulares y funciones listas para producción — ahorrando días de trabajo de integración.
Explora plugins premium →Explorar categorías de plugins
Ve directamente a las páginas de categorías de plugins en el marketplace.