В последнее время я пишу статьи, связанные с Vue, и если вам интересно, вы можете вернуться к тому, что я писал раньше.
Сборник авторских статей
- «Учитесь на основе исходного кода» полностью разбирайтесь в параметрах Vue.
- Правильная позиция для обновления vue-cli3 в проекте "Vue Practice"
- JS-операция «Узнать из исходного кода» в исходном коде Vue
- Почему вы до сих пор не можете понять цепочку областей видимости JavaScript?
Текст: Съешьте эту рыбу 🐟 -propsинициализация
initPropsКак это работает:
1.normalizeProps: initPropsНормализованные данные до
normalizePropsКод немного длинный, здесь перечислены только нормализованные.propТип и результат
1.1 Струны
props: ["data"]
// 规范化后
props: {
data:{
type: null
}
}
1.2 Объекты
props: {
data1: {
type: String,
default: ''
}
data2: Number,
}
// 规范化后
props: {
data1: {
type: String,
default: ''
},
data2: {
type: Number
},
}
2.initProps: иметь дело сprops
Анализ исходного кода выглядит следующим образом:
function initProps (vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {}
const props = vm._props = {}
const keys = vm.$options._propKeys = []
const isRoot = !vm.$parent
if (!isRoot) {
toggleObserving(false)
}
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
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 direct....`,
vm
)
}
})
} else {
defineReactive(props, key, value)
}
if (!(key in vm)) {
proxy(vm, `_props`, key)
}
}
toggleObserving(true)
}
2.1 Определение константы
const propsData = vm.$options.propsData || {}
const props = vm._props = {}
const keys = vm.$options._propKeys = []
const isRoot = !vm.$parent
-
propsData: сохраняет переданныеpropsзначение -
props: 引用vm._props` и инициализируется как {} -
keys: существуетvm.$optionsдобавить_propKeysАтрибуты -
isRoot: чтобы определить, существует ли онvm.$parent, если не корневой узел
2.2 Условное суждение и цикл
if (!isRoot) {
toggleObserving(false)
}
for (const key in propsOptions) {
// 省略...
}
toggleObserving(true)
-
!isRoot: если текущий экземпляр не является корневым узлом, закрытьtoggleObserving -
toggleObserving: можно понимать как переключатель для наблюдения за данными -
for...in: траверсpropsOptions
2.2.1: ОбходpropsOptionsделать что
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
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 ` +
`overwri tten 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)
}
}
Сфокусируйся на:
-
propsOptionsкоторыйopts.props -
keyкаждыйpropимя
Войдите в цикл в этой точке:
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
- Буду
keyдобавить вvm.$options._propKeys -
value: использоватьvalidatePropПроверьте, является ли это ожидаемым значением типа, а затем верните соответствующее значение свойства (или значение по умолчанию).
2.2.2: Затем введитеif...else:
Примечание здесь:
if (process.env.NODE_ENV !== 'production') {
// 驼峰转连字符
const hyphenatedKey = hyphenate(key)
// 校验prop是否为内置的属性
// 内置属性:key,ref,slot,slot-scope,is
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 ` +
`overwri tten 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)
}
Наконец упрощено:
if (process.env.NODE_ENV !== 'production') {
// 驼峰转连字符
// 校验prop是否为内置的属性
// 内置属性:key,ref,slot,slot-scope,is
// 若是内置,弹出警告
defineReactive(props, key, value, () => {
// 子组件直接修改属性时 弹出警告
} else {
defineReactive(props, key, value)
}
Вспомогательная функция:JS-операция «Узнать из исходного кода» в исходном коде Vue
2.2.3: defineReactive: окончательная обработка
defineReactive(props, key, value)
defineReactiveЭто старый знакомый, но вот небольшая заметка:
ранееtoggleObserving(false), выключает переключатель наблюдения, поэтомуdefineReactiveвызыватьobserve, является недопустимым вызовом.
На этом можно сделать вывод
propsчерезdefineReactiveОпределено, хотя в настоящее время это оперативные данные, оно не имеет глубокого определения.
То есть после того, как родительский компонент передает свойства дочернему компоненту, дочерний компонент не должен повторять наблюдение.props
2.2.4 toggleObserving(true)`: Наконец, откройте переключатель наблюдения.
toggleObserving(true)
Снова откройте переключатель наблюдения, чтобы не повлиять на последующее выполнение кода.