组件用props接收了,那么传给组件的值就能在this里拿到,如果没用props接收,那么只能在attrs里的值并不是响应式的,但是props里的值是响应式的
实现:
- h处理完传入的虚拟节点后会进行渲染,最后调用mountComponent进行组件的挂载(想了解这段过程的看我之前文章)
- 从虚拟节点的type里拿到组件props对象
- 在组件实例上添加两个属性props和attrs
- 然后我们用一个函数来初始化props,传入组件实例好外部传给组件的属性
- 注意,vnode上的type是组件用户写的那部分内容,而vnode上的props是外部传过来的属性
我们在runtime-core中创建一个componentProps.ts文件专门来处理组件props
- 我们最后要处理出两个对象props和attrs
- 我们先拿到用户在组件中用props接收的数据,也就是你平时组件中写的props内容
如果外部给组件传了属性
- 循环用户传来的属性,如果当前组件用props接收了,就放props对象里,如果没有,就放attrs里
- 然后放到组件实例的props上,用shallowReactive处理一下,这个方法只会把对象的第一层做响应式处理,深层不会,所以这也就是你在组件中更改props里的值内部的属性不会重新渲染的原因
- 我们用shallowReactive处理的原因是我不希望props能让用户在组件内部被更改,但是我又必须让prop整体也就是最外层是响应式,因为我希望后续属性变化了后要更新视图
然后我们把attrs也挂载组件的实例上,不用任何处理
问题:
我们前面的文章讲到,在组件处理渲染的时候,会拿到组件内容的虚拟节点进行挂载,但是我们之间的文章里在组件渲染的时候是调用组件render方法然后调用call把this绑定到组件的data数据上,这样是有问题的,组件内容里就拿到不到组件上的props等属性,所以我们要给它一个组件内容渲染的上下文
解决:
在组件实例instance上增加一个代理对象proxy属性
然后我们来处理这个proxy属性,让它代理组件的实例
- 当我们从代理对象上取值的时候,会先去看看组件内部数据也就是data里有没有这个属性,如果有就取,没有就去看看组件内部的props上有没有这个属性,有就取。如果都没取到,那么我就看看你调的是不是$attrs,如果是的,我就从组件实例上取attrs属性
当你设置属性值的时候
- 跟取值一样的套路,但是当我们设置props属性的时候,我们报一个警告
我们还差最后一件事
- 更改组件渲染时,获取组件渲染内容时内部的this指向,这样render中取this属性,就会从我们刚才处理的组件实例代理对象上取