深入浅析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 相关文章推荐
javascript 多级checkbox选择效果
Aug 20 Javascript
jquery.messager.js插件导致页面抖动的解决方法
Jul 14 Javascript
JS delegate与live浅析
Dec 21 Javascript
jQuery中trigger()与bind()用法分析
Dec 18 Javascript
vue脚手架vue-cli的学习使用教程
Jun 06 Javascript
Jquery中.bind()、.live()、.delegate()和.on()之间的区别详解
Aug 01 jQuery
react-native使用react-navigation进行页面跳转导航的示例
Sep 07 Javascript
简述vue中的config配置
Jan 23 Javascript
vue better-scroll插件使用详解
Jan 25 Javascript
关于自定义Egg.js的请求级别日志详解
Dec 12 Javascript
vue中监听返回键问题
Aug 28 Javascript
JavaScript实现雪花飘落效果
Dec 27 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
星际争霸任务指南——虫族
2020/03/04 星际争霸
怎样在php中使用PDF文档功能
2006/10/09 PHP
深入掌握include_once与require_once的区别
2013/06/17 PHP
php利用递归实现删除文件目录的方法
2016/09/23 PHP
浅谈PHP错误类型及屏蔽方法
2017/05/27 PHP
关于laravel 数据库迁移中integer类型是无法指定长度的问题
2019/10/09 PHP
Cookie 注入是怎样产生的
2009/04/08 Javascript
基于jQuery的星级评分插件
2011/08/12 Javascript
jQuery+CSS实现菜单滑动伸展收缩(仿淘宝)
2013/03/22 Javascript
jQuery动画特效实例教程
2014/08/29 Javascript
5种处理js跨域问题方法汇总
2014/12/04 Javascript
jQuery 选择器详解
2015/01/19 Javascript
JavaScript中的slice()方法使用详解
2015/06/06 Javascript
JavaScript数组去重的五种方法
2015/11/05 Javascript
Jquery Easyui进度条组件Progress使用详解(8)
2020/03/26 Javascript
vue动态绑定组件子父组件多表单验证功能的实现代码
2018/05/14 Javascript
video.js 一个页面同时播放多个视频的实例代码
2018/11/27 Javascript
微信小程序实现蒙版弹出窗功能
2019/09/17 Javascript
[57:41]Secret vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
基础的十进制按位运算总结与在Python中的计算示例
2016/06/28 Python
Python错误: SyntaxError: Non-ASCII character解决办法
2017/06/08 Python
python判断字符串是否是json格式方法分享
2017/11/07 Python
[原创]Python入门教程4. 元组基本操作
2018/10/31 Python
Python实现将多个空格换为一个空格.md的方法
2018/12/20 Python
Python通过TensorFlow卷积神经网络实现猫狗识别
2019/03/14 Python
Python如何截图保存的三种方法(小结)
2020/09/01 Python
如何利用python发送邮件
2020/09/26 Python
web字体加载方案优化小结
2019/11/29 HTML / CSS
常见的软件开发流程有哪些
2015/11/14 面试题
C++程序员求职信
2014/05/07 职场文书
离职证明标准格式
2014/09/15 职场文书
民主生活会批评与自我批评总结
2014/10/17 职场文书
2015年保管员工作总结
2015/04/30 职场文书
python实现监听键盘
2021/04/26 Python
Windows11插耳机没反应怎么办? win11耳机没声音的多种解决办法
2021/11/21 数码科技
nginx容器方式反向代理实战
2022/04/18 Servers