说说你对vue的mixin的理解,有什么应用场景?
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
一、mixin是什么
Mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类
Mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂
Vue中的mixin
先来看一下官方定义
mixin(混入),提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。
本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如data、components、methods、created、computed等等
我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来
在Vue中我们可以局部混入跟全局混入
局部混入
定义一个mixin对象,有组件options的data、methods属性
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
组件通过mixins属性调用mixin对象
Vue.component('componentA',{
mixins: [myMixin]
})
该组件在使用的时候,混合了mixin里面的方法,在自动执行created生命钩子,执行hello方法
全局混入
通过Vue.mixin()进行全局的混入
Vue.mixin({
created: function () {
console.log("全局混入")
}
})
使用全局混入需要特别注意,因为它会影响到每一个组件实例(包括第三方组件)
PS:全局混入常用于插件的编写
注意事项:
当组件存在与mixin对象相同的选项的时候,进行递归合并的时候组件的选项会覆盖mixin的选项
但是如果相同选项为生命周期钩子的时候,会合并成一个数组,先执行mixin的钩子,再执行组件的钩子
二、使用场景
在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立
这时,可以通过Vue的mixin功能将相同或者相似的代码提出来
举个例子
定义一个modal弹窗组件,内部通过isShowing来控制显示
const Modal = {
template: '#modal',
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
}
}
定义一个tooltip提示框,内部通过isShowing来控制显示
const Tooltip = {
template: '#tooltip',
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
}
}
通过观察上面两个组件,发现两者的逻辑是相同,代码控制显示也是相同的,这时候mixin就派上用场了
首先抽出共同代码,编写一个mixin
const toggle = {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
}
}
两个组件在使用上,只需要引入mixin
const Modal = {
template: '#modal',
mixins: [toggle]
};
const Tooltip = {
template: '#tooltip',
mixins: [toggle]
}
通过上面小小的例子,让我们知道了Mixin对于封装一些可复用的功能如此有趣、方便、实用
三、源码分析
首先从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
}
}
主要是调用merOptions方法
源码位置:/src/core/util/options.js
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的几种类型的合并策略
- 替换型
- 合并型
- 队列型
- 叠加型
替换型
替换型合并有props、methods、inject、computed
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
同名的props、methods、inject、computed会被后来者代替
合并型
和并型合并有:data
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
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被合并为一个数组,然后正序遍历一次执行
叠加型
叠加型合并有:component、directives、filters
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
}
叠加型主要是通过原型链进行层层的叠加
小结:
- 替换型策略有
props、methods、inject、computed,就是将新的同名参数替代旧的参数 - 合并型策略是
data, 通过set方法进行合并和重新赋值 - 队列型策略有生命周期函数和
watch,原理是将函数存入一个数组,然后正序遍历依次执行 - 叠加型有
component、directives、filters,通过原型链进行层层的叠加
参考文献
- https://zhuanlan.zhihu.com/p/31018570
- https://juejin.cn/post/6844904015495446536#heading-1
- https://juejin.cn/post/6844903846775357453
- https://vue3js.cn/docs/zh
说说你对vue的mixin的理解,有什么应用场景?的更多相关文章
- vue中mixin的理解与用法
vue中提供了一种混合机制--mixins,用来更高效的实现组件内容的复用.最开始我一度认为这个和组件好像没啥区别..后来发现错了.下面我们来看看mixins和普通情况下引入组件有什么区别? 组件在引 ...
- Vue中mixin的用法
在项目中我们经常会遇到多个组件调用同一个方法的问题,为了避免每次都在.vue文件中定义并调用,我们可采用vue的mixin的用法: 具体使用如下: 我们需要在main.js中引入mixins文件夹下的 ...
- vue中mixins的理解及应用
vue中mixins的理解及应用 vue中提供了一种混合机制--mixins,用来更高效的实现组件内容的复用.最开始我一度认为这个和组件好像没啥区别..后来发现错了.下面我们来看看mixins和普通情 ...
- vue的mixin简化开发
vue的mixin可以将多个组件公用的声明周期方法和数据封装成一个对象,在不同的组件中自由插拔.实际做项目的时候,可以定义一些mixin,供多个组件使用.也非常有必要定义一个全局的mixin对象,对所 ...
- vue 混入 mixin,自定义指令,过滤器
vue 混入 mixin ,分发 vue 组件中重复的功能 局部的书写格式 // mixin.js var mymixin = { // 这是一个对象:对象里面的写法与组件里面的写法一模一样,组件该 ...
- vue中keepalive怎么理解?---vue中文社区
vue中keepalive怎么理解? 说在前面: keep-alive是vue源码中实现的一个组件, 感兴趣的可以研究源码 https://github.com/vuejs/vue/blob/dev/ ...
- Vue中$nextTick的理解
Vue中$nextTick的理解 Vue中$nextTick方法将回调延迟到下次DOM更新循环之后执行,也就是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,能够获取更新后的 ...
- vue渐进式开发的理解和指令
1.vue渐进式开发 vue是一个渐进式的框架,轻量,易于上手,为啥是渐进式那,我当时也很蒙,比如的官网是jquery写的,就可以通过script标签引入事先准备好的vue.min.js的压缩源代码或 ...
- Vue学习之--------深入理解Vuex之多组件共享数据(2022/9/4)
在上篇文章的基础上:Vue学习之--------深入理解Vuex之getters.mapState.mapGetters 1.在state中新增用户数组 2.新增Person.vue组件 提示:这里使 ...
- VUE学习-mixin混入
mixin混入 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能. 组件式混入 // 定义一个混入对象 var myMixin = { created: functi ...
随机推荐
- NC235247 Sramoc问题
题目链接 题目 题目描述 \(Sramoc(K ,M)\) 表示用数字 \(0,1,2,3,4,...,k-1\) 组成的自然数中能被M整除的最小数.给定 \(K,M\) \(2\leq K\leq ...
- NC13885 Music Problem
题目链接 题目 题目描述 Listening to the music is relax, but for obsessive(强迫症), it may be unbearable. HH is an ...
- 【Unity3D】刚体组件Rigidbody
1 前言 刚体(Rigidbody)是运动学(Kinematic)中的一个概念,指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体.在 Unity3D 中,刚体组件赋予了游戏 ...
- gitlab+jenkins+docker持续集成环境搭建实战
介绍 什么是持续集成? 持续集成(CI)是在源代码变更后自动检测.拉取.构建和(在大多数情况下)进行单元测试的过程.持续集成是启动管道的环节(尽管某些预验证 -- 通常称为 上线前检查(pre-fli ...
- form表单如何实现ajax提交
最近在开发一个游戏网关的后台管理系统,总结了下中间碰到的一些问题. 之一就是:form表单如何实现ajax提交? 问题:在使用form表单的时候,一旦点击提交触发submit事件,一般会使得页面跳转, ...
- win32 - 创建子线程中的窗口
跟创建普通的win32窗口一样,线程中的窗口也需要注册和窗口处理过程 // Test_WM_CLOSE.cpp : Defines the entry point for the applicatio ...
- [BUUCTF][WEB][极客大挑战 2019]Knife 1
这题几乎是送分 题目不断暗示,后台存在一句话木马 拿个蚁剑连上去就完事了 这里用curl 连上去,演示一下,理解一下其中的原理 #注意 phpinfo() 后面的分号不能省 curl -d " ...
- 文心一言 VS 讯飞星火 VS chatgpt (202)-- 算法导论15.3 1题
一.对于矩阵链乘法问题,下面两种确定最优代价的方法哪种更高效?第一种方法是穷举所有可能的括号化方案,对每种方案计算乘法运算次数,第二种方法是运行RECURSIVE-MATRIX-CHAIN.证明你的结 ...
- 最新最简单安装龙蜥操作系统centos8
下载 https://openanolis.cn/download 我用的是稳定版本 Anolis OS8.2QU1 安装(vm用的15.5pro) 关键点 进去后,输入命令 ip a // 查看ip ...
- 【Java复健指南11】OOP高级02-代码块、单例设计和final关键字
代码块 定义 代码化块又称为初始化块,属于类中的成员[即是类的一部分]. 类似于方法,将逻辑语句封装在方法体中,通过{}包围起来. 但和方法不同,没有方法名,没有返回,没有参数,只有方法体, 而且不用 ...
