Vue中Vue.extend()的使用及解析
Vue Vue.extend()的使用
Vue.extend 屬于 Vue 的全局 API,在實際業(yè)務(wù)開發(fā)中我們很少使用,因為相比常用的 Vue.component 寫法使用 extend 步驟要更加繁瑣一些。但是在一些獨立組件開發(fā)場景中,Vue.extend + $mount 這對組合是我們需要去關(guān)注的。
應(yīng)用場景
在 vue 項目中,初始化的根實例后,所有頁面基本上都是通過 router 來管理,組件也是通過 import 來進行局部注冊,所以組件的創(chuàng)建不需要去關(guān)注,相比 extend 要更省心一點點。但是這樣做會有幾個缺點:
組件模板都是事先定義好的,如果我要從接口動態(tài)渲染組件怎么辦?所有內(nèi)容都是在 #app 下渲染,注冊組件都是在當(dāng)前位置渲染。如果我要實現(xiàn)一個類似于 window.alert() 提示組件要求像調(diào)用 JS 函數(shù)一樣調(diào)用它,該怎么辦?
這時候,Vue.extend + vm.$mount 組合就派上用場了。
簡單實用
基礎(chǔ)用法
Vue.extend( options )
- 參數(shù):{Object} options
- 用法:使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個“子類”。參數(shù)是一個包含組件選項的對象;
- data 選項是特例,需要注意: 在 Vue.extend() 中它必須是函數(shù);
<div id="mount-point"></div> // 創(chuàng)建構(gòu)造器 var Profile = Vue.extend({ template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 創(chuàng)建 Profile 實例,并掛載到一個元素上。 new Profile().$mount('#mount-point') // 結(jié)果如下: <p>Walter White aka Heisenberg</p>
可以看到,extend 創(chuàng)建的是 Vue 構(gòu)造器,而不是我們平時常寫的組件實例,所以不可以通過 new Vue({ components: testExtend }) 來直接使用,需要通過 new Profile().$mount(’#mount-point’) 來掛載到指定的元素上。
第二種寫法
可以在創(chuàng)建實例的時候傳入一個元素,生成的組件將會掛載到這個元素上,跟 $mount 差不多。
// 1. 定義一個vue模版 let tem ={ template:'{{firstName}} {{lastName}} aka {{alias}}', data:function(){ return{ firstName:'Walter', lastName:'White', alias:'Heisenberg' } } // 2. 調(diào)用 const TemConstructor = Vue.extend(tem) const intance = new TemConstructor({el:"#app"}) // 生成一個實例,并且掛載在 #app 上
使用Vue.extend()編寫vue插件
今天,我們使用Vue.extend()編程式的寫法來編寫一個vue插件,本質(zhì)是將插件實例掛載到Vue的原型上。然后,就像element-ui的toast組件那樣,使用this.$toast()實例方法去調(diào)用插件。
Vue.extend()
使用Vue這個基礎(chǔ)構(gòu)造器,構(gòu)造出一個“子類”,其實就是個構(gòu)造函數(shù),通過new運算符生成vue實例。具體見官方文檔Vue-extend。
如何編程式使用組件呢
比如,我們要實現(xiàn)個彈窗功能。通過編程式導(dǎo)航,我們就不用在模板中寫了,可以使用js直接編寫喚出彈窗。首先,我們正常的編寫彈窗組件。如下:
<template> ? <div class="gulu-toast" :class="toastClasses"> ? ? <div class="toast" ref="toast"> ? ? ? <div class="message"> ? ? ? ? <slot v-if="!enableHtml"></slot> ? ? ? ? <div v-else v-html="$slots.default[0]"></div> ? ? ? </div> ? ? ? <div class="line" ref="line"></div> ? ? ? <span class="close" v-if="closeButton" @click="onClickClose"> ? ? ? ? {{closeButton.text}} ? ? ? </span> ? ? </div> ? </div> </template>
<script> ? //構(gòu)造組件的選項 ? export default { ? ? name: 'Toast', ? ? props: { ? ? ? autoClose: { ? ? ? ? type: [Boolean, Number], ? ? ? ? default: 5, ? ? ? ? validator (value) { ? ? ? ? ? return value === false || typeof value === 'number'; ? ? ? ? } ? ? ? }, ? ? ? closeButton: { ? ? ? ? type: Object, ? ? ? ? default () { ? ? ? ? ? return { ? ? ? ? ? ? text: '關(guān)閉', callback: undefined ? ? ? ? ? } ? ? ? ? } ? ? ? }, ? ? ? enableHtml: { ? ? ? ? type: Boolean, ? ? ? ? default: false ? ? ? }, ? ? ? position: { ? ? ? ? type: String, ? ? ? ? default: 'top', ? ? ? ? validator (value) { ? ? ? ? ? return ['top', 'bottom', 'middle'].indexOf(value) >= 0 ? ? ? ? } ? ? ? } ? ? }, ? ? mounted () { ? ? ? // 這里是為了防止不斷點擊,出現(xiàn)多個彈窗 ? ? ? const toast = document.getElementsByClassName('gulu-toast')[0] ? ? ? toast && document.body.removeChild(toast) ? ? ? this.updateStyles() ? ? ? this.execAutoClose() ? ? }, ? ? computed: { ? ? ? toastClasses () { ? ? ? ? return { ? ? ? ? ? [`position-${this.position}`]: true ? ? ? ? } ? ? ? } ? ? }, ? ? methods: { ? ? ? updateStyles () { ? ? ? ? this.$nextTick(() => { ? ? ? ? ? this.$refs.line.style.height = ? ? ? ? ? ? `${this.$refs.toast.getBoundingClientRect().height}px` ? ? ? ? }) ? ? ? }, ? ? ? execAutoClose () { ? ? ? ? if (this.autoClose) { ? ? ? ? ? setTimeout(() => { ? ? ? ? ? ? this.close() ? ? ? ? ? }, this.autoClose * 1000) ? ? ? ? } ? ? ? }, ? ? ? close () { ? ? ? ? this.$el.remove() ? ? ? ? this.$emit('close') ? ? ? ? this.$destroy() ? ? ? }, ? ? ? onClickClose () { ? ? ? ? this.close() ? ? ? ? if (this.closeButton && typeof this.closeButton.callback === 'function') { ? ? ? ? ? this.closeButton.callback(this)//this === toast實例 ? ? ? ? } ? ? ? } ? ? } ? } </script>
接下來,就是Vue.extend()出場了。
import Toast from './src/toast.vue'; Toast.install = function (Vue) { ?? ?// 其實就是全局掛載使用 ? ? Vue.prototype.$toast = function (text, props) { ? ? ? ? const ToastMain = Vue.extend(Toast) ? ? ? ? const instance = new ToastMain({ ? ? ? ? ? ? propsData: props // 這里必須是propsData ? ? ? ? }) ? ? ? ? instance.$slots.default = [text] // 插槽內(nèi)容 ? ? ? ? // instance.$mount().$el 該段代碼意義為: ? ? ? ? // 文檔之外渲染,并且獲取該實例的根DOM元素,將其插入到body元素中。 ? ? ? ? document.body.appendChild(instance.$mount().$el)? ? ? } } export default Toast
我們在main.js入口文件中,使用Vue.use()安裝后,就可以在任何地方使用了~~。
具體使用
this.$toast("關(guān)閉嗎?", { ? ? ? ? closeButton: { ? ? ? ? ? text: "關(guān)閉", ? ? ? ? ? callback: () => { ? ? ? ? ? ? console.log('已經(jīng)關(guān)閉了'); ? ? ? ? ? }, ? ? ? ? }, ? ? ? ? autoClose: 12, ? ? ? ? position: 'bottom' ? ? ? });
小結(jié):
首先,Vue.extend 獲得是一個構(gòu)造函數(shù),可以通過實例化生成一個 Vue 實例。
實例化時可以向這個實例傳入?yún)?shù),但是需要注意的是 props 的值需要通過 propsData 屬性來傳遞。
還可以通過$slots來自定義插槽內(nèi)容。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue源碼中要const _toStr = Object.prototype.toString的原因分析
這篇文章主要介紹了Vue源碼中要const _toStr = Object.prototype.toString的原因分析,在文中給大家提到了Object.prototype.toString方法的原理,需要的朋友可以參考下2018-12-12使用antv替代Echarts實現(xiàn)數(shù)據(jù)可視化圖表詳解
這篇文章主要為大家介紹了使用antv替代Echarts實現(xiàn)數(shù)據(jù)可視化圖表詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08@click.native和@click的區(qū)別及說明
這篇文章主要介紹了@click.native和@click的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08Create?vite理解Vite項目創(chuàng)建流程及代碼實現(xiàn)
這篇文章主要為大家介紹了Create?vite理解Vite項目創(chuàng)建流程及代碼實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10vue無法加載文件C:\xx\AppData\Roaming\npm\vue.ps1系統(tǒng)禁止運行腳本
這篇文章主要介紹了vue?:?無法加載文件?C:\xx\AppData\Roaming\npm\vue.ps1...系統(tǒng)上禁止運行腳本問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07