今天围观了知乎上有一块儿争执,并在评论中看到以下对话: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) }