Vue中extends繼承和組件復(fù)用性詳解
前言
提到extends繼承,最先想到的可能是ES6中的class、TS中的interface、面向?qū)ο缶幊陶Z言中中的類和接口概念等等,但是我們今天的關(guān)注點(diǎn)在于:如何在Vue中使用extends繼承特性。
再開始探討Vue繼承相關(guān)的內(nèi)容之前,有必要回顧一下創(chuàng)建Vue組件實(shí)例的幾種方式,個(gè)人總結(jié)如下,
構(gòu)造函數(shù)方式:new Vue
這種方式是較為常見的,在Vue-cli腳手架構(gòu)建的前端項(xiàng)目中,經(jīng)??吹饺缦滤镜拇a段,
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')這就是在以Vue構(gòu)造函數(shù)的方式創(chuàng)建實(shí)例,然后將其掛載到id選擇器為app的DOM元素上。
Vue.extend方式
Vue.js開發(fā)庫提供了Vue.extend()API,用于創(chuàng)建一個(gè)組件。

Vue.extend()方法的源碼如下,內(nèi)部主要是創(chuàng)建了一個(gè)Vue組件對象,并通過外部配置項(xiàng),將其props、computed、mixin等選項(xiàng)設(shè)置為可用,最終將對象返回,
/**
* Class inheritance
*/
Vue.extend = function (extendOptions) {
extendOptions = extendOptions || {};//外部配置項(xiàng)-即:Vue組件的選項(xiàng)配置
console.log(extendOptions)
var Super = this;//指向Vue自身實(shí)例的引用
var SuperId = Super.cid;
var cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {});
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId];
}
var name = getComponentName(extendOptions) || getComponentName(Super.options);
if (name) {
validateComponentName(name);
}
var Sub = function VueComponent(options) {
this._init(options);
};
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.cid = cid++;
Sub.options = mergeOptions(Super.options, extendOptions);
Sub['super'] = Super;
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
if (Sub.options.props) {
initProps(Sub);
}
if (Sub.options.computed) {
initComputed(Sub);
}
// allow further extension/mixin/plugin usage
Sub.extend = Super.extend;
Sub.mixin = Super.mixin;
Sub.use = Super.use;
// create asset registers, so extended classes
// can have their private assets too.
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type];
});
// enable recursive self-lookup
if (name) {
Sub.options.components[name] = Sub;
}
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options;
Sub.extendOptions = extendOptions;
Sub.sealedOptions = extend({}, Sub.options);
// cache constructor
cachedCtors[SuperId] = Sub;
return Sub;
}通過查看Vue.extend()方法的源碼,我們會發(fā)現(xiàn),它內(nèi)部是在調(diào)用Vue原型對象上面的_init()方法來完成組件初始化,通過如下圖所示的一些核心配置,使其成為一個(gè)名副其實(shí)的Vue組件實(shí)例,

那么我們自己如何調(diào)用Vue.extend()方法創(chuàng)建組件呢?示例代碼如下,
/**
* 方式1-Vue.extend-使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個(gè)組件
* PS:此種方式中,data必須為函數(shù)
* */
const IButton = Vue.extend({
name: "IButton",
template: `<button class="btn" @click="clickBtnHandler($event)">Click</button>`,
methods: {
clickBtnHandler(e) {
console.log(e.target.dataset)
}
},
})
Vue.component('i-button', IButton);//Vue.component用途之一:將組件注冊到全局環(huán)境Vue.component方式

Vue.component()方法有兩個(gè)作用,其①:將組件注冊全局可用的組件;其②:以給定的id,創(chuàng)建一個(gè)全局范圍內(nèi)可用的組件。使用此接口創(chuàng)建一個(gè)Vue組件的示例代碼如下,
/**
* 方式2-Vue.component-間接調(diào)用Vue.extend,創(chuàng)建一個(gè)組件
* PS:此種方式中,data必須為函數(shù)
* */
const IList = Vue.component('i-list', {
template: `<div>
<p>列表</p>
<ul>
<li v-for="n in number">{{n}}</li>
</ul></div>`,
data: function () {
return {
number: 5
}
}
})
// Vue.component('i-list', IList);//Vue.component創(chuàng)建的組件無需再注冊render渲染函數(shù)方式

也可以通過Vue.js提供的render()渲染函數(shù)創(chuàng)建一個(gè)Vue組件,如下示例代碼,通過render函數(shù)的函數(shù),根據(jù)props參數(shù)level來創(chuàng)建了一個(gè)級別為level的h標(biāo)簽,并提供插槽供開發(fā)者對其進(jìn)行拓展。
//方式3:基于渲染函數(shù)構(gòu)造函數(shù)式組件-[基于slot插槽方式提供組件內(nèi)容1]
const ITitle = Vue.component(
"i-title",
{
render: function (createElement) {
return createElement(
'h' + this.level, // 標(biāo)簽名稱
this.$slots.default // 子節(jié)點(diǎn)數(shù)組
)
},
props: {
level: {
type: Number,
required: true
}
}
});對象方式

通過對象的形式定義組件-這也是我們在Vue前端應(yīng)用開發(fā)中最常使用的方式,然后通過export default導(dǎo)出。示例代碼如下,
//方式4-通過對象的形式定義組件-這也是我們在Vue前端應(yīng)用開發(fā)中最常使用的方式,然后通過export default導(dǎo)出
const InfoBox = {
name: "InfoBox",
template: `<div class="box" :style="styleObject">{{content}}</div>`,
data() {
return {
content: '消息內(nèi)容',
styleObject: {
boxSizing: "border-box",
padding: "25px",
width: '300px',
height: '200px',
backgroundColor: 'rgba(0,0,0,0.3)'
}
}
}
}
Vue.component('info-box', InfoBox);//Vue.component用途之一:將組件注冊到全局環(huán)境Vue:extends繼承特性
第一部分只介紹了如何創(chuàng)建一個(gè)組件,并沒有介紹如何去提高一個(gè)組件的復(fù)用性。既然談到復(fù)用性,可行的方法有很多,例如:slot插槽、mixix混入、Vue.directive自定義一個(gè)可復(fù)用的指令、通過Install方法開發(fā)一個(gè)可復(fù)用的插件、通過Vue.filter定義一個(gè)可復(fù)用的過濾器等。關(guān)于如上內(nèi)容,Vue官網(wǎng)都有詳細(xì)的介紹。
而接下來要討論的就是Vue官網(wǎng)里面介紹比較含蓄的一種方法:借助extends實(shí)現(xiàn)組件的繼承。

那么具體如何操作呢?我們先來定義一個(gè)基礎(chǔ)列表組件IList,并以事件委托的方式為每一個(gè)列表元素注冊點(diǎn)擊事件,示例代碼如下,
<!--
* @Description: IList列表組件,基于事件委托機(jī)制對列表事件回調(diào)做了優(yōu)化處理
* @Author: Xwd
* @Date: 2023-02-16 00:21:49
* @LastEditors: Xwd
* @LastEditTime: 2023-02-19 17:03:25
* @Attention: 此列表組件的clickHandler()點(diǎn)擊事件默認(rèn)基于index下標(biāo)來選擇性的返回item的值,在一些場景下存在風(fēng)險(xiǎn)-->
<template>
<div class="i-list">
<p v-if="!!title" class="i-title">{{ title }}</p>
<!-- <div class="split-horizon"></div> -->
<div v-if="(list || []).length > 0" class="i-content" @click="clickHandler($event)">
<div class="i-item" v-for="(item, index) in list" :key="index">
<img class="i-item-icon" :src="item.image || noImage" />
<div class="i-item-body">
<div class="i-item-title">{{ item.title }}<span class="iconfont" title="地圖定位" :data-id="item.id"
:data-index="index"></span></div>
<div class="i-item-desc" :title="item.desc">{{ item.desc }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import noImage from '@/assets/images/no.png';
export default {
name: "IList",
props: {
title: {
type: String,
required: false,
default: "",
},
list: {
type: Array,
required: false,
default: () => [],
}
},
mounted() { },
methods: {
/**
* 列表元素點(diǎn)擊事件-回調(diào)函數(shù)
* @param {*} event
*/
clickHandler(event) {
const index = event.target.dataset.index;
if (typeof index !== "undefined" && index !== null) {
this.$emit("click", this.list[Number(index)], Number(index));
}
}
}
}
</script>
<style lang="less" scoped>
</style>而由于我們存在一些不確定因素,例如:props中的list是否具有唯一id、點(diǎn)擊回調(diào)函數(shù)中的具體邏輯是什么?所以我們可以將次組件作為一個(gè)基組件,在后續(xù)使用過程中,在子組件TownList.vue中通過extends的選項(xiàng),來繼承IList組件,實(shí)現(xiàn)復(fù)用。示例代碼如下,
<!--
* @Description:
* @Author: Xwd
* @Date: 2023-02-19 16:50:16
* @LastEditors: Xwd
* @LastEditTime: 2023-02-19 16:56:57
-->
<script>
import IList from '@/components/layout/IList.vue';
export default {
name:"TownList",
extends:IList,
methods:{
/**
* 列表元素點(diǎn)擊事件-回調(diào)函數(shù),覆寫父組件方法,基于元素id值重定義處理邏輯
* @param {*} event 事件對象
*/
clickHandler(event) {
const id = event.target.dataset.id;
console.log(`id=${id}`)
if (typeof id !== "undefined" && id !== null) {
const dataIndex = this.list.findIndex(item => item.id == id);
dataIndex !== -1 & this.$emit("click", this.list[dataIndex], dataIndex)
}
}
}
}
</script>此處我們通過id來區(qū)分每一個(gè)元素,并覆寫了父組件中的clickHandler——點(diǎn)擊事件回調(diào)方法。最終效果如下,

此種方式的不足之處在于:無法在子組件中添加template節(jié)點(diǎn),否則會直接覆蓋掉原有的template模板。
總結(jié)
到此這篇關(guān)于Vue中extends繼承和組件復(fù)用性的文章就介紹到這了,更多相關(guān)Vue extends繼承和組件復(fù)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue多布局模式實(shí)現(xiàn)方法詳細(xì)講解
這篇文章主要介紹了Vue多布局模式實(shí)現(xiàn)方法,多布局模式可以根據(jù)用戶角色所在場景切換頁面布局,是非常常見的基礎(chǔ)功能,感興趣的同學(xué)可以參考下文2023-05-05
Vue.js?前端項(xiàng)目在常見?Web?服務(wù)器上的部署配置過程
Web服務(wù)器支持多種編程語言,如 PHP,JavaScript,Ruby,Python 等,并且支持動態(tài)生成 Web 頁面,這篇文章主要介紹了Vue.js?前端項(xiàng)目在常見?Web?服務(wù)器上的部署配置,需要的朋友可以參考下2023-02-02
關(guān)于vue中標(biāo)簽的屬性綁定值渲染問題
這篇文章主要介紹了關(guān)于vue中標(biāo)簽的屬性綁定值渲染問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
vue項(xiàng)目打包解決靜態(tài)資源無法加載和路由加載無效(404)問題
這篇文章主要介紹了vue項(xiàng)目打包,解決靜態(tài)資源無法加載和路由加載無效(404)問題,靜態(tài)資源無法使用,那就說明項(xiàng)目打包后,圖片和其他靜態(tài)資源文件相對路徑不對,本文給大家介紹的非常詳細(xì),需要的朋友跟隨小編一起看看吧2023-10-10
Vue3 computed初始化獲取設(shè)置值實(shí)現(xiàn)示例
這篇文章主要為大家介紹了Vue3 computed初始化以及獲取值設(shè)置值實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
vue項(xiàng)目根據(jù)不同環(huán)境進(jìn)行設(shè)置打包命令的方法
這篇文章主要介紹了vue項(xiàng)目根據(jù)不同環(huán)境進(jìn)行設(shè)置打包命令,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11
vue微信分享的實(shí)現(xiàn)(在當(dāng)前頁面分享其他頁面)
這篇文章主要介紹了vue微信分享,在當(dāng)前頁面分享其他頁面,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-04-04

