Vue實(shí)現(xiàn)Dialog封裝
在寫業(yè)務(wù)的時(shí)候很常見的一個(gè)場景就是需要在不同的頁面調(diào)用同一個(gè)表單,常用的交互就是把表單以彈窗的形式展示,但是在每個(gè)頁面又重復(fù)的引入表單組件有時(shí)候又很麻煩
解決方案有兩個(gè):
- 在根組件里面引入動(dòng)態(tài)組件,在業(yè)務(wù)里面通過this.$root.openDialog(name, props)去控制動(dòng)態(tài)組件的展示形式
- 封裝成插件的形式去調(diào)用,比如this.$dialog('EditDialog.vue', props)
當(dāng)然了,業(yè)務(wù) Dialog 組件要有一套規(guī)范,props 接收一個(gè) onOk、onCancel 回調(diào),data 里面定義一個(gè) visible 屬性
<template> <el-dialog :title="title" :visible.sync="visible" append-to-body> <!-- 業(yè)務(wù)代碼 --> </el-dialog> </template> <script> export default { props: ['onOk', '其他業(yè)務(wù)需要的屬性'], data() { return { visible: false } } } </script>
Vue2 寫法
在 Vue2 里面我個(gè)人感覺寫成插件是比較好用的,實(shí)現(xiàn)如下,使用混入做了一些操作,和業(yè)務(wù)進(jìn)行解耦
有點(diǎn)不太好的地方是組件是動(dòng)態(tài)插入的,Vue devtools 要刷新下才能看到組件
const mixin = { mounted() { document.body.appendChild(this.$el) this.visible = true }, watch: { visible(value) { // 動(dòng)畫結(jié)束后銷毀實(shí)例 if (value === false) { setTimeout(() => { this.$destroy() if (this.$el && this.$el.parentNode) { this.$el.parentNode.removeChild(this.$el) } }, 400) } } } } export default { install(Vue, options) { Vue.prototype.$dialog = (name, props) => { // 相對(duì)于該插件的位置,靜態(tài)編譯期間會(huì)檢查的 import('../components/dialogs/' + name) .then(module => { const component = module.default const mixins = component.mixins || [] mixins.push(mixin) // 實(shí)現(xiàn)自動(dòng)打開,動(dòng)態(tài)了混入生命周期函數(shù)和銷毀操作 component.mixins = mixins return Vue.extend(component) }) .then(Dialog => { const dialog = new Dialog({ propsData: props || {} }) dialog.$mount() }) } } }
調(diào)用方式如下,注意 onOk 回調(diào)的 this 指向,使用箭頭函數(shù)直接就避免了 😎
this.$dialog('GroupEdit.vue', { type: 'edit', group: {}, onOk: () => { this.freshList() } })
Vue3 插件版寫法
很糟糕的是,由于 Vue3 的升級(jí)Vue.extend沒有了,$mount也沒有了,組件只能在應(yīng)用里面去渲染
每個(gè)應(yīng)用之間的數(shù)據(jù)是隔離的,所以插件什么的都要重新引入。同時(shí)如果要交互交互的話也比較麻煩,引入同一個(gè) vuex 實(shí)例應(yīng)該可以,但是沒怎試
為了低耦合只能去新建一個(gè)應(yīng)用去掛載渲染
import { createApp, defineComponent } from 'vue' import ElementPlus from 'element-plus' const mixin = { mounted() { document.body.appendChild(this.$el) this.visible = true }, watch: { visible(value) { // 動(dòng)畫結(jié)束后銷毀實(shí)例 if (value === false) { setTimeout(() => { this.$.appContext.app.unmount() }, 400) } } } } export default { install(app) { app.config.globalProperties.$dialog = (name, props) => { import('../components/dialogs/' + name) .then(module => { const component = module.default let mixins = component.mixins || [] mixins.push(mixin) component.mixins = mixins return defineComponent(component) }) .then(Dialog => { const app = createApp(Dialog, props || {}) app.use(ElementPlus) app.mount(document.createElement('div')) }) } } }
Vue3 動(dòng)態(tài)組件寫法
在 Vue3 里面,插件版的寫法同樣達(dá)到了要求,但是完全是一個(gè)新引應(yīng)用了,如果在業(yè)務(wù)里訪問this.$root,vuex,router還是有點(diǎn)麻煩的
所以 Vue3 里面還是動(dòng)態(tài)組件的寫法比較好
在根組件引入動(dòng)態(tài) component,定義一些控制變量
<template> <router-view></router-view> <component :is="currentDialog" v-bind="currentDialogProps" /> </template> <script> export default { data() { return { currentDialog: null, currentDialogProps: null } } } </script>
調(diào)用的的話this.$root.$dialog(),看起來太難看,其實(shí)還是可以手動(dòng)模擬插件的效果的
const app = createApp(App) const vm = app.mount('#app') initDialog(app, vm) function initDialog(app, vm) { const mixin = { mounted() { this.visible = true }, watch: { visible(value) { // 動(dòng)畫結(jié)束后銷毀實(shí)例 if (value === false) { setTimeout(() => { this.$root.currentDialog = null this.$root.currentDialogProps = {} }, 400) } } } } app.config.globalProperties.$dialog = (name, props) => { import('./components/dialogs/' + name).then(module => { const component = module.default let mixins = component.mixins || [] mixins.push(mixin) component.mixins = mixins // 不需要 defineComponent(component) vm.currentDialog = markRaw(component) vm.currentDialogProps = markRaw(props || {}) }) } }
一些比較 hack 的寫法
vue3 組件實(shí)例獲取應(yīng)用實(shí)例
vm.$.appContext.app == app
vue3 應(yīng)用實(shí)例獲取組件實(shí)例,注意_instance 僅在 dev 環(huán)境能訪問到
app._instance.proxy == vm app._instance.root.proxy == vm app._instance.ctx.$root == vm
騷操作還是有的,但是最好不要用
const app = createApp(App) const vm = app.mount('#app') if (process.env.NODE_ENV === 'production') { app._instance = { proxy: vm, root: { proxy: vm }, ctx: { $root: vm } } }
到此這篇關(guān)于Vue實(shí)現(xiàn)Dialog封裝的文章就介紹到這了,更多相關(guān)Vue Dialog封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue?nextTick獲取更新后的DOM的實(shí)現(xiàn)
本文主要介紹了Vue?nextTick獲取更新后的DOM的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01前端vue+express實(shí)現(xiàn)文件的上傳下載示例
本文主要介紹了前端vue+express實(shí)現(xiàn)文件的上傳下載示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12elementUI+Springboot實(shí)現(xiàn)導(dǎo)出excel功能的全過程
這篇文章主要介紹了elementUI+Springboot實(shí)現(xiàn)導(dǎo)出excel功能,現(xiàn)在也對(duì)這個(gè)導(dǎo)出功能進(jìn)行一個(gè)匯總整理寫出來,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09Vue報(bào)錯(cuò):Injection?"xxxx"?not?found的解決辦法
這篇文章主要給大家介紹了關(guān)于Vue報(bào)錯(cuò):Injection?"xxxx"?not?found的解決辦法,文中通過圖文將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07vue-form表單驗(yàn)證是否為空值的實(shí)例詳解
今天小編就為大家分享一篇vue-form表單驗(yàn)證是否為空值的實(shí)例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10Vue.set() this.$set()引發(fā)的視圖更新思考及注意事項(xiàng)
this.$set()和Vue.set()本質(zhì)方法一樣,前者可以用在methods中使用。這篇文章主要介紹了Vue.set() this.$set()引發(fā)的視圖更新思考及注意事項(xiàng),需要的朋友可以參考下2018-08-08