Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >面试官:说说你对vue的mixin的理解,有哪些应用场景?

面试官:说说你对vue的mixin的理解,有哪些应用场景?

作者头像
@超人
发布于 2021-02-26 08:12:31
发布于 2021-02-26 08:12:31
1.9K00
代码可运行
举报
文章被收录于专栏:Vue中文社区Vue中文社区
运行总次数:0
代码可运行

一、mixin是什么

Mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类

Mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂

Vue中的mixin

先来看一下官方定义

mixin(混入),提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。

本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如datacomponentsmethodscreatedcomputed等等

我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来

Vue中我们可以局部混入全局混入

局部混入

定义一个mixin对象,有组件optionsdatamethods属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

组件通过mixins属性调用mixin对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Vue.component('componentA',{
  mixins: [myMixin]
})

该组件在使用的时候,混合了mixin里面的方法,在自动执行create生命钩子,执行hello方法

全局混入

通过Vue.mixin()进行全局的混入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Vue.mixin({
  created: function () {
      console.log("全局混入")
    }
})

使用全局混入需要特别注意,因为它会影响到每一个组件实例(包括第三方组件)

PS:全局混入常用于插件的编写

注意事项:

当组件存在与mixin对象相同的选项的时候,进行递归合并的时候组件的选项会覆盖mixin的选项

但是如果相同选项为生命周期钩子的时候,会合并成一个数组,先执行mixin的钩子,再执行组件的钩子

二、使用场景

在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立

这时,可以通过Vuemixin功能将相同或者相似的代码提出来

举个例子

定义一个modal弹窗组件,内部通过isShowing来控制显示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const Modal = {
  template: '#modal',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

定义一个tooltip提示框,内部通过isShowing来控制显示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const Tooltip = {
  template: '#tooltip',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

通过观察上面两个组件,发现两者的逻辑是相同,代码控制显示也是相同的,这时候mixin就派上用场了

首先抽出共同代码,编写一个mixin

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const toggle = {
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

两个组件在使用上,只需要引入mixin

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const Modal = {
  template: '#modal',
  mixins: [toggle]
};
 
const Tooltip = {
  template: '#tooltip',
  mixins: [toggle]
}

通过上面小小的例子,让我们知道了Mixin对于封装一些可复用的功能如此有趣、方便、实用

三、源码分析

首先从Vue.mixin入手

源码位置:/src/core/global-api/mixin.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export function initMixin (Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }
}

主要是调用merOptions方法

源码位置:/src/core/util/options.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {

if (child.mixins) { // 判断有没有mixin 也就是mixin里面挂mixin的情况 有的话递归进行合并
    for (let i = 0, l = child.mixins.length; i < l; i++) {
    parent = mergeOptions(parent, child.mixins[i], vm)
    }
}

  const options = {} 
  let key
  for (key in parent) {
    mergeField(key) // 先遍历parent的key 调对应的strats[XXX]方法进行合并
  }
  for (key in child) {
    if (!hasOwn(parent, key)) { // 如果parent已经处理过某个key 就不处理了
      mergeField(key) // 处理child中的key 也就parent中没有处理过的key
    }
  }
  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key) // 根据不同类型的options调用strats中不同的方法进行合并
  }
  return options
}

从上面的源码,我们得到以下几点:

  • 优先递归处理 mixins
  • 先遍历合并parent 中的key,调用mergeField方法进行合并,然后保存在变量options
  • 再遍历 child,合并补上 parent 中没有的key,调用mergeField方法进行合并,保存在变量options
  • 通过 mergeField 函数进行了合并

下面是关于Vue的几种类型的合并策略

  • 替换型
  • 合并型
  • 队列型
  • 叠加型

替换型

替换型合并有propsmethodsinjectcomputed

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
strats.props =
strats.methods =
strats.inject =
strats.computed = function (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {
  if (!parentVal) return childVal // 如果parentVal没有值,直接返回childVal
  const ret = Object.create(null) // 创建一个第三方对象 ret
  extend(ret, parentVal) // extend方法实际是把parentVal的属性复制到ret中
  if (childVal) extend(ret, childVal) // 把childVal的属性复制到ret中
  return ret
}
strats.provide = mergeDataOrFn

同名的propsmethodsinjectcomputed会被后来者代替

合并型

和并型合并有:data

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
strats.data = function(parentVal, childVal, vm) {    
    return mergeDataOrFn(
        parentVal, childVal, vm
    )
};

function mergeDataOrFn(parentVal, childVal, vm) {    
    return function mergedInstanceDataFn() {        
        var childData = childVal.call(vm, vm) // 执行data挂的函数得到对象
        var parentData = parentVal.call(vm, vm)        
        if (childData) {            
            return mergeData(childData, parentData) // 将2个对象进行合并                                 
        } else {            
            return parentData // 如果没有childData 直接返回parentData
        }
    }
}

function mergeData(to, from) {    
    if (!from) return to    
    var key, toVal, fromVal;    
    var keys = Object.keys(from);   
    for (var i = 0; i < keys.length; i++) {
        key = keys[i];
        toVal = to[key];
        fromVal = from[key];    
        // 如果不存在这个属性,就重新设置
        if (!to.hasOwnProperty(key)) {
            set(to, key, fromVal);
        }      
        // 存在相同属性,合并对象
        else if (typeof toVal =="object" && typeof fromVal =="object") {
            mergeData(toVal, fromVal);
        }
    }    
    return to
}

mergeData函数遍历了要合并的 data 的所有属性,然后根据不同情况进行合并:

  • 当目标 data 对象不包含当前属性时,调用 set 方法进行合并(set方法其实就是一些合并重新赋值的方法)
  • 当目标 data 对象包含当前属性并且当前值为纯对象时,递归合并当前对象值,这样做是为了防止对象存在新增属性

队列型

队列型合并有:全部生命周期和watch

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function mergeHook (
  parentVal: ?Array<Function>,
  childVal: ?Function | ?Array<Function>
): ?Array<Function> {
  return childVal
    ? parentVal
      ? parentVal.concat(childVal)
      : Array.isArray(childVal)
        ? childVal
        : [childVal]
    : parentVal
}

LIFECYCLE_HOOKS.forEach(hook => {
  strats[hook] = mergeHook
})

// watch
strats.watch = function (
  parentVal,
  childVal,
  vm,
  key
) {
  // work around Firefox's Object.prototype.watch...
  if (parentVal === nativeWatch) { parentVal = undefined; }
  if (childVal === nativeWatch) { childVal = undefined; }
  /* istanbul ignore if */
  if (!childVal) { return Object.create(parentVal || null) }
  {
    assertObjectType(key, childVal, vm);
  }
  if (!parentVal) { return childVal }
  var ret = {};
  extend(ret, parentVal);
  for (var key$1 in childVal) {
    var parent = ret[key$1];
    var child = childVal[key$1];
    if (parent && !Array.isArray(parent)) {
      parent = [parent];
    }
    ret[key$1] = parent
      ? parent.concat(child)
      : Array.isArray(child) ? child : [child];
  }
  return ret
};

生命周期钩子和watch被合并为一个数组,然后正序遍历一次执行

叠加型

叠加型合并有:componentdirectivesfilters

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
strats.components=
strats.directives=

strats.filters = function mergeAssets(
    parentVal, childVal, vm, key
) {    
    var res = Object.create(parentVal || null);    
    if (childVal) { 
        for (var key in childVal) {
            res[key] = childVal[key];
        }   
    } 
    return res
}

叠加型主要是通过原型链进行层层的叠加

小结:

  • 替换型策略有propsmethodsinjectcomputed,就是将新的同名参数替代旧的参数
  • 合并型策略是data, 通过set方法进行合并和重新赋值
  • 队列型策略有生命周期函数和watch,原理是将函数存入一个数组,然后正序遍历依次执行
  • 叠加型有componentdirectivesfilters,通过原型链进行层层的叠加

参考文献

  • https://zhuanlan.zhihu.com/p/31018570
  • https://juejin.cn/post/6844904015495446536#heading-1
  • https://juejin.cn/post/6844903846775357453
  • https://vue3js.cn/docs/zh

面试官VUE系列总进度:14/33

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Vue中文社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Vue原理】Mixins - 源码版
今天探索的是 mixins 的源码,mixins 根据不同的选项类型会做不同的处理
神仙朱
2019/08/02
7130
【Vue原理】Mixins - 源码版
Vue 合并策略 optionMergeStrategies 看这里就够了
文章篇幅较长, 建议花整块时间阅读分析。 另外由于篇幅过长, 本文分三篇文章产出, 便于大家理解与阅读。
winty
2021/05/18
1.2K0
Vue——mergeOptions【四】
前面我们简单的了解了 vue 初始化时的一些大概的流程,这里我们详细的了解下具体的内容; 这块建议搭建可以根据 demo 进行 debugger 来观察;
思索
2024/08/15
970
【Vuejs】887- 深入浅出 Vue Mixin
https://flyyang.me/2019/01/24/vue-mixin/
pingan8787
2021/03/16
4530
【Vuejs】887- 深入浅出 Vue Mixin
vue mixins原理
以前一直以为mixins在vue里面应该不是很重要,只是提供了一个混入的api,慢慢的才知道mixin在vue里面非常重要。生命周期、vuex等都有mixin的影子,在内部算是很重要的一个api。
wade
2020/09/14
4990
Vue 高频原理面试篇+详细解答
原文首地址 掘金 三连哦 更多好文 github 大家好,我是林一一,这是一篇关于 vue 的原理面试题,如果能够完全弄懂相信对大家很有帮助。 面试题篇 1.老生常谈之, MPA/SPA 的理解,优缺点是什么? MPA 多页面应用。 构成:有多个页面 html 构成, 跳转方式:页面的跳转是从一个页面到另一个页面 刷新的方式:全页面刷新 页面数据跳转:依赖 URL/cookie/localStorage 跳转后的资源 会重新加载 优点:对 SEO 比较友好,开发难度低一点。 SPA单页面应用 页面组成:
前端小tips
2021/12/09
7170
Vue 高频原理面试篇+详细解答
Vue 组件扩展
最近,新项目架构搭建在扩展组件的场景中:图表使用了extends方式,而公共业务server和view之间使用了mixins方式。对于二者的选择,我们通常会解释为extends的优先级高于mixins,但其真实的差异是由于其合并策略不同或者说在合并策略中执行的顺序不同导致的 – 源码
奋飛
2019/08/14
1.3K0
小白也能秒懂Vue源码中那些精细设计(选项处理)
我"崩"不住了,在彭凡同志锲而不舍的催促下这篇文章终于"蛋"生了。说正经的这篇文章不好写,不好写的原因是我不太擅长写这些类比文,但它还是写出来了。相信大部分人都有开发过功能插件,在写插件的时候普遍应用基本思想是以"默认配置为优先,以用户配置为覆盖"。如果你觉得简单先别着急穿裤子走人继续往下看看。
iOSSir
2020/07/24
9780
小白也能秒懂Vue源码中那些精细设计(选项处理)
Vue 之 Mixins的使用
同名钩子函数将会混合为一个数组,都将被调用到,但是混入对象的钩子将在组件自身钩子之前调用。
愤怒的小鸟
2021/02/01
5300
vue核心面试题:组件中的data为什么是一个函数
2.vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,就需要通过data函数返回一个对象作为组件的状态。
青梅煮码
2023/02/18
5940
前端VUE【实战】—— mixin混入用法总结
单纯组件引用: 父组件 + 子组件 >>> 父组件 + 子组件 mixins: 父组件 + 子组件 >>> new父组件
江一铭
2022/06/17
9150
前端VUE【实战】—— mixin混入用法总结
初探Vue的Mixin混入
在停更了近一周之后(假期已完美结束),胡哥又开启了文章的每日更新,与大家一起分享、讨论大前端的技术原理与项目实践。抽丝剥茧,让技术方案可见可闻;归纳整理,让知识体系成长可依。欢迎更多的小伙伴关注、分享《胡哥有话说》公众号,让胡哥与你一起:流年笑掷,未来可期。
胡哥有话说
2019/07/25
1.5K0
vue源码分析-从new Vue开始
那你觉得是不是很有意思,咱们new Vue之后,就可以使用他那么多的功能,可见Vue是暴出来的一个一个功能类函数,我们进入源码一探究竟:
yyzzabc123
2022/10/19
6090
前端vue面试题集锦1
官方解释:Vue.extend 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
bb_xiaxia1998
2022/12/19
6150
面试官:为什么data属性是一个函数而不是一个对象?
在我们定义好一个组件的时候,vue最终都会通过Vue.extend()构成组件实例
@超人
2021/02/26
3.5K0
面试官:为什么data属性是一个函数而不是一个对象?
Vue 3 mixins 混入
其实混入理解很简单,就是提取公用的部分,将这部分进行公用,这是一种很灵活的方式,来提供给 Vue 组件复用功能,一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
公众号---人生代码
2020/11/03
2K0
Vue 3 mixins 混入
vue的混入mixins
1、在您的 Vue 应用程序内部,我们将创建一个名为 mixins 的文件夹,并且新建文件命名为 nomeMixins.js
leader755
2022/03/09
3380
前端一面经典vue面试题(持续更新中)
只需要在组件即将被销毁的生命周期 componentWillUnmount (react)中在 LocalStorage / SessionStorage 中把当前组件的 state 通过 JSON.stringify() 储存下来就可以了。在这里面需要注意的是组件更新状态的时机。
bb_xiaxia1998
2022/12/07
9980
你不知道的React 和 Vue 的20个区别【源码层面】
面试竞争力越来越大,是时候撸一波Vue和React源码啦; 本文从20个层面来对比Vue和React的源码区别; 文章源码:请戳,原创码字不易,欢迎star!
火狼1
2020/07/08
1.6K0
你不知道的React 和 Vue 的20个区别【源码层面】
vue源码分析-动态组件
动态组件我相信大部分在开发的过程中都会用到,当我们需要在不同的组件之间进行状态切换时,动态组件可以很好的满足我们的需求,其中的核心是component标签和is属性的使用。
yyzzabc123
2022/10/19
9070
相关推荐
【Vue原理】Mixins - 源码版
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验