您现在的位置是:网站首页> 编程资料编程资料
vue2源码解析之全局API实例详解_vue.js_
2023-05-24
1006人已围观
简介 vue2源码解析之全局API实例详解_vue.js_
前言
实例方法是挂载在vue的原型上,而全局方法是挂载在vue上;全局方法有12个,分别为extend、nextTick、set、delete、directive、filter、component、use、mixin、version和observable;
Vue.extend()
基本使用
/* 作用: 使用基础vue构造器,创建一个子类,参数是一个包含组件选项的对象 `data` 选项是特例,需要注意 - 在 `Vue.extend()` 中它必须是函数 */ Vue.extend(options) // eg: // 创建构造器 var Profile = Vue.extend({ template: '{{firstName}} {{lastName}} aka {{alias}}
', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 创建 Profile 实例,并挂载到一个元素上。 new Profile().$mount('#mount-point') // 结果: Walter White aka Heisenberg
整体源码
// 源码位置 src/core/global-api/extend.js Vue.extend = function (extendOptions: Object): Function { // 初始化参数 extendOptions = extendOptions || {} // 存储父类 const Super = this // 存储父类的唯一标识 const SuperId = Super.cid // 获取到参数中的缓存数据 const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {}) // 如果已经缓存过就会缓存中获取返回 if (cachedCtors[SuperId]) { return cachedCtors[SuperId] } // 获取到name const name = extendOptions.name || Super.options.name if (process.env.NODE_ENV !== 'production' && name) { validateComponentName(name) } // 创建一个子类 const Sub = function VueComponent (options) { this._init(options) } // 原型继承 Sub.prototype = Object.create(Super.prototype) // 修改构造器 Sub.prototype.constructor = Sub // 子类的唯一标识 Sub.cid = cid++ // 合并父类和传递进来的参数 Sub.options = mergeOptions( Super.options, extendOptions ) // 子类中存储父类 Sub['super'] = Super // 如果子类中有props 进行初始化 if (Sub.options.props) { initProps(Sub) } // 如果子类中有计算属性,进行初始化 if (Sub.options.computed) { initComputed(Sub) } // 把父类的extend,mixin,use放在子类上 Sub.extend = Super.extend Sub.mixin = Super.mixin Sub.use = Super.use // 把指定的属性全部从父类上拷贝到子类上 ASSET_TYPES.forEach(function (type) { Sub[type] = Super[type] }) if (name) { Sub.options.components[name] = Sub } Sub.superOptions = Super.options Sub.extendOptions = extendOptions Sub.sealedOptions = extend({}, Sub.options) // cache constructor // 缓存子类 cachedCtors[SuperId] = Sub return Sub } } // 把子类中的props存储到原型上 function initProps (Comp) { const props = Comp.options.props for (const key in props) { proxy(Comp.prototype, `_props`, key) } } // 把子类中的计算属性存储到原型上 function initComputed (Comp) { const computed = Comp.options.computed for (const key in computed) { defineComputed(Comp.prototype, key, computed[key]) } }extend方法内部其实就是创建一个子类,通过原型继承的方式继承父类,然后把父类的属性和一些方法存储到子类上,并且把子类进行缓存,再一开始就先从缓存中获取子类,如果没有就进行属性和方法的继承,最后返回子类;
Vue.nextTick,Vue.set,Vue.delete
以上三种都在实例方法中解析过
Vue.directive、Vue.filter、Vue.component
基本使用
注册或获取全局指令
// 注册 Vue.directive('my-directive', { bind: function () {}, inserted: function () {}, update: function () {}, componentUpdated: function () {}, unbind: function () {} }) // 注册 (指令函数) Vue.directive('my-directive', function () { // 这里将会被 `bind` 和 `update` 调用 }) // getter,返回已注册的指令 var myDirective = Vue.directive('my-directive')注册或获取过滤器
// 注册 Vue.filter('my-filter',function(){}) // 获取 Vue.filter('my-filter')注册或获取组件
// 注册 传入一个扩展过的构造器 Vue.component('my-component', Vue.extend({})) // 注册 传入一个选项对象 Vue.component('my-component', {}) // 获取 Vue.component('my-component')源码分析
// 源码位置 src/core/global-api/ export const ASSET_TYPES = [ 'component', 'directive', 'filter' ] export function initAssetRegisters (Vue: GlobalAPI) { /** * Create asset registration methods. */ ASSET_TYPES.forEach(type => { Vue[type] = function ( id: string, definition: Function | Object ): Function | Object | void { // 不存在definition 表示获取,直接从options下的相应的typs+'s'进行获取 if (!definition) { return this.options[type + 's'][id] } else { /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && type === 'component') { validateComponentName(id) } // 如果是组件 并且definition为一个{}对象,那么就通过extend继承vue if (type === 'component' && isPlainObject(definition)) { // 没有name就使用id definition.name = definition.name || id // 使definition继承vue definition = this.options._base.extend(definition) } // 如果是指令并且definition是一个函数,那么就把这个函数作为bind和update if (type === 'directive' && typeof definition === 'function') { definition = { bind: definition, update: definition } } // 设置值 保存到对应的key下 this.options[type + 's'][id] = definition return definition } } }) }指令,过滤器,组件把它们放在一个数组中,遍历这个数组,分别进行处理
export const ASSET_TYPES = [ 'component', 'directive', 'filter' ] ASSET_TYPES.forEach(type => { Vue[type] = function ( id: string, definition: Function | Object ){} })如果没有传递第二个参数,表示是获取,直接进行获取返回
if (!definition) { return this.options[type + 's'][id] }否则就是传递了第二个参数,表示是注册,首先判断是否是组件,是组件并且第二个参数是对象,那么就继承Vue;
// 如果是组件 if (type === 'component' && isPlainObject(definition)) { // 没有name就使用id definition.name = definition.name || id // 使definition继承vue 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
通过以上三种方法就可以自定义组件,过滤器和指令,然后就可以在模板中使用它们,最终的处理还是在模板编译节点进行的;
Vue.use
基本使用
/* 作用: 安装 Vue.js 插件。如果插件是一个对象,必须提供 `install` 方法。 如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。 该方法需要在调用 `new Vue()` 之前被调用。 当 install 方法被同一个插件多次调用,插件将只会被安装一次 plugin:- `{Object | Function} plugin` */ Vue.use( plugin )源码预览
// 源码位置 src/core/global-api/use.js export function initUse (Vue: GlobalAPI) { Vue.use = function (plugin: Function | Object) { // 初始_installedPlugins变量 const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) // 如果已经存在直接返回 if (installedPlugins.indexOf(plugin) > -1) { return this } // 获取剩余的参数转成数组 const args = toArray(arguments, 1) // 把this添加进去 args.unshift(this) // 如果install是一个函数 直接执行 if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args) } else if (typeof plugin === 'function') { // 如果插件是一个函数,直接执行 plugin.apply(null, args) } // 添加到数组中 installedPlugins.push(plugin) return this } }首先获取到用来缓存的属性,如果不存在初始化为一个数组,再判断传递进来的插件是否已经存在,存在表示重复操作,直接返回;(实现:当 install 方法被同一个插件多次调用,插件将只会被安装一次)
// 初始_installedPlugins变量 const installedPlugins = (this._installedPlugins || (this._installedPlugins = [])) // 如果已经存在直接返回 if (installedPlugins.indexOf(plugin) > -1) { return this }接着获取到剩余的参数,并且把当前实例也作为参数(实现:install 方法调用时,会将 Vue 作为参数传入。)
// 获取剩余的参数转成数组 const args = toArray(arguments, 1) // 把this添加进去 args.unshift(this)
判断plugin.install是否是一个函数,如果是函数就通过plugin执行(实现:如果插件是一个对象,必须提供 install 方法)
// 如果install是一个函数 直接执行 if (typeof plugin.install === 'function') { plugin.install.apply(plugin, args) }否则plugin是一个函数,那么直接执行(实现:如果插件是一个函数,它会被作为 install 方法)
else if (typeof plugin === 'function') { // 如果插件是一个函数,直接执行 plugin.apply(null, args) }最后添加到缓存中并返回
// 添加到数组中 installedPlugins.push(plugin) return this
Vue.mixin
基本使用
/* 作用: 全局注册一个混入,影响注册之后所有创建的每个vue实例,插件作者可以使用混入, 向组件注入自定义的行为。**不推荐在应用代码中使用
相关内容
- Ajv format校验使用示例分析_javascript技巧_
- 详解如何用JavaScript编写一个单元测试_javascript技巧_
- 小程序开发实战指南之封装自定义弹窗组件_javascript技巧_
- react component function组件使用详解_React_
- Vue 基础语法之计算属性(computed)、侦听器(watch)、过滤器(filters)详解_vue.js_
- vue选项卡Tabs组件实现示例详解_vue.js_
- vue 过滤、模糊查询及计算属性 computed详解_vue.js_
- 详解vue 祖先组件操作后代组件方法_vue.js_
- Vue2 Observer实例dep和闭包中dep区别详解_vue.js_
- Vue privide 和inject 依赖注入的使用详解_vue.js_
点击排行
本栏推荐
