弹窗组件咱们不少时候会引用第三方组件,或者写的并非很通用,只能在单独页面展现,下面咱们来优雅的书写vue的自定义弹窗组件。vue
弹窗这类组件的特色是它们在当前vue实例以外独立存在,不能写在当前业务dom内,这样样式很差控制,通用性比较差。git
一般挂载于body,经过js动态生成和取消。这里就说明了一个知识点,要求咱们对实例的建立和实例的挂载有必定的了解。github
下面咱们来写个简单例子。element-ui
create函数
首先咱们要有个明确思路该怎么作:app
一、建立一个create函数。
二、传入一个组件的配置(组件显示自己和它的props参数)。
三、建立它的实例,并将其挂载到body上。
四、最后返回组件实例。
import Vue from 'vue' // Component为传入的组件,props为传入的组件参数 export default function create(Component, props) { // 建立实例,每一个vue项目的入口文件都会用到就不具体说明了 // $mount()本质是把虚拟dom转化为真实dom,这点很重要 const vm = new Vue({ render(h) { return h(Component, { props }) } }).$mount() // 经过vm.$el获取生成的dom,把生成的真实dom插入body中 document.body.appendChild(vm.$el) // 获取根组件实例(这里不理解能够去看下前面的文章vue通信大全) const comp = vm.$children[0] // 弹窗关闭时候调用 comp.remove = () => { // 移除自己 document.body.removeChild(vm.$el) // 释放本身所占资源 vm.$destroy() } // 返回建立的实例 return comp }
看了上面代码,不少人会问出两个问题。dom
1.咱们在初始化$mount绑定id为app的dom节点上,那么这里咱们想绑定在body不是能够直接写成$mount('body'),这样就不用在用js去appendChild。
答案是不行,由于官网明确说明了这种方法是覆盖该dom内全部内容因此不行。可是$mount()本质是把虚拟dom转化为真实dom,这点很重要。ide
2.还有些同窗会说出extend方式也能够建立组件实例并挂载
是的,下面咱们就来实现一下。函数
import Vue from 'vue' export default function create(Component, props) { // vue.extend()获取建立实例 const Ctor = Vue.extend(Component) // 建立组件实例,这时获得的是虚拟dom,如何转化为真实dom const comp = new Ctor({ propsData: props }) // 前面说到$mount就是这个做用 comp.$mount() // 挂在在body上,这时是comp的dom document.body.appendChild(comp.$el) comp.remove = () => { // 移除自己 document.body.removeChild(comp.$el) // 释放本身所占资源 comp.$destroy() } return comp }
这样写起来是否是更轻便。ui
下面简单写下传入显示组件,也就是上文中的Component参数。这里就不赘述,比较简单。this
<template> <div v-if="isShow"> <h3>{{title}}</h3> <p>{{message}}</p> </div> </template> <script> export default { // 上文中传入的props参数 props: { title: { type: String, default: "" }, message: { type: String, default: "" }, duration: { type: Number, default: 1000 } }, data() { return { isShow: false }; }, methods: { // 调用show方法展现 show() { this.isShow = true; // 使用setTimeout定时关闭 setTimeout(this.hide, this.duration); }, // 消失后移除自身所占资源 hide() { this.isShow = false; this.remove(); } } }; </script>
create()返回的是组件自身实例,调用show()方法天然会调用显示组件里面methods中的show方法,而后就成功了。
create(Notice, { title: '我是自定义弹窗组件', message: '我成功出现了', duration: 3000 }).show()
以上只是一个简单的弹窗通用封装,若是想了解的更深刻能够参考element-ui的设计理念,去看看其中源码,相信还会有很多收获。
地址:https://github.com/ElemeFE/el...
组件都在packages里面,能够在这个文件夹里观看源码