实现 VUE 中 MVVM - step11 - Extend

栏目: 编程工具 · 发布时间: 5年前

内容简介:在我们先来看看官网对于使用基础 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/computed4options 中的内容,所以我们先合并这 4 项,由于 data/methods/computed3 项是具有唯一性(比如 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 方法也就实现了,下一步,实现父子组件。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法导论(原书第3版)

算法导论(原书第3版)

Thomas H.Cormen、Charles E.Leiserson、Ronald L.Rivest、Clifford Stein / 殷建平、徐云、王刚、刘晓光、苏明、邹恒明、王宏志 / 机械工业出版社 / 2012-12 / 128.00元

在有关算法的书中,有一些叙述非常严谨,但不够全面;另一些涉及了大量的题材,但又缺乏严谨性。本书将严谨性和全面性融为一体,深入讨论各类算法,并着力使这些算法的设计和分析能为各个层次的读者接受。全书各章自成体系,可以作为独立的学习单元;算法以英语和伪代码的形式描述,具备初步程序设计经验的人就能看懂;说明和解释力求浅显易懂,不失深度和数学严谨性。 全书选材经典、内容丰富、结构合理、逻辑清晰,对本科......一起来看看 《算法导论(原书第3版)》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具