gpt4 book ai didi

javascript - 如何创建 Vue 3 自定义元素,包括子组件样式?

转载 作者:行者123 更新时间:2023-12-05 00:31:00 28 4
gpt4 key购买 nike

我试过 Vue 的 defineCustomElement()创建自定义元素,但由于某种原因,子组件样式不包含在阴影根中。
然后我尝试使用 native Element.attachShadow() API 手动创建我的影子根。而不是使用 defineCustomElement() (基于 Codesandbox ),但是根本没有加载任何样式:
代码 : 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);
代码 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"
]
}
如何在阴影根中创建具有所有样式的自定义元素?

最佳答案

Vue 3 中不需要该 Vue 配置。只有 Vue 2 中的开发服务器需要它来呈现自定义元素中的样式。
使用 defineCustomElement()是注册自定义元素的推荐方式。但是,使用 defineCustomElement() 时存在一个 Unresolved 问题。 ,其中嵌套的组件样式根本不呈现( @vuejs/vue-next#4462 )。
一种解决方法是将所有组件作为自定义元素导入,以便将样式附加到组件定义而不是附加到 <head>。 ,然后在安装时将这些样式插入到 DOM 中:

  • 启用 vue-loader 's customElement modevue.config.js :
    // vue.config.js
    module.exports = {
    chainWebpack: config => {
    config.module
    .rule('vue')
    .use('vue-loader')
    .tap(options => {
    options.customElement = true
    return options
    })
    }
    }
    或者,将所有组件文件扩展名从 .vue 重命名。至.ce.vue .
  • 创建一个实用函数来包装 Vue 的 defineCustomElement()并在 setup() 中执行以下操作:
  • 创建一个添加 mixin 的临时应用程序实例对于mountedunmounted生命周期钩子(Hook)。
  • mounted钩子(Hook),从 this.$.type.styles 插入组件自己的样式进入 <style> 中的 DOM标签。对 this.$options.components 中的组件定义执行相同操作。 map 。
  • unmounted钩,删除 <style>mounted 插入的标签.
  • 复制临时应用实例的_context getCurrentInstance() 进入当前应用程序上下文.
  • 返回组件的渲染函数。

  • // 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)
    },
    })
  • 编辑 public/index.html替换 <div id="app">使用自定义元素(例如,名为“my-custom-element”):
    前:
    // public/index.html
    <body>
    <div id="app"></div>
    </body>
    后:
    // public/index.html
    <body>
    <my-custom-element></my-custom-element>
    </body>
  • 而不是 createApp() , 使用 defineCustomElement()从上面创建应用程序的自定义元素:
    前:
    // main.js
    import { createApp } from 'vue'
    import App from './App.vue'
    createApp(App).mount('#app')
    后:
    // main.js
    import { defineCustomElement } from './defineCustomElementWithStyles'
    import App from './App.vue'
    customElements.define('my-custom-element', defineCustomElement(App))

  • demo

    关于javascript - 如何创建 Vue 3 自定义元素,包括子组件样式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69797635/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com