之所以将directive、filter、component三个方法放到一起,是因为这三个方法实现的原理是一模一样的,在vue的源码中,也是一起实现的。
Vue.directive( id, [definition] )
Vue.component( id, [definition] )
Vue.filter( id, [definition] )
参数:
{string} id
{Function} [definition]
作用:
注册或者获取全局的指令、组件、过滤器。
原理:
src/core/global-api/assets.js
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
src/core/global-api/index.js
Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
ASSET_TYPES.forEach(type => {
Vue[type] = function (id,definition) {
if (!definition) {
return this.options[type + 's'][id]
} else {
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
看上面的代码,在asset.js文件中定义了存放directive、filter、component的数组。道入道global-api/index.js文件中。
首先在实例的options选项中添加一个空对象。然后通过遍历ASSET_TYPES向Vue.options添加directive、filter、component三个空对象。
然后遍历ASSET_TYPES,为vue实例上添加了directive、filter、component方法。方法接收俩个参数:参数id指对应的指令,参数definition指令的定义。当然difinition也是用来判断是注册指令还是获取指令的标志。
方法中,首先判断definition是否存在,如果不存在那就意味着获取指令。那么就从存放指令的options上直接返回对应id的指令。
如果definition存在,那是意味这要注册指令。
如果不是生成环境,且是component指令,就要首先去校验id的合法性。
如果组件,而且判断传入的definition
参数是否是一个对象,如果是对象,则使用Vue.extend
方法将其变为Vue
的子类,同时如果definition
对象中不存在name
属性时,则使用组件id
作为组件的name
属性。
判断如果是指令directive而且传入的definition是一个function,则默认监听bind
和update
两个事件,即将definition
函数分别赋给bind
和update
两个属性。
如果以上判断definition不是函数,那么就默认是用户的自定义指令。直接挂在option上:this.options[types + 's'][id] = definition
最后返回definition。
这就是directive、component、filter的实现原理,他们的实现如出一辙。。。。