Vue2 原理速成班:一天学会,跟面试官扳扳手腕!

36 阅读2分钟

想要一天彻底搞懂 Vue 2 的原理,确实是一项挑战,但并非不可能。下面是一个学习计划,以及补充Vue2原理的重要性和实际价值的说明。

初始化流程

  1. 初始化Vue的指令

    a. 对vue实例的options属性进行合并

  2. 初始化mixin

    a. 对vue实例的options属性进行合并

  3. 初始化插件

    a. 执行插件定义的install 方法

image.png

我们先来看Vue是怎么渲染在页面中的,html结构如下

    const vm = new MiniVue({
        el: '#app',
        data: {
            newAge: 20,
            age: 18,
            name: '小马',
            obj: {
                a: {
                    msg: 'abc'
                }
            },
            select: ['v1', 2, 3, 4],
            pick: '',
            checkedNames: [],
            address: ['中国', '天津', '南开'],
            html: '<span style="color:red">这是一段v-html</span>',
            show: 'a',
            newAddress: ['银河', '太阳', '地球'],
            if: true
        },
        // 五个生命周期函数
        init() {
            console.log('init')
        },
        created() {
            console.log('created')
        },
        beforeCompile() {
            console.log('beforeCompile')
        },
        compiled() {
            console.log('compiled')
        },
        destroyed() {
            console.log('destroyed')
        },
        directives: {
            'my-directive': objd
        },
        methods: {
            increase() {
                this.age++
            },
            reset() {
                this.address = ['中国', '天津', '南开']
            },
            sayHi() {
                console.log('父组件有一个自己的sayHi方法')
            },
            sayTest(msg) {
                console.log('hi, '  + msg)
            }
        },
        computed: {
            comTest() {
                return this.age + ' ' + this.name
            }
        },
        filters: {
            capitalize(value) {
                if (!value) {
                    return ''
                }
                value = value.toString()
                return value.charAt(0).toUpperCase() + value.slice(1)
            }
        },
        components: {
            'my-component': obj
        },
        mixin: {
            methods: {
                newMixin() {
                    console.log('newMixin')
                }
            }
        },
        computed: {
            comTest() {
                return this.age + ' ' + this.name
            }
        }
    })

看下 MiniVue构造函数的定义,这里MiniVue就可以理解为Vue,我们对模型进行了简化。

function MiniVue(options) {
    debugger
    this._init(options)
}

看看__init看了啥

    _init(options) {
        this.$el = null
        this.$parent = options.parent
        // MiniVue实例
        this._isMiniVue = true
        // 根组件
        this.$root = this.$parent? this.$parent.$root : this
        // 存放子组件
        this.$children = []

        // 存放观察者实例
        this._watchers = []

        // 存放事件
        this._events = {}

        // 存放指令
        this._directives = []

        // 父级上下文对象
        this._context = options._context || this.$parent

        if (this.$parent) {
            this.$parent.$children.push(this)
        }
        
        // 合并参数
        // 在这里将用到的components继承Vue实例
        options = this.$options = mergeOptions(this.constructor.options, options, this)
        this._callHook('init')
        
        this._initMixins()
        this._initComponents()    
        this._initProps()      
        this._initMethods()     
        this._initData()      
        this._initWatch()
        this._initComputed()
        this._initEvents()

        this._callHook('created')
        if (options.el) {
            this._compile()
        }
    },

初始化mixin

    // 局部mixin
    _initMixins() {
        let options = this.$options
        if (options.mixin) {
            this.$options = mergeOptions(options, options.mixin)         
        }
    },

初始化components

    // 局部componet
    _initComponents() {
        const components = this.$options.components
        const keys = Object.keys(components)
        keys.forEach(key => {
            components[key] = MiniVue.component(key, components[key], true)
        })
    },

看props处理

export function getBindAttr(node, name) {
    let val = getAttr(node, ':' + name)
    if (val === null) {
        val = getAttr(node, 'v-bind:' + name)
    }
    return val
}
        if ((value = getBindAttr(el, name)) !== null) {
            // 动态绑定
            // 如果是:xxxx 则给动态标记
            prop.dynamic = true
            prop.raw = prop.parentPath = value
        } else if ((value = getAttr(el, name)) !== null) {
            // 静态绑定
            prop.raw = value
        }

会把prop转成一个对象,如下图:

image.png

然后把这个对象push到props中

初始化流程图

image.png

image.png

模板编译过程

image.png

模板渲染过程

image.png