深入浅析Vue中mixin和extend的区别和使用场景


Posted in Javascript onAugust 01, 2019

Vue中有两个较为高级的静态方法mixin和extend,接下来我们来讨论下关于他们各自的原理和使用场景。

Mixin:

原理:

先来看看官网的介绍:

参数:{Object} mixin

用法:

混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。

// 为自定义的选项 'myOption' 注入一个处理器。
   Vue.mixin({
    created: function () {
     var myOption = this.$options.myOption
     if (myOption) {
      console.log(myOption)
     }
    }
   })
   
   new Vue({
    myOption: 'hello!'
   })
   // => "hello!"

我们知道,Vue.mixin传递的这个参数对象,在初始化Vue实例的时候会merge到options上,下面是Vue源码中对mixin的操作。

// src\core\global-api\mixin.js
 export function initMixin (Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
   this.options = mergeOptions(this.options, mixin)
   return this
  }
 }
// src\core\instance\index.js
 function Vue (options) {
   if (process.env.NODE_ENV !== 'production' &&
   !(this instanceof Vue)
   ) {
   warn('Vue is a constructor and should be called with the `new` keyword')
   }
   this._init(options)
 }
 
 initMixin(Vue)
 ...
 
 export default Vue

也就是说,mixin只是对我们在初始化Vue实例时传递的配置对象的一个扩展。

就像上面官网实例写的例子,我们在执行Vue.mixin方法时传递一个配置对象进去,对象里面有个created勾子函数,通过源码我们可以看到这个传递进来的对象最终会和我们在初始化实例也就是new Vue(options)时的这个options合并(通过上面源码中的mergeOptions方法),保存在option上。

使用场景:

当我们需要全局去注入一些methods,filter或者hooks时我们就可以使用mixin来做。 比如我们希望每一个Vue实例都有一个print方法,我们就可以这么做:

Vue.mixin({
    methods: {
      print() {
        console.log(`我是一个通过mixin注入的方法!`)
      }
    }
  })

或者我们想要去监听在什么阶段时什么组件被加载了,被卸载了等等,我们可以这么做:

Vue.mixin({
    mounted() {
      console.log(`${this.$route.name} component mounted!`)
    },
    destroyed() {
      console.log(`${this.$route.name} component destroyed!`)
    }
  })

如果我们并不想给每一个组件实例都混入这些配置options,而只是个别的组件,最好不要使用mixin,它可能会影响到我们组件的性能。

Extend:

原理:

先来看看官网的介绍:

参数:{Object} options

用法:

使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数。

data必须是函数是为了防止各个实例的数据混乱,闭包的应用。

<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
 template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
 data: function () {
  return {
   firstName: 'Walter',
   lastName: 'White',
   alias: 'Heisenberg'
  }
 }
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')

再来看看源码里面关于Vue.extend的实现:

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]
  }

  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

  // For props and computed properties, we define the proxy getters on
  // the Vue instances at extension time, on the extended prototype. This
  // avoids Object.defineProperty calls for each instance created.
  if (Sub.options.props) {
   initProps(Sub)
  }
  if (Sub.options.computed) {
   initComputed(Sub)
  }

  // allow further extension/mixin/plugin usage
  Sub.extend = Super.extend
  Sub.mixin = Super.mixin
  Sub.use = Super.use

  // create asset registers, so extended classes
  // can have their private assets too.
  ASSET_TYPES.forEach(function (type) {
   Sub[type] = Super[type]
  })
  // enable recursive self-lookup
  if (name) {
   Sub.options.components[name] = Sub
  }

  // keep a reference to the super options at extension time.
  // later at instantiation we can check if Super's options have
  // been updated.
  Sub.superOptions = Super.options
  Sub.extendOptions = extendOptions
  Sub.sealedOptions = extend({}, Sub.options)

  // cache constructor
  cachedCtors[SuperId] = Sub
  return Sub
 }
}

首先我们可以看到,extend方法返回的Sub其实是一个构造函数,而且继承自Vue,也就是说extend方法返回的是Vue的一个子类。

Sub.prototype = Object.create(Super.prototype)
  Sub.prototype.constructor = Sub

这两行代码其实就是实现Sub对Vue的继承,源码中有一行是

const Super = this

所以这里的Super指的就是Vue。

Sub.options = mergeOptions(
   Super.options,
   extendOptions
)

我们注意到在extend中也会对传进来的配置option和Vue原来的options做一个合并。

使用场景:

当我们不需要全局去混入一些配置,比如,我们想要获得一个component。我们可以使用Vue.component(),也可以使用Vue.extend()。

const ChildVue = Vue.extend({
  ...options
})

new ChildVue({
  ...options
})

注意extend得到的是一个Vue的子类,也就是构造函数。

区别:

mixin是对Vue类的options进行混入。所有Vue的实例对象都会具备混入进来的配置行为。

extend是产生一个继承自Vue类的子类,只会影响这个子类的实例对象,不会对Vue类本身以及Vue类的实例对象产生影响。

总结

以上所述是小编给大家介绍的Vue中mixin和extend的区别和使用场景,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
jQuery '行 4954 错误: 不支持该属性或方法' 的问题解决方法
Jan 19 Javascript
js不能跳转到上一页面的问题解决方法
Mar 01 Javascript
Jquery attr(&quot;checked&quot;) 返回checked或undefined 获取选中失效
Oct 10 Javascript
JavaScript如何实现跨域请求
Aug 05 Javascript
jQuery购物网页经典制作案例
Aug 19 Javascript
vue.js入门教程之绑定class和style样式
Sep 02 Javascript
使用JQuery中的trim()方法去掉前后空格
Sep 16 Javascript
Webpack 服务器端代码打包的示例代码
Sep 19 Javascript
AngularJs ng-change事件/指令的用法小结
Nov 01 Javascript
详解node child_process模块学习笔记
Jan 24 Javascript
vue项目创建并引入饿了么elementUI组件的步骤
Apr 11 Javascript
Vue 列表页带参数进详情页的操作(router-link)
Nov 13 Javascript
在Vue环境下利用worker运行interval计时器的步骤
Aug 01 #Javascript
详解Vue2.5+迁移至Typescript指南
Aug 01 #Javascript
微信小程序组件传值图示过程详解
Jul 31 #Javascript
vue.js实现回到顶部动画效果
Jul 31 #Javascript
vue实现滑动超出指定距离回顶部功能
Jul 31 #Javascript
Vue实现回到顶部和底部动画效果
Jul 31 #Javascript
详解mpvue实现对苹果X安全区域的适配
Jul 31 #Javascript
You might like
在PHP中使用Sockets 从Usenet中获取文件
2008/01/10 PHP
php获取URL中带#号等特殊符号参数的解决方法
2014/09/02 PHP
Zend Framework教程之Loader以及PluginLoader用法详解
2016/03/09 PHP
PHP+AJAX 投票器功能
2017/11/11 PHP
用js判断用户浏览器是否是XP SP2的IE6
2007/03/08 Javascript
js+css使DIV始终居于屏幕中间 左下 左上 右上 右下的代码集合
2011/03/10 Javascript
深入document.write()与HTML4.01的非成对标签的详解
2013/05/08 Javascript
Javascript获取HTML静态页面参数传递值示例
2013/08/18 Javascript
jQuery提示插件alertify使用指南
2015/04/21 Javascript
jQuery实现文本展开收缩特效
2015/06/03 Javascript
js编写贪吃蛇的小游戏
2020/08/24 Javascript
Javascript实现图片懒加载插件的方法
2016/10/20 Javascript
JavaScript 异步调用
2017/10/25 Javascript
解决angularjs中同步执行http请求的方法
2018/08/13 Javascript
webpack优化的深入理解
2018/12/10 Javascript
浅谈对于“不用setInterval,用setTimeout”的理解
2019/08/28 Javascript
layui原生表单验证的实例
2019/09/09 Javascript
基于Ionic3实现选项卡切换并重新加载echarts
2020/09/24 Javascript
详解Python程序与服务器连接的WSGI接口
2015/04/29 Python
Python实现将MySQL数据库表中的数据导出生成csv格式文件的方法
2018/01/11 Python
python list是否包含另一个list所有元素的实例
2018/05/04 Python
Python程序包的构建和发布过程示例详解
2019/06/09 Python
利用Python函数实现一个万历表完整示例
2021/01/23 Python
使用python对excel表格处理的一些小功能
2021/01/25 Python
意大利高端时尚买手店:Stefania Mode
2018/03/01 全球购物
如何从一个文件档案的尾端新增记录
2016/12/02 面试题
关于毕业的广播稿
2014/01/10 职场文书
教师爱岗敬业演讲稿
2014/05/05 职场文书
工程承诺书怎么写
2014/05/24 职场文书
护理目标管理责任书
2014/07/25 职场文书
社区党建工作汇报材料
2014/10/27 职场文书
《窃读记》教学反思
2016/02/18 职场文书
《藏戏》教学反思
2016/02/23 职场文书
导游词之神仙居景区
2019/11/15 职场文书
python编写函数注意事项总结
2021/03/29 Python
vue实现简易音乐播放器
2022/08/14 Vue.js