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实现自定义组件的方式引入图标)
- vueassets文件路径(vue如何根据url下载非同源文件)
- vue 富文本图片上传(vue.js云存储实现图片上传功能)
- vue动态路由实现权限控制(vue2/vue3路由权限管理的方法实例)
- vue-router的两种模式(vue-route路由管理的安装与配置方法)
- vue组件keep-alive的原理是什么(如何理解Vue简单状态管理之store模式)
- vue实现聊天(Vue+ssh框架实现在线聊天)
- vue组件开发步骤(解析如何自动化生成vue组件文档)
- vueweb端聊天(Vue实现聊天界面)
- vue功能测试和生产环境切换(vue 单元测试的推荐插件和使用示例)
- vue数据改变页面不刷新(vue列表数据删除后主动刷新页面及刷新方法详解)
- icon图标怎么引入vue(vue引入iconfont图标库的优雅实战记录)
- vue2和vue3都如何创建项目(vue3.0+vite2实现动态异步组件懒加载)
- vue表单上传图片数据(vue-cropper插件实现图片截取上传组件封装)
- vue pdf预览插件(Vue-pdf实现在线预览PDF文件)
- vue 手机端tab切换页面不刷新(vue Tab切换以及缓存页面处理的几种方式)
- 散文 八月再见,九月,我在风中等你(散文八月再见九月)
- 8月再见 9月你好(8月再见)
- 魔兽世界 设计师爆料,原始版本并无PVP,跨阵营属于返璞归真(魔兽世界设计师爆料)
- 吐槽完《弧光大作战》之后,我们和设计师聊了聊魔兽首款手游的立项初衷和未来(吐槽完弧光大作战之后)
- 魔兽争霸3自定义战役少年杰雷 2(魔兽争霸3自定义战役少年杰雷)
- 今日菜价 芥兰涨幅最高 1.33 ,花菜降幅最高 3.10(今日菜价芥兰涨幅最高)
热门推荐
- 阿里云几个服务器可以备案(阿里云服务器网站备案简单流程说明文档)
- asp.net 日期格式化
- vmware esxi账号密码(VMware Esxi忘记root密码成功找回的操作方法)
- linuxrabbitmq安装和使用教程(用docker部署RabbitMQ环境的详细介绍)
- python代码词频分析(python实现词法分析器)
- 非关系型数据库和关系型数据库(关系型数据库与非关系型数据库简介)
- sql行转列的应用(SQL查询语句行转列横向显示实例解析)
- php中如何打开文件读文件(PHP通过文件保存和更新信息的方法分析)
- linuxmysql客户端搭建(一台linux主机启动多个MySQL数据库的方法)
- oracle恢复删除的表数据
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9