问题
- props是什么?
- props的分类?
- 如何声明和验证(认知型)?
- 单向数据流?
- 响应式?
- 如何实现赋值、验证与响应式?
- 与data的异同
props是什么?
- 官方定义没什么可说的,用来完成父子通信,直接阅读。
- 从知识迁移的的角度,类比暴漏了对外setter和getter的private属性,包括proxy和监听
props的分类
- 自定义属性:子组件具体声明的属性
- 原生属性:传给子组件未声明的属性。默认挂载在组件的根元素。受inheritAttrs属性控制。
- 特殊属性:特殊的原生属性。例如style,class
清晰的分类有解除初学者的一些困惑。
如何声明和验证(认知型)
从使用者的角度,直接参考官网,忘记了翻一下。
建议:自定义属性的时候使用严格类型检查的方式。比较好维护。
单向数据流
- 父子 prop 之间形成了一个单向下行绑定。
- 从可维护性的角度的去考虑的。Vue的prop性质从机制上保证了数据流的单向性,而不是靠人为约定(试图修改时给出警告)。
-
官方给出了两种可能违反单向数据流的最佳实践
- props有双向绑定的需求,实际中会有子组件修改prop的意图,怎么做?
官方推荐
响应式
与data选项中的数据一样。数据改变视图更新。
宏观上如何实现赋值、验证与响应式
以下省略组件的create过程和响应式原理。
// src/core/instance/state.js
export function initState (vm: Component) {
...
const opts = vm.$options
if (opts.props) initProps(vm, opts.props) // opts.props, 规范化后的声明属性。这里是模版
...
}
function initProps (vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {} // 父组件给传递的原始数值。 省略了提取过程。
const props = vm._props = {} // 实例化后的props
// ...
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm) // 数据安全验证
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
const hyphenatedKey = hyphenate(key)
if (isReservedAttribute(hyphenatedKey) ||
config.isReservedAttr(hyphenatedKey)) {
warn(
`"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
vm
)
}
defineReactive(props, key, value, () => {
if (!isRoot && !isUpdatingChildComponent) {
warn(
`Avoid mutating a prop directly since the value will be ` +
`overwritten whenever the parent component re-renders. ` +
`Instead, use a data or computed property based on the prop's ` +
`value. Prop being mutated: "${key}"`,
vm
)
}
})
} else {
defineReactive(props, key, value)
}
// static props are already proxied on the component's prototype
// during Vue.extend(). We only need to proxy props defined at
// instantiation here.
if (!(key in vm)) {
proxy(vm, `_props`, key)
}
}
toggleObserving(true)
}
总结:
- 通过子组件声明的propsOptions和父组件提供的propsData,满足props实例化的充分条件。真实的实例化属性被存储于_props属性,通过proxy可以直接使用。
- 通过validateProp(...)实现安全验证
- 通过defineReactive(...)实现响应式