彈窗組件咱們不少時候會引用第三方組件,或者寫的並非很通用,只能在單獨頁面展現,下面咱們來優雅的書寫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裏面,能夠在這個文件夾裏觀看源碼