Vue.extend和VueComponent的關(guān)系源碼解析
前言
寫Vue.js已經(jīng)3年了吧,對(duì)Vue.extend全局方法的了解也就停留在了解啦,一直抱著不用就不學(xué)的思想,造成了一次又一次的錯(cuò)過(guò)~~~
直到最近,才通過(guò)公司10年禿頭少年的代碼,才知道錯(cuò)過(guò)Vue.extend方法,也就等于錯(cuò)過(guò)了對(duì)Vue組件的第二春了解的機(jī)會(huì)!??!
需求分析
在頁(yè)面中彈出消息提示框,比如在用戶點(diǎn)擊按鈕給予回應(yīng)
這種業(yè)務(wù)場(chǎng)景很常見(jiàn)吧,肯定是先創(chuàng)建一個(gè)彈框組件,在需要使用彈框的地方注冊(cè)組件并掛載到頁(yè)面上去
但是需求還沒(méi)結(jié)束,又提出在所以頁(yè)面都可以彈出這個(gè)消息提示框
首選局部注冊(cè)肯定是不行了,局部注冊(cè)只能當(dāng)前頁(yè)面使用,所以要選擇在App.vue中注冊(cè)并掛載,因?yàn)锳pp.vue是所有組件的根組件,所以組件也都能訪問(wèn)到App.vue中的方法,我們只需要在App.vue暴露一個(gè)彈框顯示的方法就可以了
產(chǎn)品還不打算放過(guò)我,又提出需求是可以同時(shí)出現(xiàn)多個(gè)消息提示框
這個(gè)就不好實(shí)現(xiàn)了呀,一個(gè)組件掛載只能彈出一個(gè)提示框,總不能在App.vue掛載很多個(gè)吧,其實(shí)這也是解決方案,但是不利于擴(kuò)展、占用內(nèi)存?。?!
那就沒(méi)有辦法了嗎?也不是,那就要請(qǐng)出主角Vue.extend全局方法?。?!
Vue.extend
看看官方的八股文:
使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個(gè)“子類”。參數(shù)是一個(gè)包含組件選項(xiàng)的對(duì)象
我認(rèn)為這段文字表達(dá)十分明了,首先Vue.extend參數(shù)是包含組件選項(xiàng)的對(duì)象,返回值是Vue的子類
import Vue from 'vue' let VueComponent = Vue.extend({}) VueComponent.prototype.__proto__ == Vue.prototype // true
我們這里將子類稱為VueComponent
你對(duì)這個(gè)名稱很熟悉吧~~~
import Vue from 'vue/dist/vue.esm.js' // 必須引入這個(gè)版本的Vue才可以使用template選項(xiàng) new Vue({ el: "#app", template: ` <App></App> `, components: { App }, mounted() { let app = this.$children[0]; // App組件實(shí)例 let VueComponent = app.constructor // App構(gòu)造函數(shù) console.log(app); console.log(VueComponent); console.log(VueComponent.prototype.__proto__ == Vue.prototype); } })
不難發(fā)現(xiàn)VueComponent就是組件的構(gòu)造函數(shù)~~~
是不是一下就明白了,Vue.extend的返回值就是組件的構(gòu)造函數(shù),傳入的選項(xiàng)就是組件的初始配置
Vue.extend作用可以理解為:
首選創(chuàng)建一個(gè)Vue類的子類(組件的構(gòu)造函數(shù)),將傳入的組件選項(xiàng)配置當(dāng)做實(shí)例子類的默認(rèn)值(組件的初始配置),并返回這個(gè)類(組件的構(gòu)造函數(shù))
Vue.component("Toast", {}) // 全局注冊(cè)組件 console.log(Vue.component("Toast")); // Toast組件構(gòu)造函數(shù)
在使用Vue.component方法注冊(cè)全局組件時(shí),其實(shí)內(nèi)部也是先調(diào)用Vue.extend生成VueComponent,再聲明到全局組件中,局部組件也是一樣的~~~
其實(shí)這里還能了解一個(gè)知識(shí)點(diǎn):所以的組件構(gòu)造函數(shù)的父類都是Vue,所以組件可以使用Vue上所以方法和屬性,比如emit、set等
編程式的使用組件
VueComponent可以被稱為小Vue,VueComponent的使用也就可以對(duì)照Vue
let VueComponent = Vue.extend({}) new VueComponent({ el: "#app", template: `<h1>Vue.extend的使用</h1>` })
是不是和Vue的使用一模一樣喃?
區(qū)別在于Vue.extend可以通過(guò)參數(shù)確定組件的初始配置~~~
現(xiàn)在完成一下最開(kāi)始的需求吧~
編寫my-toast.vue
<template> <h1 class="title" v-if="show">{{ title }}</h1> </template> <script> export default { name: "my-toast", props: { title: { typeof: String, default: "" } }, data() { return { show: true }; }, created() { setTimeout(() => { this.show = false; this.$nextTick(() => { this.$destroy(); }); }, 2000); } }; </script> <style> .title { width: 180px; height: 50px; position: fixed; right: 20px; top: 20px; background-color: rgba(0, 0, 0, 0.15); text-align: center; line-height: 50px; border-radius: 8px; font-size: 16px; } </style>
在vue的原型上綁定顯示彈框方法
import Vue from 'vue'; import myToast from './components/my-toast.vue'; Vue.prototype.$toast = function (title) { const ToastComponent = Vue.extend(myToast); const toastComponent = new ToastComponent({ propsData: { title } }) toastComponent.$mount(document.createElement('div')); document.body.appendChild(toastComponent.$el); }
在需要彈框的地方調(diào)用方法
// ....某vue頁(yè)面 mounted() { this.$toast("測(cè)試"); }
let vm = new VueComponent(options)
的注意點(diǎn):
- 傳遞的props配置需要配置到propsData屬性中
- 使用VueX、
VueRoter
等第三方模塊,需要把這些模塊掛載到options上 - 使用插槽需要通過(guò)vm.$scopedSlots傳遞
源碼分析
你可以在源碼目錄src/core/global-api/extend.js
下找到這個(gè)函數(shù)的定義
Vue.extend = function (extendOptions: any): typeof Component { extendOptions = extendOptions || {} // this指的是Vue const Super = this // 每個(gè)組件構(gòu)造函數(shù)都有唯一的cid const SuperId = Super.cid // 創(chuàng)建完的VueComponent構(gòu)造函數(shù),會(huì)保存到_Ctor中 // 如果下次傳入相同的extendOptions和SuperId,就直接取用緩存內(nèi)的值 const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {}) if (cachedCtors[SuperId]) { return cachedCtors[SuperId] } // 獲取組件name const name = getComponentName(extendOptions) || getComponentName(Super.options) if (__DEV__ && name) { // 校驗(yàn)組件name validateComponentName(name) } // 創(chuàng)建VueComponent構(gòu)造函數(shù) const Sub = function VueComponent(this: any, options: any) { this._init(options) } as unknown as typeof Component // 重點(diǎn):實(shí)現(xiàn)了原型鏈繼承,讓VueComponent的原型指向Vue的原型 // Vue的原型的所有方法和屬性,在VueComponent也存在 Sub.prototype = Object.create(Super.prototype) Sub.prototype.constructor = Sub // 生成唯一cid Sub.cid = cid++ // 傳入的extendOptions和Vue.options合并 Sub.options = mergeOptions(Super.options, extendOptions) Sub['super'] = Super // 配置props的響應(yīng)式 if (Sub.options.props) { initProps(Sub) } // 配置computed的響應(yīng)式 if (Sub.options.computed) { initComputed(Sub) } // 繼承靜態(tài)方法 Sub.extend = Super.extend Sub.mixin = Super.mixin Sub.use = Super.use // ASSET_TYPES = ['component', 'directive', 'filter'] ASSET_TYPES.forEach(function (type) { Sub[type] = Super[type] }) if (name) { Sub.options.components[name] = Sub } // 保存基礎(chǔ)配置 Sub.superOptions = Super.options Sub.extendOptions = extendOptions Sub.sealedOptions = extend({}, Sub.options) // 設(shè)置緩存 cachedCtors[SuperId] = Sub return Sub }
Vue.extend關(guān)鍵在于繼承Vue,拋開(kāi)其他功能代碼,主要實(shí)現(xiàn)繼承的代碼:
// 繼承原型 Sub.prototype = Object.create(Super.prototype) Sub.prototype.constructor = Sub // 繼承靜態(tài)方屬性和方法 // 繼承靜態(tài)方法 Sub.extend = Super.extend Sub.mixin = Super.mixin Sub.use = Super.use // ASSET_TYPES = ['component', 'directive', 'filter'] ASSET_TYPES.forEach(function (type) { Sub[type] = Super[type] })
以上就是Vue.extend和VueComponent的關(guān)系源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Vue.extend和VueComponent的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vite前端構(gòu)建Turborepo高性能monorepo方案
這篇文章主要為大家介紹了vite前端構(gòu)建Turborepo高性能monorepo方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08el-date-picker設(shè)置日期默認(rèn)值兩種方法(當(dāng)月月初至月末)
這篇文章主要給大家介紹了關(guān)于el-date-picker設(shè)置日期默認(rèn)值(當(dāng)月月初至月末)的相關(guān)資料,文中通過(guò)代碼示例將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08基于Vue3+TypeScript實(shí)現(xiàn)圖片預(yù)覽組件
在現(xiàn)代的 Web 應(yīng)用中,圖片預(yù)覽是一個(gè)常見(jiàn)的需求,本文將介紹如何使用 Vue3 和 TypeScript 開(kāi)發(fā)一個(gè)圖片預(yù)覽組件,支持展示單張或多張圖片,并提供了豐富的配置選項(xiàng),需要的朋友可以參考下2024-04-04vue+springmvc導(dǎo)出excel數(shù)據(jù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue+springmvc導(dǎo)出excel數(shù)據(jù)的實(shí)現(xiàn)代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06vue中對(duì)象數(shù)組去重的實(shí)現(xiàn)
這篇文章主要介紹了vue中對(duì)象數(shù)組去重的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02