Heim > Web-Frontend > View.js > Hauptteil

So verwenden Sie defineCustomElement zum Definieren von Komponenten in Vue3

PHPz
Freigeben: 2023-05-28 11:29:52
nach vorne
3007 Leute haben es durchsucht

    Erstellen Sie benutzerdefinierte Elemente mit Vue

    Web Components ist der Sammelname für eine Reihe webnativer APIs, die es Entwicklern ermöglichen Erstellen Sie wiederverwendbare benutzerdefinierte Elemente.

    Der Hauptvorteil der Verwendung benutzerdefinierter Elemente besteht darin, dass sie in jeder Frame- oder sogar Nicht-Frame-Umgebung verwendet werden können. Sie sind ideal, wenn Sie Endbenutzer ansprechen, die möglicherweise einen anderen Front-End-Technologie-Stack verwenden, oder wenn Sie die endgültige Anwendung von den Implementierungsdetails der verwendeten Komponenten entkoppeln möchten.

    Vue und Web Components sind komplementäre Technologien und Vue bietet hervorragende Unterstützung für die Verwendung und Erstellung benutzerdefinierter Elemente. In einer Vue-Anwendung können Sie benutzerdefinierte Elemente integrieren und Vue auch zum Erstellen und Veröffentlichen benutzerdefinierter Elemente verwenden.

    Vue erreichte im Custom Elements Everywhere-Test eine Punktzahl von 100 %. Die Verwendung benutzerdefinierter Elemente in einer Vue-Anwendung hat grundsätzlich die gleiche Wirkung wie die Verwendung nativer HTML-Elemente, erfordert jedoch einige zusätzliche Konfigurationen, damit sie funktionieren: In diesem Fall behandelt Vue alle nicht nativen HTML-Tags zunächst als Vue-Komponenten und „rendert ein benutzerdefiniertes Element“. " als Fallback-Option. Dies führt dazu, dass Vue während der Entwicklung die Warnung „Fehler beim Parsen der Komponente“ ausgibt.

    Um Vue wissen zu lassen, dass ein bestimmtes Element als benutzerdefiniertes Element behandelt werden soll und die Komponentenanalyse überspringt, können wir die Option „compilerOptions.isCustomElement“ angeben, die für dieses Optionsobjekt festgelegt ist Der Wert wird beim Kompilieren der Vorlage im Browser verwendet und wirkt sich auf alle Komponenten der konfigurierten Anwendung aus.

    • Alternativ können diese Optionen komponentenweise über die Option „compilerOptions“ überschrieben werden (mit höherer Priorität für die aktuelle Komponente).

    • Da es sich um eine Option zur Kompilierungszeit handelt, muss das Build-Tool die Konfiguration an @vue/compiler-dom übergeben:

    • # 🎜🎜#
    vue-loader: Durch die Optionen des CompilerOptions-Loaders geleitet.

      // vue.config.js
      module.exports = {
        chainWebpack: config => {
          config.module
            .rule('vue')
            .use('vue-loader')
            .tap(options => ({
              ...options,
              compilerOptions: {
                // 将所有带 ion- 的标签名都视为自定义元素
                isCustomElement: tag => tag.startsWith('ion-')
              }
            }))
        }
      }
      Nach dem Login kopieren
    • vite: Als Option an @vitejs/plugin-vue übergeben.
      // vite.config.js
      import vue from '@vitejs/plugin-vue'
      export default {
        plugins: [
          vue({
            template: {
              compilerOptions: {
                // 将所有带短横线的标签名都视为自定义元素
                isCustomElement: (tag) => tag.includes('-')
              }
            }
          })
        ]
      }
      Nach dem Login kopieren
    • Kompilierungskonfiguration im Browser.
      // src/main.js
      // 仅在浏览器内编译时才会工作
      const app = createApp(App)
      app.config.compilerOptions.isCustomElement = (tag) => tag.includes('-')
      Nach dem Login kopieren
    • DOM-Attribute übergeben

      Da DOM-Attribute nur Zeichenfolgenwerte sein können, können wir die Attribute von DOM-Objekten nur zur Übergabe komplexer Daten verwenden . Beim Festlegen von Requisiten für ein benutzerdefiniertes Element prüft Vue 3 mithilfe des in-Operators automatisch, ob die Eigenschaft bereits im DOM-Objekt vorhanden ist. Wenn der Schlüssel vorhanden ist, wird der Wert vorzugsweise auf Eigenschaften festgelegt von DOM-Objekten. Das bedeutet, dass Sie sich in den meisten Fällen keine Gedanken über dieses Problem machen müssen, wenn Ihr benutzerdefiniertes Element den empfohlenen Best Practices folgt.
    Es wird jedoch auch einige Sonderfälle geben: Die Daten müssen als DOM-Objektattribut übergeben werden, aber das benutzerdefinierte Element kann dieses Attribut nicht korrekt definieren/widerspiegeln (da in< /code> Prüfung fehlgeschlagen). In diesem Fall können Sie die Verwendung einer <code>v-bind-Bindung erzwingen und die Eigenschaften des DOM-Objekts über den Modifikator .prop festlegen:

    <my-element :user.prop="{ name: &#39;jack&#39; }"></my-element>
    <!-- 等价简写 -->
    <my-element .user="{ name: &#39;jack&#39; }"></my-element>
    Nach dem Login kopieren
    # 🎜 🎜#defineCustomElement()

    Vue bietet eine Methode defineCustomElement, die fast identisch mit der Definition allgemeiner Vue-Komponenten ist, um die Erstellung benutzerdefinierter Elemente zu unterstützen. defineComponent ist genau derselbe wie die von dieser Methode empfangenen Parameter. Es gibt jedoch einen Konstruktor für eine native benutzerdefinierte Elementklasse zurück, die von HTMLElement geerbt wurde (kann über customElements.define() registriert werden). in 操作符自动检查该属性是否已经存在于 DOM 对象上,并且在这个 key 存在时,更倾向于将值设置为一个 DOM 对象的属性。这意味着,在大多数情况下,如果自定义元素遵循推荐的最佳实践,你就不需要考虑这个问题。

    然而,也会有一些特别的情况:必须将数据以一个 DOM 对象属性的方式传递,但该自定义元素无法正确地定义/反射这个属性 (因为 in 检查失败)。在这种情况下,你可以强制使用一个 v-bind 绑定、通过 .prop

    function defineCustomElement(
      component:
        | (ComponentOptions & { styles?: string[] })
        | ComponentOptions[&#39;setup&#39;]
    ): {
      new (props?: object): HTMLElement
    }
    Nach dem Login kopieren

    Zusätzlich zu den regulären Komponentenoptionen unterstützt defineCustomElement() auch einen speziellen Optionsstil, bei dem es sich um ein Array von Inline-CSS-Strings handelt. Das bereitgestellte CSS wird in den ShadowRoot des Elements eingefügt.

    <my-vue-element></my-vue-element>
    Nach dem Login kopieren
    import { defineCustomElement } from &#39;vue&#39;
    const MyVueElement = defineCustomElement({
      // 这里是同平常一样的 Vue 组件选项
      props: {},
      emits: {},
      template: `...`,
      // defineCustomElement 特有的:注入进 ShadowRoot 的 CSS
      styles: [`/* css */`]
    })
    // 注册自定义元素之后,所有此页面中的 `<my-vue-element>` 标签都会被升级
    customElements.define(&#39;my-vue-element&#39;, MyVueElement)
    // 也可以在注册之后实例化元素:
    document.body.appendChild(
      new MyVueElement({
        // 初始化 props(可选)
      })
    )
    Nach dem Login kopieren

    Wenn die Konsole zu diesem Zeitpunkt einen Fehler meldet: color{red}{Wenn die Konsole zu diesem Zeitpunkt einen Fehler meldet:} Wenn die Konsole zu diesem Zeitpunkt einen Fehler meldet: Von der Komponente bereitgestellte Vorlagenoption aber Die Laufzeitkompilierung wird in Vite nicht unterstützt. Fügen Sie die folgende Konfiguration zu config.js hinzu:

    resolve: { alias: { &#39;vue&#39;: &#39;vue/dist/vue.esm-bundler.js&#39; } },
    Nach dem Login kopieren

    lifecycle

    Wenn der connectedCallback des Elements zuerst ist aufgerufen, mountet ein benutzerdefiniertes Vue-Element intern eine Vue-Komponenteninstanz in seinem ShadowRoot.

    • Wenn der DisconnectedCallback dieses Elements aufgerufen wird, prüft Vue nach einem Mikrotask, ob das Element noch im Dokument vorhanden ist.

    • Wenn sich das Element noch im Dokument befindet, bedeutet dies, dass es sich um einen Verschiebungsvorgang handelt und die Komponenteninstanz beibehalten wird; 🎜## 🎜🎜#

      Wenn das Element nicht mehr im Dokument vorhanden ist, handelt es sich um einen Entfernungsvorgang und die Komponenteninstanz wird zerstört.
      • Requisiten
      • Alle in der Option „Requisiten“ deklarierten Requisiten werden als selbstdefiniert definiert die Eigenschaften des Elements. Vue kann automatisch angemessen damit umgehen, ob es sich um eine Eigenschaft oder Eigenschaft handelt.
      • attribute 总是根据需要反射为相应的属性类型。原话已经非常清晰明了,可以直接重述。重新表述如下: 基本数据类型的属性值(例如字符串、布尔值或数字)可以通过反射反映为属性。

      • 当它们被设为 attribute 时 (永远是字符串),Vue 也会自动将以 Boolean 或 Number 类型声明的 prop 转换为所期望的类型。比如下面这样的 props 声明:

      props: {
        selected: Boolean,
        index: Number
      }
      Nach dem Login kopieren

      并以下面这样的方式使用自定义元素:

      <my-element selected index="1"></my-element>
      Nach dem Login kopieren

      在组件中,selected 会被转换为 true (boolean 类型值) 而 index 会被转换为 1 (number 类型值)。

      事件

      • emit 触发的事件都会通过以 CustomEvents 的形式从自定义元素上派发。

      • 额外的事件参数 (payload) 将会被暴露为 CustomEvent 对象上的一个 detail 数组。

      插槽

      • 在一个组件中,插槽将会照常使用 渲染。但是,使用最终元素时,只能使用原生插槽的语法,无法使用作用域插槽。

      • 当传递具名插槽时,应使用 slot attribute 而不是 v-slot 指令:

      <my-element>
        <div slot="named">hello</div>
      </my-element>
      Nach dem Login kopieren

      依赖注入

      • Provide / Inject API 和相应的组合式 API 在 Vue 定义的自定义元素中都可以正常工作。

      • 但是,依赖关系只在自定义元素之间起作用。一个由常规 Vue 组件提供的属性无法被注入到由 Vue 定义的自定义元素中。

      将 SFC 编译为自定义元素

      defineCustomElement 也可以搭配 Vue 单文件组件 (SFC) 使用。但是,根据默认的工具链配置,SFC 中的 <style> 在生产环境构建时仍然会被抽取和合并到一个单独的 CSS 文件中。当正在使用 SFC 编写自定义元素时,通常需要改为注入 <style> 标签到自定义元素的 ShadowRoot 上。

      官方的 SFC 工具链支持以“自定义元素模式”导入 SFC (需要 @vitejs/plugin-vue@^1.4.0 或 vue-loader@^16.5.0)。一个以自定义元素模式加载的 SFC 将会内联其 <style> 标签为 CSS 字符串,并将其暴露为组件的 styles 选项。这会被 defineCustomElement 提取使用,并在初始化时注入到元素的 ShadowRoot 上。

      要开启这个模式,将组件文件以 .ce.vue 结尾即可:

      // Example.ce.vue
      <template>
        <h2>Example.ce</h2>
      </template>
      <script>
      </script>
      <style>
        h2 {
          color: red;
        }
      </style>
      Nach dem Login kopieren
      import { defineCustomElement } from &#39;vue&#39;
      import Example from &#39;./Example.ce.vue&#39;
      console.log(Example.styles)
      // 转换为自定义元素构造器
      const ExampleElement = defineCustomElement(Example)
      // 注册
      customElements.define(&#39;my-example&#39;, ExampleElement)
      Nach dem Login kopieren

      基于 Vue 构建自定义元素库

      按元素分别导出构造函数,以便用户可以灵活地按需导入它们,还可以通过导出一个函数来方便用户自动注册所有元素。

      // Vue 自定义元素库的入口文件
      import { defineCustomElement } from &#39;vue&#39;
      import Foo from &#39;./MyFoo.ce.vue&#39;
      import Bar from &#39;./MyBar.ce.vue&#39;
      const MyFoo = defineCustomElement(Foo)
      const MyBar = defineCustomElement(Bar)
      // 分别导出元素
      export { MyFoo, MyBar }
      export function register() {
        customElements.define(&#39;my-foo&#39;, MyFoo)
        customElements.define(&#39;my-bar&#39;, MyBar)
      }
      Nach dem Login kopieren

      defineComponent()

      用来在定义 Vue 组件时为 TypeScript 提供类型推导的辅助函数。

      • 对于一个 ts 文件,如果我们直接写 export default {},无法有针对性的提示 vue 组件里应该有哪些属性。

      • 但是,增加一层 defineComponet 的话,export default defineComponent({}),就可以对参数进行一些类型推导和属性的提示等操作。

      function defineComponent(
        component: ComponentOptions | ComponentOptions[&#39;setup&#39;]
      ): ComponentConstructor
      Nach dem Login kopieren

      参数是一个组件选项对象。返回值将是该选项对象本身,因为该函数实际上在运行时没有任何操作,仅用于提供类型推导,注意返回值的类型有一点特别:它是一个构造函数类型,它是根据选项推断出的组件实例类型。这样做可以在 TSX 中将返回值用作标签时提供类型推断支持。

      你可以像这样从 defineComponent() 的返回类型中提取出一个组件的实例类型 (与其选项中的 this 的类型等价):

      const Foo = defineComponent(/* ... */)
      type FooInstance = InstanceType<typeof Foo>
      Nach dem Login kopieren

      defineAsyncComponent()

      用来定义一个异步组件。在大型项目中,我们可能会将应用拆分成更小的模块,并在需要时从服务器加载相关组件。defineAsyncComponent 在运行时是懒加载的,参数可以是一个返回 Promise 的异步加载函数(resolve 回调方法应该在从服务器获得组件定义时调用),或是对加载行为进行更具体定制的一个选项对象。

      import { defineAsyncComponent } from &#39;vue&#39;
      const AsyncComp = defineAsyncComponent(() => {
        return new Promise((resolve, reject) => {
          // ...从服务器获取组件
          resolve(/* 获取到的组件 */)
        })
      })
      // ... 像使用其他一般组件一样使用 `AsyncComp`
      // 也可以使用 ES 模块动态导入
      const AsyncComp = defineAsyncComponent(() =>
        import(&#39;./components/MyComponent.vue&#39;)
      )
      Nach dem Login kopieren

      得到的 AsyncComp 是一个外层包装过的组件,仅在页面需要它渲染时才会调用加载内部实际组件的函数。它会将接收到的 props 和插槽传给内部组件,所以你可以使用这个异步的包装组件无缝地替换原始组件,同时实现延迟加载。

      与普通组件一样,异步组件可以使用 app.component() 全局注册:

      app.component(&#39;MyComponent&#39;, defineAsyncComponent(() =>
        import(&#39;./components/MyComponent.vue&#39;)
      ))
      Nach dem Login kopieren

      也可以直接在父组件中直接定义它们:

      <script setup>
      import { defineAsyncComponent } from &#39;vue&#39;
      const AdminPage = defineAsyncComponent(() =>
        import(&#39;./components/AdminPageComponent.vue&#39;)
      )
      </script>
      <template>
        <AdminPage />
      </template>
      Nach dem Login kopieren

      异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent() 也支持在高级选项中处理这些状态:

      const AsyncComp = defineAsyncComponent({
        // 加载函数
        loader: () => import(&#39;./Foo.vue&#39;),
        // 加载异步组件时使用的组件
        loadingComponent: LoadingComponent,
        // 展示加载组件前的延迟时间,默认为 200ms
        delay: 200,
        // 加载失败后展示的组件
        errorComponent: ErrorComponent,
        // 如果提供了一个时间限制,并超时了,也会显示这里配置的报错组件,默认值是:Infinity
        timeout: 3000
      })
      Nach dem Login kopieren

    Das obige ist der detaillierte Inhalt vonSo verwenden Sie defineCustomElement zum Definieren von Komponenten in Vue3. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Verwandte Etiketten:
    Quelle:yisu.com
    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
    Beliebte Tutorials
    Mehr>
    Neueste Downloads
    Mehr>
    Web-Effekte
    Quellcode der Website
    Website-Materialien
    Frontend-Vorlage