vuevlog制作软件(Vue实现Dialog封装)
vuevlog制作软件
Vue实现Dialog封装目录
- Vue2 写法
- Vue3 插件版写法
- Vue3 动态组件写法
- 一些比较 hack 的写法
在写业务的时候很常见的一个场景就是需要在不同的页面调用同一个表单,常用的交互就是把表单以弹窗的形式展示,但是在每个页面又重复的引入表单组件有时候又很麻烦
解决方案有两个:
- 在根组件里面引入动态组件,在业务里面通过this.$root.openDialog(name, props)去控制动态组件的展示形式
- 封装成插件的形式去调用,比如this.$dialog('EditDialog.vue', props)
当然了,业务 Dialog 组件要有一套规范,props 接收一个 onOk、onCancel 回调,data 里面定义一个 visible 属性
<template> <el-dialog :title="title" :visible.sync="visible" append-to-body> <!-- 业务代码 --> </el-dialog> </template> <script> export default { props: ['onOk', '其他业务需要的属性'], data() { return { visible: false } } } </script>
在 Vue2 里面我个人感觉写成插件是比较好用的,实现如下,使用混入做了一些操作,和业务进行解耦
有点不太好的地方是组件是动态插入的,Vue devtools 要刷新下才能看到组件
const mixin = { mounted() { document.body.appendChild(this.$el) this.visible = true }, watch: { visible(value) { // 动画结束后销毁实例 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) => { // 相对于该插件的位置,静态编译期间会检查的 import('../components/dialogs/' + name) .then(module => { const component = module.default const mixins = component.mixins || [] mixins.push(mixin) // 实现自动打开,动态了混入生命周期函数和销毁操作 component.mixins = mixins return Vue.extend(component) }) .then(Dialog => { const dialog = new Dialog({ propsData: props || {} }) dialog.$mount() }) } } }
调用方式如下,注意 onOk 回调的 this 指向,使用箭头函数直接就避免了 😎
this.$dialog('GroupEdit.vue', { type: 'edit', group: {}, onOk: () => { this.freshList() } })
很糟糕的是,由于 Vue3 的升级Vue.extend没有了,$mount也没有了,组件只能在应用里面去渲染
每个应用之间的数据是隔离的,所以插件什么的都要重新引入。同时如果要交互交互的话也比较麻烦,引入同一个 vuex 实例应该可以,但是没怎试
为了低耦合只能去新建一个应用去挂载渲染
import { createApp, defineComponent } from 'vue' import ElementPlus from 'element-plus' const mixin = { mounted() { document.body.appendChild(this.$el) this.visible = true }, watch: { visible(value) { // 动画结束后销毁实例 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('li')) }) } } }
在 Vue3 里面,插件版的写法同样达到了要求,但是完全是一个新引应用了,如果在业务里访问this.$root,vuex,router还是有点麻烦的
所以 Vue3 里面还是动态组件的写法比较好
在根组件引入动态 component,定义一些控制变量
<template> <router-view></router-view> <component :is="currentDialog" v-bind="currentDialogProps" /> </template> <script> export default { data() { return { currentDialog: null, currentDialogProps: null } } } </script>
调用的的话this.$root.$dialog(),看起来太难看,其实还是可以手动模拟插件的效果的
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) { // 动画结束后销毁实例 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 || {}) }) } }
vue3 组件实例获取应用实例
vm.$.appContext.app == app
vue3 应用实例获取组件实例,注意_instance 仅在 dev 环境能访问到
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 } } }
到此这篇关于Vue实现Dialog封装的文章就介绍到这了,更多相关Vue Dialog封装内容请搜索开心学习网以前的文章或继续浏览下面的相关文章希望大家以后多多支持开心学习网!
- vue如何获取元素(vue第一次获取不到元素的解决方法记录)
- vue购物车简单项目(vue实现简单购物车案例)
- vue-cli安装教程学习(Vue新手指南之创建第一个vue-cli脚手架程序)
- vue3封装table组件(Vue封装通用table组件的完整步骤记录)
- vue控制div滚动条(vue3实现CSS无限无缝滚动效果)
- vue使用websocket的详细步骤(vue使用webSocket更新实时天气的方法)
- vue-router的安装(详解Vue-Router的安装与使用)
- vue3.0 黑暗风格(Vue3.0 手写放大镜效果)
- 数组循环遍历展示vue(Vue中foreach数组与js中遍历数组的写法说明)
- vue-cli请求数据的方式(vue-cli配置使用Vuex的全过程记录)
- vue各种模块(一篇文章学会Vue中间件管道)
- vue组件方法里如何修改data(vue项目中使用rem替换px的实现示例)
- vue3兼容的插件多吗(关于vue3编写挂载DOM的插件问题)
- vue指令使用技巧(Vue指令工作原理实现方法)
- vue-router底层实现原理(vue-router history模式服务器端配置过程记录)
- vue考试链接重置(Vue实现答题功能)
- TVB负评王连续挑战警察角色《使徒行者3》中将饰演卧底(TVB负评王连续挑战警察角色使徒行者3中将饰演卧底)
- 《精英律师》剧照首曝光,实力演员飙戏,演绎律政职场百态(精英律师剧照首曝光)
- 靳东领衔打造高精职场 新丽出品《精英律师》曝定妆照(靳东领衔打造高精职场)
- 靳东新剧《精英律师》定档,众星云集,这剧可追(靳东新剧精英律师定档)
- 精英律师 廖佳敏封印恋情曝光,顾婕马失前蹄 你个老不死的(廖佳敏封印恋情曝光)
- 以家人之名广受好评,剧情生动引起观众共鸣,演员张新成圈粉无数(以家人之名广受好评)
热门推荐
- linux常用的参数类型和参数代码(浅析Linux resolv.conf)
- 如何提高织梦dedecms的安全性(织梦DedeCms上flash彩色标签云tag的实现方法)
- 免费ftp服务器怎么用(几种流行的ftp服务器软件推荐)
- pythonselenium自动化教程(python使用selenium实现批量文件下载)
- netcore连什么数据库好(.Net Core导入千万级数据至Mysql的步骤)
- 瀑布流模板怎么搞(3种方式实现瀑布流布局小结)
- js中的内存机制(详解JS内存空间)
- php解压压缩包(PHP 实现文件压缩解压操作的方法)
- select top 根据传入的参数获取数据的条数
- Request.Url的值有可能会带端口号