ly2011 / blog

前端学习笔记
https://ly2011.github.io/blog
122 stars 12 forks source link

vue源码探索的一些疑惑 #146

Open ly2011 opened 5 years ago

ly2011 commented 5 years ago

vue源码探索的一些疑惑

1. 父组件create => 子组件create => 子组件mounted => 父组件mounted?

父组件的初次render会将子组件的vnode存于父组件的vnode的children中,父组件mount之前会做一次初始化patch,patch完会根据vnode创建dom元素,但在创建完,插入dom前会先创建子组件的vue实例和dom元素,并且插入到父组件的dom中去,然后再将父组件插入到浏览器dom中,所以在所有子组件mount之后,父组件才会mount

2. 为啥子组件的emit能触发父组件在该子组件上的监听事件?

<!-- 父组件中 -->
<child @custom-event="handler" />

<!-- 子组件中 -->
this.$emit('custom-event', params)

父组件初次render生成vnode时,会将监听在子组件上的事件(event和handler)挂到到子组件vnode的 componentOptions.listeners 中,在创建或更新子组件的时候将其挂到自身的 $options._parentListeners,然后子组件将这些事件挂在自身的 _events 下,每次$emit就会触发 _events 里的相应的事件,_events 就相当于自身的一个事件池,$on,$off,$emit都会在事件池中触发相应操作

3. 父组件如何监听子组件的生命周期事件?

<!-- 父组件中 -->
<child @hook:mounted="handler" />

4. 子组件的解析分两部分,一部分是在父组件render的时候解析,一种是自己render的时候解析?

待验证,因为看到子组件的vue实例的$options感觉像是在父组件中的解析的结果,而$options.proto才是子组件本身的options

  1. vm._renderProxy 设置代理时候为啥要判断 options.render._withStripped?

https://github.com/vuejs/vue/blob/dev/src/core/instance/proxy.js#L69

vue的render的作用域是vm._renderProxy,在本地开发时候,vue对于template里用到的但是没有在data里定义的数据进行提示,这时候就有了Proxy的has和get拦截。

对于非SFC,使用el或者templete来创建组件的方式,vue会解析template生成render,形如

vm.$options.render = function () {
    with (this) {
        return _c(/*...*/)
    }
}

而使用webpack和vue-loader时,对于SFC,vuejs@component-compiler-utils将template编译成严格模式下不包含with的代码,并为编译后的render设置render._withStripped = true,这时候render会变成下面这样

var render = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _vm._m(0)
}

模板内的变量都是通过属性访问操作_vm._m的形式访问的,Proxy的has是拦截不到属性访问的,所以用了get来拦截

这样以后自定义render也可以有警告提示了

const render = function (h) {
    return h('div', [this.a])
}
render._withStripped = true

var vm = new Vue({
    el: '#app',
    render,
    data: {
        test: 1
    }
})