Table of Contents
Use Vue to build custom elements
Skip component parsing
Passing DOM attributes
defineCustomElement ()
Life cycle
Props
事件
插槽
依赖注入
将 SFC 编译为自定义元素
基于 Vue 构建自定义元素库
defineComponent()
defineAsyncComponent()
Home Web Front-end Vue.js How to use defineCustomElement to define components in Vue3

How to use defineCustomElement to define components in Vue3

May 28, 2023 am 11:29 AM
vue3 definecustomelement

    Use Vue to build custom elements

    Web Components is the collective name for a set of web native APIs that allow developers to create reusable custom elements ( custom elements).

    The main advantage of using custom elements is that they can be used in any frame or even non-frame environment. They are ideal when you are targeting end users who may be using a different front-end technology stack, or when you want to decouple the final application from the implementation details of the components it uses.

    Vue and Web Components are complementary technologies, and Vue provides excellent support for using and creating custom elements. In a Vue application, you can integrate custom elements, and you can also use Vue to build and publish custom elements.

    Vue achieved a 100% score in the Custom Elements Everywhere test. Using custom elements in a Vue application basically has the same effect as using native HTML elements, but requires some additional configuration to work:

    Skip component parsing

    By default, Vue Any non-native HTML tags will be treated as Vue components first, with "render a custom element" as a fallback option. This will cause Vue to throw a "Failed to parse component" warning during development.

    • To let Vue know that a specific element should be treated as a custom element and skip component parsing, we can specify the compilerOptions.isCustomElement option. The value set on this option object will It is used during template compilation in the browser and will affect all components of the configured application.

    • Alternatively, these options can be overridden on a per-component basis via the compilerOptions option (with higher priority for the current component).

    Because it is a compile-time option, the build tool needs to pass the configuration to @vue/compiler-dom:

    • vue-loader: Options passed through the compilerOptions loader.

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    // vue.config.js

    module.exports = {

      chainWebpack: config => {

        config.module

          .rule('vue')

          .use('vue-loader')

          .tap(options => ({

            ...options,

            compilerOptions: {

              // 将所有带 ion- 的标签名都视为自定义元素

              isCustomElement: tag => tag.startsWith('ion-')

            }

          }))

      }

    }

    Copy after login
    • vite: Passed as an option to @vitejs/plugin-vue.

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    // vite.config.js

    import vue from '@vitejs/plugin-vue'

    export default {

      plugins: [

        vue({

          template: {

            compilerOptions: {

              // 将所有带短横线的标签名都视为自定义元素

              isCustomElement: (tag) => tag.includes('-')

            }

          }

        })

      ]

    }

    Copy after login
    • In-browser compilation configuration.

    1

    2

    3

    4

    // src/main.js

    // 仅在浏览器内编译时才会工作

    const app = createApp(App)

    app.config.compilerOptions.isCustomElement = (tag) => tag.includes('-')

    Copy after login

    Passing DOM attributes

    Since DOM attributes can only be string values, we can only use the attributes of the DOM object to pass complex data. When setting props for a custom element, Vue 3 will automatically check whether the property already exists on the DOM object through the in operator, and when the key exists, it is more likely to set the value to a DOM properties of the object. This means that, in most cases, you don't need to think about this issue if your custom element follows recommended best practices.

    However, there will also be some special cases: the data must be passed as a DOM object attribute, but the custom element cannot correctly define/reflect this attribute (because in check failed). In this case, you can force the use of a v-bind binding and set the properties of the DOM object via the .prop modifier:

    1

    2

    3

    <my-element :user.prop="{ name: &#39;jack&#39; }"></my-element>

    <!-- 等价简写 -->

    <my-element .user="{ name: &#39;jack&#39; }"></my-element>

    Copy after login

    defineCustomElement ()

    Vue provides a defineCustomElement method that is almost identical to defining general Vue components to support the creation of custom elements. defineComponent is exactly the same as the parameters received by this method. But it returns a constructor for a native custom element class that inherits from HTMLElement (can be registered via customElements.define()).

    1

    2

    3

    4

    5

    6

    7

    function defineCustomElement(

      component:

        | (ComponentOptions & { styles?: string[] })

        | ComponentOptions[&#39;setup&#39;]

    ): {

      new (props?: object): HTMLElement

    }

    Copy after login

    In addition to the regular component options, defineCustomElement() also supports a special option styles, which is an array of inline CSS strings. The provided CSS will be injected into the ShadowRoot of the element.

    1

    <my-vue-element></my-vue-element>

    Copy after login

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    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(可选)

      })

    )

    Copy after login

    If the console reports an error at this time:\color{red}{If the console reports an error at this time:}If the console reports an error at this time: Component provided template option but runtime compilation is not supported, in vite.config Add the following configuration to .js:

    1

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

    Copy after login

    Life cycle

    • When the element's connectedCallback is first called, a Vue custom element will mount a Vue component internally instance to its ShadowRoot.

    • When this element's disconnectedCallback is called, Vue will check after a microtask whether the element is still in the document.

      • If the element is still in the document, then it is a move operation and the component instance will be retained;

      • If the element If the element no longer exists in the document, then this is a removal operation and the component instance will be destroyed.

    Props

    • All props declared in the props option will be defined as properties of the custom element. Vue can automatically handle appropriately whether it's reflected as a property or property.

    • attribute 总是根据需要反射为相应的属性类型。原话已经非常清晰明了,可以直接重述。重新表述如下: 基本数据类型的属性值(例如字符串、布尔值或数字)可以通过反射反映为属性。

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

    1

    2

    3

    4

    props: {

      selected: Boolean,

      index: Number

    }

    Copy after login

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

    1

    <my-element selected index="1"></my-element>

    Copy after login

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

    事件

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

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

    插槽

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

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

    1

    2

    3

    <my-element>

      <div slot="named">hello</div>

    </my-element>

    Copy after login

    依赖注入

    • 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 结尾即可:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    // Example.ce.vue

    <template>

      <h2>Example.ce</h2>

    </template>

    <script>

    </script>

    <style>

      h2 {

        color: red;

      }

    </style>

    Copy after login

    1

    2

    3

    4

    5

    6

    7

    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)

    Copy after login

    基于 Vue 构建自定义元素库

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    // 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)

    }

    Copy after login

    defineComponent()

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

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

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

    1

    2

    3

    function defineComponent(

      component: ComponentOptions | ComponentOptions[&#39;setup&#39;]

    ): ComponentConstructor

    Copy after login

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

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

    1

    2

    const Foo = defineComponent(/* ... */)

    type FooInstance = InstanceType<typeof Foo>

    Copy after login

    defineAsyncComponent()

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    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;)

    )

    Copy after login

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

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

    1

    2

    3

    app.component(&#39;MyComponent&#39;, defineAsyncComponent(() =>

      import(&#39;./components/MyComponent.vue&#39;)

    ))

    Copy after login

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    <script setup>

    import { defineAsyncComponent } from &#39;vue&#39;

    const AdminPage = defineAsyncComponent(() =>

      import(&#39;./components/AdminPageComponent.vue&#39;)

    )

    </script>

    <template>

      <AdminPage />

    </template>

    Copy after login

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    const AsyncComp = defineAsyncComponent({

      // 加载函数

      loader: () => import(&#39;./Foo.vue&#39;),

      // 加载异步组件时使用的组件

      loadingComponent: LoadingComponent,

      // 展示加载组件前的延迟时间,默认为 200ms

      delay: 200,

      // 加载失败后展示的组件

      errorComponent: ErrorComponent,

      // 如果提供了一个时间限制,并超时了,也会显示这里配置的报错组件,默认值是:Infinity

      timeout: 3000

    })

    Copy after login

    The above is the detailed content of How to use defineCustomElement to define components in Vue3. For more information, please follow other related articles on the PHP Chinese website!

    Statement of this Website
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

    Hot AI Tools

    Undresser.AI Undress

    Undresser.AI Undress

    AI-powered app for creating realistic nude photos

    AI Clothes Remover

    AI Clothes Remover

    Online AI tool for removing clothes from photos.

    Undress AI Tool

    Undress AI Tool

    Undress images for free

    Clothoff.io

    Clothoff.io

    AI clothes remover

    Video Face Swap

    Video Face Swap

    Swap faces in any video effortlessly with our completely free AI face swap tool!

    Hot Tools

    Notepad++7.3.1

    Notepad++7.3.1

    Easy-to-use and free code editor

    SublimeText3 Chinese version

    SublimeText3 Chinese version

    Chinese version, very easy to use

    Zend Studio 13.0.1

    Zend Studio 13.0.1

    Powerful PHP integrated development environment

    Dreamweaver CS6

    Dreamweaver CS6

    Visual web development tools

    SublimeText3 Mac version

    SublimeText3 Mac version

    God-level code editing software (SublimeText3)

    How to use tinymce in vue3 project How to use tinymce in vue3 project May 19, 2023 pm 08:40 PM

    tinymce is a fully functional rich text editor plug-in, but introducing tinymce into vue is not as smooth as other Vue rich text plug-ins. tinymce itself is not suitable for Vue, and @tinymce/tinymce-vue needs to be introduced, and It is a foreign rich text plug-in and has not passed the Chinese version. You need to download the translation package from its official website (you may need to bypass the firewall). 1. Install related dependencies npminstalltinymce-Snpminstall@tinymce/tinymce-vue-S2. Download the Chinese package 3. Introduce the skin and Chinese package. Create a new tinymce folder in the project public folder and download the

    vue3+vite: How to solve the error when using require to dynamically import images in src vue3+vite: How to solve the error when using require to dynamically import images in src May 21, 2023 pm 03:16 PM

    vue3+vite:src uses require to dynamically import images and error reports and solutions. vue3+vite dynamically imports multiple images. If vue3 is using typescript development, require will introduce image errors. requireisnotdefined cannot be used like vue2 such as imgUrl:require(' .../assets/test.png') is imported because typescript does not support require, so import is used. Here is how to solve it: use awaitimport

    How to refresh partial content of the page in Vue3 How to refresh partial content of the page in Vue3 May 26, 2023 pm 05:31 PM

    To achieve partial refresh of the page, we only need to implement the re-rendering of the local component (dom). In Vue, the easiest way to achieve this effect is to use the v-if directive. In Vue2, in addition to using the v-if instruction to re-render the local dom, we can also create a new blank component. When we need to refresh the local page, jump to this blank component page, and then jump back in the beforeRouteEnter guard in the blank component. original page. As shown in the figure below, how to click the refresh button in Vue3.X to reload the DOM within the red box and display the corresponding loading status. Since the guard in the component in the scriptsetup syntax in Vue3.X only has o

    How Vue3 parses markdown and implements code highlighting How Vue3 parses markdown and implements code highlighting May 20, 2023 pm 04:16 PM

    Vue implements the blog front-end and needs to implement markdown parsing. If there is code, it needs to implement code highlighting. There are many markdown parsing libraries for Vue, such as markdown-it, vue-markdown-loader, marked, vue-markdown, etc. These libraries are all very similar. Marked is used here, and highlight.js is used as the code highlighting library. The specific implementation steps are as follows: 1. Install dependent libraries. Open the command window under the vue project and enter the following command npminstallmarked-save//marked to convert markdown into htmlnpmins

    How to use vue3+ts+axios+pinia to achieve senseless refresh How to use vue3+ts+axios+pinia to achieve senseless refresh May 25, 2023 pm 03:37 PM

    vue3+ts+axios+pinia realizes senseless refresh 1. First download aiXos and pinianpmipinia in the project--savenpminstallaxios--save2. Encapsulate axios request-----Download js-cookienpmiJS-cookie-s//Introduce aixosimporttype{AxiosRequestConfig ,AxiosResponse}from"axios";importaxiosfrom'axios';import{ElMess

    How to use Vue3 reusable components How to use Vue3 reusable components May 20, 2023 pm 07:25 PM

    Preface Whether it is vue or react, when we encounter multiple repeated codes, we will think about how to reuse these codes instead of filling a file with a bunch of redundant codes. In fact, both vue and react can achieve reuse by extracting components, but if you encounter some small code fragments and you don’t want to extract another file, in comparison, react can be used in the same Declare the corresponding widget in the file, or implement it through renderfunction, such as: constDemo:FC=({msg})=>{returndemomsgis{msg}}constApp:FC=()=>{return(

    How to select an avatar and crop it in Vue3 How to select an avatar and crop it in Vue3 May 29, 2023 am 10:22 AM

    The final effect is to install the VueCropper component yarnaddvue-cropper@next. The above installation value is for Vue3. If it is Vue2 or you want to use other methods to reference, please visit its official npm address: official tutorial. It is also very simple to reference and use it in a component. You only need to introduce the corresponding component and its style file. I do not reference it globally here, but only introduce import{userInfoByRequest}from'../js/api' in my component file. import{VueCropper}from'vue-cropper&

    How to solve the problem that after the vue3 project is packaged and published to the server, the access page displays blank How to solve the problem that after the vue3 project is packaged and published to the server, the access page displays blank May 17, 2023 am 08:19 AM

    After the vue3 project is packaged and published to the server, the access page displays blank 1. The publicPath in the vue.config.js file is processed as follows: const{defineConfig}=require('@vue/cli-service') module.exports=defineConfig({publicPath :process.env.NODE_ENV==='production'?'./':'/&

    See all articles