内容简介:在我们先来看看官网对于使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
在 Vue
中有 extend
方法可以扩展 Vue
的实例,在上一步中,有一些实现是必须要通过子父组件才能实现,而子组件相当于一个特殊的 Vue
实例,所以这步,我们先把这个扩展实例的方法实现。
我们先来看看官网对于 extend
方法的介绍:
使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
从后面一句和具体的使用方法可以得出其实是我们创建实例时,对于传入参数的扩展。对于这个参入参数我们就叫它 options
。
我们接着往下想,既然这个 options
是能扩展的,那么原 Vue
类下,肯定保存着一个默认 options
,而创建 Vue
实例时,会把传入的 options
和默认的 options
进行合并。
所以 extend
方法,是对默认 options
进行扩展,从而实现扩展。
mergeOptions
ok 有了思路,我们来实现它:
首先是默认的 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 这个库提供的合并方法,用来合并两个对象,并不会修改原对象的内容。
extend
ok 合并 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
方法也就实现了,下一步,实现父子组件。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- php如何实现session,自己实现session,laravel如何实现session
- AOP如何实现及实现原理
- webpack 实现 HMR 及其实现原理
- Docker实现原理之 - OverlayFS实现原理
- 为什么实现 .NET 的 ICollection 集合时需要实现 SyncRoot 属性?如何正确实现这个属性?
- 自己实现集合框架(十):顺序栈的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。