Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

1.1K
Views
¿Cómo creo un elemento personalizado de Vue 3, incluidos los estilos de componentes secundarios?

defineCustomElement() de Vue para crear un elemento personalizado, pero los estilos de los componentes secundarios no están incluidos en la raíz oculta por algún motivo.

Luego traté de crear manualmente mi shadow root usando la API nativa Element.attachShadow() en lugar de usar defineCustomElement() (basado en un Codesandbox ), pero luego no se cargaron estilos en absoluto:

Código : main.js :

 import { createApp } from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; let treeHead = document.querySelector("#app"); let holder = document.createElement("div"); let shadow = treeHead.attachShadow({ mode: "open" }); shadow.appendChild(holder); createApp(App).use(store).use(router).mount(holder);

Código vue.config.js :

 module.exports = { chainWebpack: (config) => { config.module .rule("vue") .use("vue-loader") .loader("vue-loader") .tap((options) => { options.shadowMode = true; return options; }); config.module .rule("css") .oneOf("vue-modules") .use("vue-style-loader") .tap((options) => { options.shadowMode = true; return options; }); config.module .rule("css") .oneOf("vue") .use("vue-style-loader") .tap((options) => { options.shadowMode = true; return options; }); }, };

package.json :

 { "name": "shadow-root", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build" }, "dependencies": { "vue": "^3.2.20", "vue-loader": "^16.8.2", "vue-router": "^4.0.0-0", "vue-style-loader": "^4.1.3", "vuex": "^4.0.0-0" }, "devDependencies": { "@vue/cli-plugin-router": "~4.5.0", "@vue/cli-plugin-vuex": "~4.5.0", "@vue/cli-service": "~4.5.0", "@vue/compiler-sfc": "^3.0.0", "node-sass": "^4.12.0", "sass-loader": "^8.0.2" }, "browserslist": [ "> 1%", "last 2 versions", "not dead" ] }

¿Cómo puedo crear un elemento personalizado con todos sus estilos en la raíz de la sombra?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Esa configuración de Vue no es necesaria en Vue 3. Solo la necesitaba el servidor de desarrollo en Vue 2 para representar los estilos en elementos personalizados.

El uso defineCustomElement() es la forma recomendada de registrar elementos personalizados. Sin embargo, hay un problema abierto al usar defineCustomElement() , donde los estilos de componentes anidados no se representan en absoluto ( @vuejs/vue-next#4462 ).

Una solución es importar todos los componentes como elementos personalizados para que los estilos se adjunten a la definición del componente en lugar de agregarse a <head> , luego inserte esos estilos en el DOM al montarlos:

  • Habilite el modo customElement vue-loader en vue.config.js :

     // vue.config.js module.exports = { chainWebpack: config => { config.module .rule('vue') .use('vue-loader') .tap(options => { options.customElement = true return options }) } }

    Como alternativa, cambie el nombre de todas las extensiones de nombre de archivo de componentes de .vue a .ce.vue .

  • Cree una función de utilidad que envuelva defineCustomElement() de Vue y haga lo siguiente en un setup() :

    1. Cree una instancia de aplicación temporal que agregue una mixin para los enlaces de ciclo de vida mounted y unmounted .
    2. En el enlace mounted , inserte los estilos propios del componente desde this.$.type.styles en el DOM en una etiqueta <style> . Haga lo mismo con las definiciones de componentes del mapa this.$options.components .
    3. En el gancho unmounted , elimine la etiqueta <style> que se insertó desde el mounted .
    4. Copie el _context de la instancia de la aplicación temporal en el contexto de la aplicación actual desde getCurrentInstance() .
    5. Devuelve una función de representación para el componente.
     // defineCustomElementWithStyles.js import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue' const nearestElement = (el) => { while (el?.nodeType !== 1 /* ELEMENT */) el = el.parentElement return el } export const defineCustomElement = (component) => VueDefineCustomElement({ setup() { const app = createApp() 1️⃣ app.mixin({ mounted() { const insertStyles = (styles) => { if (styles?.length) { this.__style = document.createElement('style') this.__style.innerText = styles.join().replace(/\n/g, '') nearestElement(this.$el).prepend(this.__style) } } 2️⃣ insertStyles(this.$?.type.styles) if (this.$options.components) { for (const comp of Object.values(this.$options.components)) { insertStyles(comp.styles) } } }, unmounted() { this.__style?.remove() 3️⃣ }, }) 4️⃣ const inst = getCurrentInstance() Object.assign(inst.appContext, app._context) 5️⃣ return () => h(component) }, })
  • Edite public/index.html para reemplazar el <div id="app"> con un elemento personalizado (p. ej., llamado " app-root "):

    Antes:

     // public/index.html <body> <div id="app"></div> </body>

    Después:

     // public/index.html <body> <app-root id="app"></app-root> </body>
  • En lugar de createApp() , usa defineCustomElement() de arriba para crear un elemento personalizado de tu aplicación:

    Antes:

     // main.js import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')

    Después:

     // main.js import { defineCustomElement } from './defineCustomElementWithStyles' import App from './App.vue' customElements.define('app-root', defineCustomElement(App))

manifestación

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!