Vue3中如何使用defineCustomElement定義元件
使用Vue 建立自訂元素
Web Components 是一組web 原生API 的統稱,允許開發者建立可重複使用的自訂元素( custom elements)。
使用自訂元素的主要優勢在於,它們可以在任何框架甚至非框架環境中使用。當你面向的最終用戶可能使用了不同的前端技術棧,或者當你希望將最終的應用與它使用的組件實現細節解耦時,它們會是理想的選擇。
Vue 和 Web Components 是互補的技術,Vue 為使用和建立自訂元素提供了出色的支援。在 Vue 應用程式中,你可以整合自訂元素,也可以使用 Vue 來建立和發布自訂元素。
Vue 在 Custom Elements Everywhere 測試中取得了 100% 的分數。在Vue 應用中使用自訂元素基本上與使用原生HTML 元素的效果相同,但需要進行一些額外的配置才能運作:
跳過元件解析
##預設情況下,Vue會將任何非原生的HTML 標籤優先當作Vue 元件處理,而將「渲染自訂元素」作為後備選項。這會在開發時導致 Vue 拋出一個「解析元件失敗」的警告。- 要讓Vue 知道特定元素應該被視為自訂元素並跳過元件解析,我們可以指定compilerOptions.isCustomElement 這個選項,設定在此選項物件上的值將會在瀏覽器內進行模板編譯時使用,並會影響所配置應用的所有元件。
- 另外也可以透過 compilerOptions 選項在每個元件的基礎上覆寫這些選項(針對目前元件有較高的優先權)。
- vue-loader:透過compilerOptions loader 的選項傳遞。
// vue.config.js module.exports = { chainWebpack: config => { config.module .rule('vue') .use('vue-loader') .tap(options => ({ ...options, compilerOptions: { // 将所有带 ion- 的标签名都视为自定义元素 isCustomElement: tag => tag.startsWith('ion-') } })) } }
- vite:透過 @vitejs/plugin-vue 的選項傳遞。
// vite.config.js import vue from '@vitejs/plugin-vue' export default { plugins: [ vue({ template: { compilerOptions: { // 将所有带短横线的标签名都视为自定义元素 isCustomElement: (tag) => tag.includes('-') } } }) ] }
- 瀏覽器內編譯時的設定。
// src/main.js // 仅在浏览器内编译时才会工作 const app = createApp(App) app.config.compilerOptions.isCustomElement = (tag) => tag.includes('-')
in 運算子自動檢查該屬性是否已經存在於DOM 物件上,並且在這個key 存在時,更傾向於將值設為一個DOM對象的屬性。這意味著,在大多數情況下,如果自訂元素遵循建議的最佳實踐,你就不需要考慮這個問題。
in檢查失敗)。在這種情況下,你可以強制使用一個
v-bind 綁定、透過
.prop 修飾符來設定該DOM 物件的屬性:
<my-element :user.prop="{ name: 'jack' }"></my-element> <!-- 等价简写 --> <my-element .user="{ name: 'jack' }"></my-element>
function defineCustomElement( component: | (ComponentOptions & { styles?: string[] }) | ComponentOptions['setup'] ): { new (props?: object): HTMLElement }
<my-vue-element></my-vue-element>
import { defineCustomElement } from 'vue' const MyVueElement = defineCustomElement({ // 这里是同平常一样的 Vue 组件选项 props: {}, emits: {}, template: `...`, // defineCustomElement 特有的:注入进 ShadowRoot 的 CSS styles: [`/* css */`] }) // 注册自定义元素之后,所有此页面中的 `<my-vue-element>` 标签都会被升级 customElements.define('my-vue-element', MyVueElement) // 也可以在注册之后实例化元素: document.body.appendChild( new MyVueElement({ // 初始化 props(可选) }) )
resolve: { alias: { 'vue': 'vue/dist/vue.esm-bundler.js' } },
- #當該元素的connectedCallback 初次呼叫時,一個Vue 自訂元素會在內部掛載一個Vue 元件實例到它的ShadowRoot 上。
- 當此元素的 disconnectedCallback 被呼叫時,Vue 會在一個微任務後檢查元素是否仍留在文件中。
- 如果元素仍然在文件中,那麼說明它是一次移動操作,元件實例將被保留; ##如果該元素不再存在於文件中,那麼說明這是一次移除操作,元件實例將被銷毀。
- 所有在 props 選項中宣告的 props 都會被定義為自訂元素的屬性。 Vue 能夠自動地適當處理它是否反射為屬性或屬性。
attribute 总是根据需要反射为相应的属性类型。原话已经非常清晰明了,可以直接重述。重新表述如下: 基本数据类型的属性值(例如字符串、布尔值或数字)可以通过反射反映为属性。
当它们被设为 attribute 时 (永远是字符串),Vue 也会自动将以 Boolean 或 Number 类型声明的 prop 转换为所期望的类型。比如下面这样的 props 声明:
props: { selected: Boolean, index: Number }
并以下面这样的方式使用自定义元素:
<my-element selected index="1"></my-element>
在组件中,selected 会被转换为 true (boolean 类型值) 而 index 会被转换为 1 (number 类型值)。
事件
emit 触发的事件都会通过以 CustomEvents 的形式从自定义元素上派发。
额外的事件参数 (payload) 将会被暴露为 CustomEvent 对象上的一个 detail 数组。
插槽
在一个组件中,插槽将会照常使用 渲染。但是,使用最终元素时,只能使用原生插槽的语法,无法使用作用域插槽。
当传递具名插槽时,应使用 slot attribute 而不是 v-slot 指令:
<my-element> <div slot="named">hello</div> </my-element>
依赖注入
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>
import { defineCustomElement } from 'vue' import Example from './Example.ce.vue' console.log(Example.styles) // 转换为自定义元素构造器 const ExampleElement = defineCustomElement(Example) // 注册 customElements.define('my-example', ExampleElement)
基于 Vue 构建自定义元素库
按元素分别导出构造函数,以便用户可以灵活地按需导入它们,还可以通过导出一个函数来方便用户自动注册所有元素。
// Vue 自定义元素库的入口文件 import { defineCustomElement } from 'vue' import Foo from './MyFoo.ce.vue' import Bar from './MyBar.ce.vue' const MyFoo = defineCustomElement(Foo) const MyBar = defineCustomElement(Bar) // 分别导出元素 export { MyFoo, MyBar } export function register() { customElements.define('my-foo', MyFoo) customElements.define('my-bar', MyBar) }
defineComponent()
用来在定义 Vue 组件时为 TypeScript 提供类型推导的辅助函数。
对于一个 ts 文件,如果我们直接写 export default {},无法有针对性的提示 vue 组件里应该有哪些属性。
但是,增加一层 defineComponet 的话,export default defineComponent({}),就可以对参数进行一些类型推导和属性的提示等操作。
function defineComponent( component: ComponentOptions | ComponentOptions['setup'] ): ComponentConstructor
参数是一个组件选项对象。返回值将是该选项对象本身,因为该函数实际上在运行时没有任何操作,仅用于提供类型推导,注意返回值的类型有一点特别:它是一个构造函数类型,它是根据选项推断出的组件实例类型。这样做可以在 TSX 中将返回值用作标签时提供类型推断支持。
你可以像这样从 defineComponent()
的返回类型中提取出一个组件的实例类型 (与其选项中的 this
的类型等价):
const Foo = defineComponent(/* ... */) type FooInstance = InstanceType<typeof Foo>
defineAsyncComponent()
用来定义一个异步组件。在大型项目中,我们可能会将应用拆分成更小的模块,并在需要时从服务器加载相关组件。defineAsyncComponent 在运行时是懒加载的,参数可以是一个返回 Promise 的异步加载函数(resolve 回调方法应该在从服务器获得组件定义时调用),或是对加载行为进行更具体定制的一个选项对象。
import { defineAsyncComponent } from 'vue' const AsyncComp = defineAsyncComponent(() => { return new Promise((resolve, reject) => { // ...从服务器获取组件 resolve(/* 获取到的组件 */) }) }) // ... 像使用其他一般组件一样使用 `AsyncComp` // 也可以使用 ES 模块动态导入 const AsyncComp = defineAsyncComponent(() => import('./components/MyComponent.vue') )
得到的 AsyncComp 是一个外层包装过的组件,仅在页面需要它渲染时才会调用加载内部实际组件的函数。它会将接收到的 props 和插槽传给内部组件,所以你可以使用这个异步的包装组件无缝地替换原始组件,同时实现延迟加载。
与普通组件一样,异步组件可以使用 app.component() 全局注册:
app.component('MyComponent', defineAsyncComponent(() => import('./components/MyComponent.vue') ))
也可以直接在父组件中直接定义它们:
<script setup> import { defineAsyncComponent } from 'vue' const AdminPage = defineAsyncComponent(() => import('./components/AdminPageComponent.vue') ) </script> <template> <AdminPage /> </template>
异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent() 也支持在高级选项中处理这些状态:
const AsyncComp = defineAsyncComponent({ // 加载函数 loader: () => import('./Foo.vue'), // 加载异步组件时使用的组件 loadingComponent: LoadingComponent, // 展示加载组件前的延迟时间,默认为 200ms delay: 200, // 加载失败后展示的组件 errorComponent: ErrorComponent, // 如果提供了一个时间限制,并超时了,也会显示这里配置的报错组件,默认值是:Infinity timeout: 3000 })
以上是Vue3中如何使用defineCustomElement定義元件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

vue3+vite:src使用require動態導入圖片報錯和解決方法vue3+vite動態的導入多張圖片vue3如果使用的是typescript開發,就會出現require引入圖片報錯,requireisnotdefined不能像使用vue2這樣imgUrl:require(' …/assets/test.png')導入,是因為typescript不支援require所以用import導入,下面介紹如何解決:使用awaitimport

tinymce是一個功能齊全的富文本編輯器插件,但在vue中引入tinymce並不像別的Vue富文本插件一樣那麼順利,tinymce本身並不適配Vue,還需要引入@tinymce/tinymce-vue,並且它是國外的富文本插件,沒有透過中文版本,需要在其官網下載翻譯包(可能需要翻牆)。 1.安裝相關依賴npminstalltinymce-Snpminstall@tinymce/tinymce-vue-S2、下載中文包3.引入皮膚和漢化包在項目public資料夾下新建tinymce資料夾,將下載的

Vue實作部落格前端,需要實作markdown的解析,如果有程式碼則需要實作程式碼的高亮。 Vue的markdown解析函式庫很多,如markdown-it、vue-markdown-loader、marked、vue-markdown等。這些庫都大同小異。這裡選用的是marked,程式碼高亮的函式庫選用的是highlight.js。具體實現步驟如下:一、安裝依賴庫在vue專案下開啟命令窗口,並輸入以下命令npminstallmarked-save//marked用於將markdown轉換成htmlnpmins

想要實現頁面的局部刷新,我們只需要實現局部元件(dom)的重新渲染。在Vue中,想要實現這效果最簡單的方式方法就是使用v-if指令。在Vue2中我們除了使用v-if指令讓局部dom的重新渲染,也可以新建一個空白元件,需要刷新局部頁面時跳轉至這個空白元件頁面,然後在空白元件內的beforeRouteEnter守衛中又跳轉回原來的頁面。如下圖所示,如何在Vue3.X中實現點擊刷新按鈕實現紅框範圍內的dom重新加載,並展示對應的加載狀態。由於Vue3.X中scriptsetup語法中組件內守衛只有o

vue3專案打包發佈到伺服器後存取頁面顯示空白1、處理vue.config.js檔案中的publicPath處理如下:const{defineConfig}=require('@vue/cli-service')module.exports=defineConfig({publicPath :process.env.NODE_ENV==='production'?'./':'/&

前言無論是vue還是react,當我們遇到多處重複程式碼的時候,我們都會想著如何重複使用這些程式碼,而不是一個檔案裡充斥著一堆冗餘程式碼。實際上,vue和react都可以透過抽組件的方式來達到復用,但如果遇到一些很小的程式碼片段,你又不想抽到另外一個檔案的情況下,相比而言,react可以在相同文件裡面宣告對應的小元件,或透過renderfunction來實現,如:constDemo:FC=({msg})=>{returndemomsgis{msg}}constApp:FC=()=>{return(

最終效果安裝VueCropper組件yarnaddvue-cropper@next上面的安裝值針對Vue3的,如果時Vue2或想使用其他的方式引用,請訪問它的npm官方地址:官方教程。在元件中引用使用時也很簡單,只需要引入對應的元件和它的樣式文件,我這裡沒有在全域引用,只在我的元件檔案中引入import{userInfoByRequest}from'../js/api' import{VueCropper}from'vue-cropper&

vue3+ts+axios+pinia實作無感刷新1.先在專案中下載aiXos和pinianpmipinia--savenpminstallaxios--save2.封裝axios請求-----下載js-cookienpmiJS-cookie-s//引入aixosimporttype{AxiosRequestConfigig ,AxiosResponse}from"axios";importaxiosfrom'axios';import{ElMess
