摘要:所以方法,是對默認進行擴展,從而實現擴展。這里我用了這個庫提供的合并方法,用來合并兩個對象,并不會修改原對象的內容。測試符合我們的預期,方法也就實現了,下一步,實現父子組件。系列文章地址優化優化總結
看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。
組件的擴展在 Vue 中有 extend 方法可以擴展 Vue 的實例,在上一步中,有一些實現是必須要通過子父組件才能實現,而子組件相當于一個特殊的 Vue 實例,所以這步,我們先把這個擴展實例的方法實現。
我們先來看看官網對于 extend 方法的介紹:
使用基礎 Vue 構造器,創建一個“子類”。參數是一個包含組件選項的對象。
從后面一句和具體的使用方法可以得出其實是我們創建實例時,對于傳入參數的擴展。對于這個參入參數我們就叫它 options。
我們接著往下想,既然這個 options 是能擴展的,那么原 Vue 類下,肯定保存著一個默認 options ,而創建 Vue 實例時,會把傳入的 options 和默認的 options 進行合并。
所以 extend 方法,是對默認 options 進行擴展,從而實現擴展。
mergeOptionsok 有了思路,我們來實現它:
首先是默認的 options ,同時我們假設一個方法(mergeOptions)用來合并 options
let uid = 0 export class Vue extends Event { ··· _init(options) { let vm = this // 為了方便引用合并的 options 我們把它掛載在 Vue 實例下 vm.$options = mergeOptions( this.constructor.options, options, vm ) ··· } } // 默認的 options Vue.options = { // 組件列表 components: {}, // 基類 _base: Vue }
接著我們來實現 mergeOptions :
import R from "ramda" export function mergeOptions(parent, child) { // data/methods/watch/computed let options = {} // 合并 data 同名覆蓋 options.data = mergeData(parent.data, child.data) // 合并 methods 同名覆蓋 options.methods = R.merge(parent.methods, child.methods) // 合并 watcher 同名合并成一個數組 options.watch = mergeWatch(parent.watch, child.watch) // 合并 computed 同名覆蓋 options.computed = R.merge(parent.computed, child.computed) return options } function mergeData(parentValue, childValue) { if (!parentValue) { return childValue } if (!childValue) { return parentValue } return function mergeFnc() { return R.merge(parentValue.call(this), childValue.call(this)) } } // 由于 watcher 的特殊性,我們不覆蓋同名屬性,而是都保存在一個數組中 function mergeWatch(parentVal, childVal) { if (!childVal) return R.clone(parentVal || {}) let ret = R.merge({}, parentVal) for (let key in childVal) { let parent = ret[key] let child = childVal[key] if (parent && !Array.isArray(parent)) { parent = [parent] } ret[key] = parent ? parent.concat(child) : Array.isArray(child) ? child : [child] } return ret }
目前我們僅僅實現了 data/methods/watch/computed 這 4 個 options 中的內容,所以我們先合并這 4 項,由于 data/methods/computed 這 3 項是具有唯一性(比如 this.a 應該是一個確定的值),所以采用同名屬性覆蓋的方式,而 watch 是當發生變化時候執行方法,所以所有注冊過的方法都應該執行,因而采用同名屬性的內容合并成一個數組。
這里我用了 ramda 這個庫提供的合并方法,用來合并兩個對象,并不會修改原對象的內容。
extendok 合并 options 的方法寫好了,我們接著來實現 extend 同過上面的分析,extend 函數僅僅是對默認 options 的擴展
Vue.extend = function (extendOptions) { const Super = this class Sub extends Super { constructor(options) { super(options) } } Sub.options = mergeOptions( Super.options, extendOptions ) Sub.super = Super Sub.extend = Super.extend return Sub }
同樣的我們使用 mergeOptions 來合并一下 options 即可,同時將 super 指向父類、獲取 extend 方法。
測試import {Vue} from "./Vue.mjs" let subVue = Vue.extend({ data() { return { dataTest: 1 } }, methods: { methodTest() { console.log("methodTest") } }, watch: { "dataTest"(newValue, oldValue) { console.log("watchTest newValue = " + newValue) } }, computed: { "computedTest": { get() { return this.dataTest + 1 } } } }) let test = new subVue({ data() { return { subData: 11 } }, methods: { subMethod() { console.log("subMethodTest") } }, watch: { "subData"(newValue, oldValue) { console.log("subWatch newValue = " + newValue) } }, computed: { "subComputed": { get() { return this.subData + 1 } } } }) console.log(test.dataTest) // 1 console.log(test.subData) // 11 console.log(test.computedTest) // 2 console.log(test.subComputed) // 12 test.methodTest() // methodTest test.subMethod() // subMethodTest test.dataTest = 2 // watchTest newValue = 2 test.subData = 12 // subWatch newValue = 12 console.log(test.constructor === subVue) // true console.log(subVue.super === Vue) // true
ok 符合我們的預期,extend 方法也就實現了,下一步,實現父子組件。
系列文章地址VUE - MVVM - part1 - defineProperty
VUE - MVVM - part2 - Dep
VUE - MVVM - part3 - Watcher
VUE - MVVM - part4 - 優化Watcher
VUE - MVVM - part5 - Observe
VUE - MVVM - part6 - Array
VUE - MVVM - part7 - Event
VUE - MVVM - part8 - 優化Event
VUE - MVVM - part9 - Vue
VUE - MVVM - part10 - Computed
VUE - MVVM - part11 - Extend
VUE - MVVM - part12 - props
VUE - MVVM - part13 - inject & 總結
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94796.html
摘要:看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。而該組件實例的父實例卻并不固定,所以我們將這些在使用時才能確定的參數在組件實例化的時候傳入。系列文章地址優化優化總結 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 前言 在上一步,我們實現 extend 方法,用于擴展 Vue 類,而我們知道子組件需要通過 extend 方法來實現,我們從測試例...
摘要:通過裝作這些變化,我們實現了從而到達了數據變化觸發函數的過程。于此同時,我們還實現了來擴展這個可響應的結構,讓這個對象擁有了觸發和響應事件的能力。最后,根據我們的實現,這是最終的產出,一個框架,了解一下系列文章地址優化優化總結 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 provide / inject 在上一步我們實現了,父子組件,和 props 一樣 pr...
摘要:事件是什么在標準瀏覽器中,我們經常使用來為一個添加一個事件等。仔細看這些情況,歸結到代碼中,無非就是一個行為或情況的名稱,和一些列的動作,而在中動作就是,一系列的動作就是一個函數的集合。 看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。 事件是什么? 在標準瀏覽器中,我們經常使用:addEventListener 來為一個 DOM 添加一個事件(click、mouse...
摘要:關于中的的實現,差不多也就這樣了,當然這僅僅是基礎的實現,而且視圖層層渲染抽象成一個函數。不同于中的實現,這里少了很多各種標記和應用標記的過程。 看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。 回顧 首先我們思考一下截止當前,我們都做了什么 通過 defineReactive 這個函數,實現了對于數據取值和設置的監聽 通過 Dep 類,實現了依賴的管理 通過 Wa...
摘要:在中關于如何實現在網上可以搜出不少,在看了部分源碼后,梳理一下內容。換個說法,當我們取值的時候,函數自動幫我們添加了針對當前值的依賴,當這個值發生變化的時候,處理了這些依賴,比如說節點的變化。 在 VUE 中關于如何實現在網上可以搜出不少,在看了部分源碼后,梳理一下內容。 首先,我們需要了解一下 js 中的一個 API :Object.defineProperty(obj, prop,...
閱讀 582·2021-11-22 14:45
閱讀 3070·2021-10-15 09:41
閱讀 1555·2021-10-11 10:58
閱讀 2797·2021-09-04 16:45
閱讀 2606·2021-09-03 10:45
閱讀 3238·2019-08-30 15:53
閱讀 1221·2019-08-29 12:28
閱讀 2133·2019-08-29 12:14