Los elementos hijos no se pueden arrastrar, se pueden soltar y se pueden resaltar. también el CSS de todos los elementos hijos que no se insertan en la sección de estilo mientras se desarrolla un componente banner en un plugin
En la definición de tu modelo component, usas 'content: config.template' pero debería ser 'components: config.template'
Lee la respuesta completa abajo ↓Pregunta
Hola @artf,
Estoy intentando desarrollar un plugin sencillo para banners que incluya un encabezado, un subtítulo y un enlace. y cada elemento puede ser arrastrable, soltable y resaltado, pero según el código inferior alguna parte del código no funciona. Por favor, ayudadme
! imagen
solo la clase banner CSS empujada, pero otro no ir en la sección de CSS
! [imagen](https://user-images.githubusercontent.com/17553816/120482976-4c426b80-c3cf-11eb-816a-689cf7d8b608.png)
------------ index.js----------
! [imagen](https://user-images.githubusercontent.com/17553816/120481948-46985600-c3ce-11eb-8239-7f1d28242320.png)
importar loadComponents desde './components';
importar loadBlocks desde './blocks';
Export default (editor, opts = {}) => {
const options = {... {
Opciones por defecto
bannerBlock: {},
claseEstandarte: "estandarte",
Plantilla: '
<div><h2 class="banner__heading">Encabezado del banner</h2></div>
<div> <h3 class="banner__subheading">Encabezado del subtítulo</h3></div>
<div> <a class="banner__link" href="#">Empieza</a></div>
`,
estilo: '
.banner {
Color de fondo: #c9efff;
Repetición de fondo: sin repetición;
Posición de antecedentes: Centro central;
Tamaño de fondo: Portada;
posición: relativa;
acolchado: 80px 20px;
radio de frontera:0;
pantalla: flex;
alinear-ítems: centro;
justificar-contenido: centro;
dirección flexible: columna;
Altura mínima: 370px;
}
.banner__heading {
Peso de fuente: 700;
color: #333;
tamaño de fuente: 40px;
margen inferior: 16px;
text-align: center;
altura de línea: 1,2;
}
.banner__subheading {
tamaño de fuente: 26px;
text-align: center;
Margen arriba: 16px;
Peso de fuente: 500;
color: #333;
}
.banner__link {
pantalla: bloqueo;
acolchado: 10px 20px;
Antecedentes: ninguno;
margen: 5px;
tamaño de fuente: 14px;
color: #fff !importante;
Color de fondo: #005A9E;
transición: todos los 0.2 se acomodan con facilidad;
Radio de frontera: 4px;
Peso de fuente: 500;
frontera: ¡ninguna importante!
text-align: center;
Ancho mínimo: 160px;
Espaciado entre letras: 1px;
}
`,
},
... OPS
};
Añadir componentes
loadComponents (editor, opciones);
Añadir bloques
loadBlocks (editor, opciones);
};
------------- Bloquear JS-------------
! [imagen](https://user-images.githubusercontent.com/17553816/120482131-70ea1380-c3ce-11eb-9624-700c200e45dc.png)
export default (editor, config = {}) => {
const bm = editor. Jefe de bloque;
const bannerBlock = config.bannerBlock;
const style = config.style;
Tipo const = "bannerblock";
const content = '<div data-gjs-type="${type}"></div>
${estilo? '<style>${estilo}</style>' : ""}';
bannerBlock & &
bm.add(type, {
etiqueta: "Banner",
categoría: 'Componentes',
Atributos: { Clase: "FA FA-List" },
activar: 1,
select: 1,
removible: cierto, // No se puede quitar
arrastrable: cierto, // No se puede mover
copiable: true, // Desactivar copiar/pegar
contenido,
... bannerBlock,
});
}
----------- Componente JS------------
! [imagen](https://user-images.githubusercontent.com/17553816/120482266-9414c300-c3ce-11eb-9132-2dad65d2d392.png)
export default (editor, config = {}) => {
const domc = editor. DomComponents;
Tipo const = 'bannerblock';
const classbanner = config.classBanner;
domc.addType(type, {
modelo: {
Predeterminados: {
Atributos: { Clase: Estandarte de Clase },
contenido: config.template,
Arrastrable: Cierto,
Droppable: Cierto,
Copiable: Cierto,
removible: cierto,
Seleccionable: Cierto,
},
},
Vista: {
},
});
};Respuestas (3)
En la definición de tu modelo component, usas 'content: config.template' pero debería ser 'components: config.template'
Hola @artf,
He buscado la solución, pero hay algunos problemas con los componentes. El componente hijo H2,H3 y Link presionaba para todos los demás componentes. Si suelto un componente de columna, esos elementos hijos también se empujan dentro de ahí. ¿Cómo puedo restringir el conflicto? A continuación, aquí está el ejemplo del codepen donde hice una demo. https://codepen.io/coderdesigners/full/XWMoNbZ
Si dejo una columna, la de abajo sube. Lo cual no es lo esperado. Debería ser así, según el valor por defecto. ! imagen
Cuando suelta el componente de banner. ! imagen
Por favor, por favor, ayúdame con esto. Sé que he cometido un error tonto que no puedo entender. Siento molestarte.
Gracias de antemano.
Y aquí están los detalles de mi plugin
! imagen exportar default { Objetar para extender el bloque de banner por defecto, por ejemplo, '{ etiqueta: 'Banner', atributos: { ... } } }` Pasa un valor falso para evitar añadir el bloque bannerBlock: {},
Objetar para extender las propiedades predeterminadas del banner, por ejemplo, '{ nombre: 'Mi Estandarte', droppable: false, ... }` bannerCreateProps: {},
Objeto para extender las propiedades predeterminadas del encabezado bannerHeadingProps: {},
Objetar para extender las propiedades predeterminadas de Subtítulo bannerSubHeadingProps: {},
Object para extender las propiedades predeterminadas del botón bannerButtonProps: {},
ID de componente de las tabulaciones tipoBanner: 'banner',
Identificador de componente TabContainer typeBannerHeading: 'Banner-Heading',
ID de componente de tabulación typeBannerSubHeading: 'Banner-Subheading',
ID de componente TabContent tipoBannerButton: 'Banner-Button',
Clase por defecto para usar en el Banner claseBannerContenedor: 'zslbanner',
Clase por defecto para usar en el Banner Encabezado de clase: 'zslbanner__heading',
Clase por defecto para usar en el Banner
Subtítulo: 'zslbanner__subheading',
Clase por defecto para usar en el Banner
claseLink: 'zslbanner__link',
Estilo predeterminado para las pestañas
style: (config) => '
.${config.classBannerContainer} {
familia tipográfica: 'Montserrat', Arial, sans-serif;
Color de fondo: #c9efff;
Repetición de fondo: sin repetición;
Posición de antecedentes: Centro central;
Tamaño de fondo: Portada;
posición: relativa;
acolchado: 80px 20px;
radio de frontera:0;
pantalla: flex;
alinear-ítems: centro;
justificar-contenido: centro;
dirección flexible: columna;
Altura mínima: 370px;
}
.${config.classHeading} {
Peso de fuente: 700;
color: #333;
tamaño de fuente: 40px;
marje:0;
margen inferior: 16px;
text-align: center;
altura de línea: 1,2;
}
.${config.classSubHeading} {
tamaño de fuente: 26px;
text-align: center;
marje:0;
margen inferior: 16px;
Peso de fuente: 500;
color: #333;
}
.${config.classLink} {
pantalla: bloqueo;
acolchado: 10px 20px;
Antecedentes: ninguno;
Margen: 20px 5px 5px 0 5px;
tamaño de fuente: 14px;
color: #fff !importante;
Color de fondo: #005A9E;
transición: todos los 0.2 se acomodan con facilidad;
Radio de frontera: 4px;
Peso de fuente: 500;
frontera: ¡ninguna importante!
text-align: center;
Ancho mínimo: 160px;
Espaciado entre letras: 1px;
}
.${config.classLink}:hover {
Color de fondo: #037ede;
}
`
}
! [imagen](https://user-images.githubusercontent.com/17553816/122001932-b6471180-cdce-11eb-822f-f81f75af60ef.png)
! [imagen](https://user-images.githubusercontent.com/17553816/122001962-c3640080-cdce-11eb-877a-56108e2adbba.png)
! [imagen](https://user-images.githubusercontent.com/17553816/122001992-cfe85900-cdce-11eb-8b1b-6c3fe60ee60f.png)
**Subheading.js**
rol de const export = 'Subtítulo';
Export default (DC, config) => {
dc.addType(config.typeBannerSubHeading, {
modelo: {
isComponent: function(t) {
return ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'p'].indexOf(t.tagName) >= 0
},
Predeterminados: {
nombre: 'Subtítulo',
Arrastrable: Cierto,
Copiable: Cierto,
removible: cierto,
Resaltable: Cierto,
Editable: Cierto,
atributos: { rol },
clases: config.classSubHeading,
etiquetaNombre: 'h3',
contenido: 'Subtítulo',
Rasgos: [
'id',
'título',
{
tipo: "select",
Opciones: [{
valor: "h1",
nombre: "Rumbo 1"
}, {
valor: "h2",
nombre: "Rumbo 2"
}, {
valor: "h3",
nombre: "Rumbo 3"
}, {
valor: "h4",
nombre: "Rumbo 4"
}, {
valor: "h5",
nombre: "Rumbo 5"
}, {
valor: "h6",
nombre: "Rumbo 6"
}, {
valor: "p",
nombre: "Paragraph"
}],
etiqueta: "Encabezado o párrafo",
nombre: "tagName",
cambioprop: 1
}
],
... config.bannerSubHeadingProps
},
},
Vista: {
eventos: {
dblclick: 'onActive',
Focusout: 'onDisable',
},
onActive() {
this.el.contentEditable = true;
},
onDisable() {
const { el, model } = this;
el.contentEditable = false;
model.set('content', el.innerHTML)
},
}
});
}
! [imagen](https://user-images.githubusercontent.com/17553816/122002066-e55d8300-cdce-11eb-8216-e91659cfaaad.png)
! [imagen](https://user-images.githubusercontent.com/17553816/122002133-fad2ad00-cdce-11eb-9aab-d3f02d37c78b.png)
**Heading.js**
export const role = 'Encabezado';
Export default (DC, config) => {
dc.addType(config.typeBannerHeading, {
modelo: {
isComponent: function(t) {
return ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'p'].indexOf(t.tagName) >= 0
},
Predeterminados: {
nombre: 'Heading',
Arrastrable: Cierto,
Copiable: Cierto,
removible: cierto,
Resaltable: Cierto,
Editable: Cierto,
atributos: { rol },
clases: config.classHeading,
etiquetaNombre: 'h2',
componentes: 'Rumbo de dirección',
Rasgos: [
'id',
'título',
{
tipo: "select",
Opciones: [{
valor: "h1",
nombre: "Rumbo 1"
}, {
valor: "h2",
nombre: "Rumbo 2"
}, {
valor: "h3",
nombre: "Rumbo 3"
}, {
valor: "h4",
nombre: "Rumbo 4"
}, {
valor: "h5",
nombre: "Rumbo 5"
}, {
valor: "h6",
nombre: "Rumbo 6"
}, {
valor: "p",
nombre: "Paragraph"
}],
etiqueta: "Encabezado o párrafo",
nombre: "tagName",
cambioprop: 1
}
],
... config.bannerHeadingProps
},
},
Vista: {
eventos: {
dblclick: 'onActive',
Focusout: 'onDisable',
},
onActive() {
this.el.contentEditable = true;
},
onDisable() {
const { el, model } = this;
el.contentEditable = false;
model.set('content', el.innerHTML)
},
}
});
}
**Button.js**
Export default (DC, config) => {
dc.addType(config.typeBannerButton, {
modelo: {
extiende: 'enlace',
Predeterminados: {
Editable: Cierto,
nombre: 'Button',
Arrastrable: Cierto,
Copiable: Cierto,
removible: cierto,
Resaltable: Cierto,
atributos: {
HFF: '#'
},
clases: config.classLink,
contenido: 'Empezar',
etiquetaNombre: 'a',
Rasgos: [
'id',
'título',
'href',
'objetivo',
],
... config.bannerButtonProps
},
},
Vista: {
eventos: {
dblclick: 'onActive',
Focusout: 'onDisable',
},
onActive() {
this.el.contentEditable = true;
},
onDisable() {
const { el, model } = this;
el.contentEditable = false;
model.set('content', el.innerHTML)
},
}
});
}
**BannerCreate.js**
Export default (DC, {
typeBanner,
typeBannerHeading,
typeBannerSubHeading,
typeBannerButton,
estilo,
... Configuración
}) => {
const type = config.typeBanner;
dc.addType(type, {
modelo: {
Predeterminados: {
nombre: 'Banner',
clases: config.classBannerContainer,
Componentes: [
{ tipo: tipoEncabezadoBanner },
{ tipo: tipoSubencabezadoBanner },
{ tipo: tipoBannerButton },
style && '<style>${style(config)}</style>'
],
... config.bannerCreateProps
},
},
});
}
Por favor, ayudadme.Gracias por informar de esto, @Palash-Mandal.
Buena pregunta sobre elementos hijos que no se pueden arrastrar y que se pueden resaltar soltando. también el CSS de todos los elementos hijos que no se han subido en la sección de estilo mientras se desarrolla un componente banner en AS plugin. 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 #3116
[AYUDA BUSCADA] Cómo cargar un CSS que se pueda ver en el visor de código y también exportarse mientras se guarda
Hola :wave: Estoy intentando cargar algo de CSS dentro del editor como parte del tema, puedo enlazar hojas de estilo como parte de la carga...
Issue #5049
Problema al arrastrar un componente compuesto por imagen y enlace
Versión GrapesJS [X] Confirmo que se debe usar la última versión de GrapesJS ¿Qué navegador usas? Versión de Brave Enlace de demo reproduci...
Issue #3627
[PREGUNTA]: Estoy intentando duplicar la página, pero los estilos no se aplican debido a los IDs, cambios a -2,-3 al final.
'''javascript const duplicatePage = (editor) => { sea components = editor.getHtml(); sea css = editor.getCss(); sea newPage = editor. Pages...
Issue #3119
[PREGUNTA] ¿Cómo crear un bloque personalizado hecho con componentes de grapesjs?
Hola, quiero que me hagan bloques personalizados con componentes de grapesjs. Encontré la solución para añadir componentes: https://github....
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 →Tutoriales relacionados
Guías detalladas sobre el mismo tema.
Tutorial
Ship to Production Faster: What’s New in GrapesJS Shadcn
Supercharge your page builder! GrapesJS Shadcn adds live drag previews, rich text / commands, dynamic data, and canvas presets to ship to prod faster.
Tutorial
How to Build a Production GrapesJS Editor: The Complete Walkthrough of Brief, Preset, Plugins, and Services
A complete walkthrough of building a production GrapesJS editor: how to choose a preset, pick plugins, and scope setup services without burning a sprint.
Tutorial
Embed GrapesJS in Your SaaS: A Weekend Guide
Embed GrapesJS in your SaaS and ship a white-label page builder over a weekend. Honest tradeoffs, real code, and the plugins that close the UX gap.
Explorar categorías de plugins
Ve directamente a las páginas de categorías de plugins en el marketplace.