今天圍觀了知乎上有一塊兒爭執,並在評論中看到以下對話:html
A 說: 例如自定義組件名大寫,而不是Element的前綴形式,更易於在模板中區分原生HTML標籤和自定義組件。再如iView禁用input能夠這麼寫<input disable/>, Element文檔是這麼寫的<input :disable-true>,哪一個更清晰呢?;二是詳細精美的文檔,早期甚至好過Element的文檔。B 說:1. 組件名支持大駝峯命名法,這個 Vue 官網裏就有提, 我不知道評論者怎麼會認爲這是組件庫的特點了,任何組件均可以這麼寫。 2. input 的 disable,一樣 Vue 文檔也有提到,只是寫法不一樣,這也算特色?vue
以前在 vue 1.0 時代,寫過一篇 組件之駝峯git
第二點有點意外,特地作了個實驗github
官方文檔寫的比較隱蔽,在升級指南中有說起,看完後不是很理解,因而翻了下 vue 2.2.1 源碼,主要涉及如下幾處:ide
vue/src/core/instance/init.js
ui
export function initMixin (Vue: Class<Component>) { Vue.prototype._init = function (options?: Object) { ... vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initState(vm) // <==== 初始化狀態 initInjections(vm) callHook(vm, 'created') ... } }
vue/src/core/instance/state.js
spa
export function initState (vm: Component) { vm._watchers = [] const opts = vm.$options if (opts.props) initProps(vm, opts.props) // <==== 初始化屬性 if (opts.methods) initMethods(vm, opts.methods) if (opts.data) { initData(vm) } else { observe(vm._data = {}, true /* asRootData */) } if (opts.computed) initComputed(vm, opts.computed) if (opts.watch) initWatch(vm, opts.watch) }
function initProps (vm: Component, propsOptions: Object) { const propsData = vm.$options.propsData || {} const props = vm._props = {} // cache prop keys so that future props updates can iterate using Array // instead of dynamic object key enumeration. const keys = vm.$options._propKeys = [] const isRoot = !vm.$parent // root instance props should be converted observerState.shouldConvert = isRoot for (const key in propsOptions) { keys.push(key) const value = validateProp(key, propsOptions, propsData, vm) // 校驗屬性值 /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { if (isReservedProp[key]) { warn( `"${key}" is a reserved attribute and cannot be used as component prop.`, vm ) } defineReactive(props, key, value, () => { if (vm.$parent && !observerState.isSettingProps) { 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) } } observerState.shouldConvert = true }
vue/src/core/util/props.js
.net
export function validateProp ( key: string, propOptions: Object, propsData: Object, vm?: Component ): any { const prop = propOptions[key] const absent = !hasOwn(propsData, key) let value = propsData[key] // handle boolean props if (isType(Boolean, prop.type)) { if (absent && !hasOwn(prop, 'default')) { value = false } else if (!isType(String, prop.type) && (value === '' || value === hyphenate(key))) { value = true } } // check default value if (value === undefined) { value = getPropDefaultValue(vm, prop, key) // since the default value is a fresh copy, // make sure to observe it. const prevShouldConvert = observerState.shouldConvert observerState.shouldConvert = true observe(value) observerState.shouldConvert = prevShouldConvert } if (process.env.NODE_ENV !== 'production') { assertProp(prop, key, value, vm, absent) } return value }
vue/src/shared/util.js
prototype
const hasOwnProperty = Object.prototype.hasOwnProperty export function hasOwn (obj: Object, key: string): boolean { return hasOwnProperty.call(obj, key) }