mixin机制 vue_Vue的mixin机制及mergeOptions解析-程序员宅基地

技术标签: mixin机制 vue  

前言

Mixin 也就是混入的意思,就是说通过某种方式将一个对象的一些属性,混入到目标对象身上。对于我个人来说,其实并不太喜欢 Mixin 这是方式的,因为它对开发者来说是透明的,我们不知道什么时候同事去绑定了一个全局的 Mixin,当然用的好那肯定是不方便的,也无奈 Vue 的 Mixin 机制那么强大,所以就驱使我来深入了解它。

start

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

}

}

Vue.mixin方法也非常的简练,内部也是直接调用了 mergeOptions 方法,从方法名字上可以看出合并Options就大概知道是什么意思了。我们来看一下 mergeOptions 方法是怎么实现的,先贴一下代码。

export function mergeOptions(

parent: Object,

child: Object,

vm?: Component

): Object {

if (process.env.NODE_ENV !== 'production') {

checkComponents(child)

}

if (typeof child === 'function') {

child = child.options

}

// 规范化

normalizeProps(child, vm)

normalizeInject(child, vm)

normalizeDirectives(child)

if (!child._base) {

if (child.extends) {

parent = mergeOptions(parent, child.extends, vm)

}

if (child.mixins) {

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)

}

for (key in child) {

if (!hasOwn(parent, key)) {

mergeField(key)

}

}

function mergeField(key) {

const strat = strats[key] || defaultStrat

options[key] = strat(parent[key], child[key], vm, key)

}

return options

}

首先我们看到 mergeOptions 函数传过来的前两个参数为parent和child,通过 mixin 里面的调用,我们可以知道要把child上的属性 merge 到parent上

if (process.env.NODE_ENV !== 'production') {

checkComponents(child)

}

首先在开发环境的时候会先检查一下 child 中的 components 属性,我们都知道这里是组件装载的地方,这里要检测一下命名是否正确。

child 也可以是一个方法,如果是一个方法,那么就可以认为这是一个组件,重新赋值 child 为 child.options,下面是源码。

if (typeof child === 'function') {

child = child.options

}

接下来这段代码用于规范化 Props、Inject 已经 Directives。

normalizeProps(child, vm)

normalizeInject(child, vm)

normalizeDirectives(child)

我们都知道这三个东西在开发过程中有多种形式存在,就拿最常用的 Props 来说,props 可以是对象也可以是数组,例如:

//数组方式

props: ['type','data', 'info']

// 对象的方式

props: {

type: {

type: String,

default: ''

},

data: {

type: Array,

default: () =>[]

},

info: {

type: Object,

default: () => ({})

}

}

可见 Vue 提供了 props 的两种写法,便于我们在开发过程中写代码,但是在 Vue 内部必然要使用一种统一的方式去处理,要不然太浪费精力去处理另外一种情况,也让代码不具有可扩展性,所以就出现对这个多方式的配置有了规范化的处理。

就拿 props 的规范化来说吧

function normalizeProps(options: Object, vm: ?Component) {

const props = options.props

if (!props) return

const res = {}

let i, val, name

if (Array.isArray(props)) {

i = props.length

while (i--) {

val = props[i]

if (typeof val === 'string') {

name = camelize(val)

res[name] = { type: null }

} else if (process.env.NODE_ENV !== 'production') {

warn('props must be strings when using array syntax.')

}

}

} else if (isPlainObject(props)) {

for (const key in props) {

val = props[key]

name = camelize(key)

res[name] = isPlainObject(val) ? val : { type: val }

}

} else if (process.env.NODE_ENV !== 'production') {

warn(

`Invalid value for option "props": expected an Array or an Object,` +

`but got${toRawType(props)}.`,

vm

)

}

options.props = res

}

这里把 props 规范化都转化成了对象的方式,其它两个也是类似的操作。

接下来的逻辑就是合并了。

if (!child._base) {

if (child.extends) {

parent = mergeOptions(parent, child.extends, vm)

}

if (child.mixins) {

for (let i = 0, l = child.mixins.length; i < l; i++) {

parent = mergeOptions(parent, child.mixins[i], vm)

}

}

}

首先判断 child 是否被合并过,只有合并过之后才有_base这个属性,然后判断 child 是否有 extends 和 mixins 属性,有的话就再次调用 mergeOptions 将它们合并到 parent 上。

最后就是这部分合并逻辑

const options = {}

let key

for (key in parent) {

mergeField(key)

}

for (key in child) {

if (!hasOwn(parent, key)) {

mergeField(key)

}

}

function mergeField(key) {

const strat = strats[key] || defaultStrat

options[key] = strat(parent[key], child[key], vm, key)

}

对于 parent 和 child 都调用了 mergeField 函数用来合并,而 mergeField 中获取了 start 函数,看一下这个是干嘛的。

const defaultStrat = function (parentVal: any, childVal: any): any {

return childVal === undefined ? parentVal : childVal

}

defaultStart 只是一个简单的选取函数,判断如果 childVal 不存在,就返回 parentVal,存在就返回 childVal,结合上面逻辑,你可能会想,child 这不就覆盖 parent 上的属性了吗?

在上面还有这段逻辑

for (key in child) {

if (!hasOwn(parent, key)) {

mergeField(key)

}

}

在遍历 key 的时候如果 child 的 key 在 parent 存在的话就会忽略。

上面说了defaultStart这个取值函数,对于 start 还有一个判断的逻辑

const strat = strats[key] || defaultStrat

这里做的是它会根据一些特定的 key 来使用一些特定的函数去处理,例如:data,生命周期,特定的component,directive,filter,watch,props,provide,methods,inject,computed`等等

简单看了一下,这些也比较容易理解,先分析这么多。

end

本来想看 Vue 的 Mixin 的原理,实则是看的 mergeOptions 的原理,结果一发不可收拾。starts 这个东西还是做的蛮全面的,把特殊的属性都使用特定的方法来处理,受益无穷。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39736047/article/details/112837942

智能推荐

VScode配置python环境_vscode写python还是ij-程序员宅基地

文章浏览阅读215次。VScode配置python环境1. 安装python扩展直接安装python扩展即可2. 配置vscodecrtl+shift+P调出命令面板,设置python解释器然后创建launch.json,然后选择python file即可然后就能正确调试了ipynb也能正常跑了,太棒了????..._vscode写python还是ij

Mac使用Microsoft-Remote-Desktop-for-Mac远程桌面Windows_remote-desktop-mac-程序员宅基地

文章浏览阅读5.8w次,点赞19次,收藏87次。假如你有两台电脑甚至更多电脑用来工作、学习,当你从一台电脑换到另一台电脑上的时候,你需要移开当前视线,当前键盘、鼠标,甚至是换个椅子等,这样的操作来切换工作,这样来来回回非常的麻烦。所以就有两台以及多台电脑共享一套键盘鼠标的操作,切换的时候,你只需要眼睛看向另一屏幕即可,继续在当前鼠标、键盘上操作。然而,现在你连视线也懒得移动,但同时也要满足你在当前屏幕使用另一电脑的操作,此时远程桌面就可以派上..._remote-desktop-mac

计算机硬盘分区win7,小编教你win7硬盘如何分区-程序员宅基地

文章浏览阅读1k次。硬盘是由外覆盖铁磁性材料铝制或者玻璃制的碟片组成,是电脑中主要的存储媒介之一。我们也会将成几个磁盘分类保存文件。下面,我就教大家如何在win7系统下给硬盘分区。win7系统是具有革命性变化的操作系统,界面美观,简单快速,为人们提供了高效易行的工作环境。接下来,我就给大家介绍一下win7硬盘分区的具体操作步骤,有需要就一起来看看吧。1、右击“计算机”,点击菜单中的“管理”硬盘电脑图解12、在“计算机..._装win7系统硬盘怎么分区

读书-程序员宅基地

文章浏览阅读53次。冯友兰《中国哲学简史》收获颇多。转载于:https://www.cnblogs.com/zhangwenbiao/p/3776861.html

一个工作5年的java工程师对于人工智能AI的一点想法_java ai使用心得-程序员宅基地

文章浏览阅读4.5k次。人工智能AI,我的理解是智能手机的升级,可以说它是“智能机器人”,智能手机作为智能机器人的“大脑”,屏幕为机器人的脸,麦克风为机器人的耳朵,摄像头是机器人的眼睛,扬声器是机器人的嘴,后续可以增加嗅觉传感器作为鼻子,大脑(头)的基本构成已经有了。但是光有大脑是不够,还得有身体,包括手、脚等,人工智能就是智能手机+身体。_java ai使用心得

Xshell5 连接linux终端 传输文件_xshell5上传文件传输失败-程序员宅基地

文章浏览阅读934次。Xshell5 连接linux终端 传输文件顶部导航栏-》窗口-》传输新建文件 即可_xshell5上传文件传输失败

随便推点

Linux——samba服务器配置_linuxsamba服务器配置-程序员宅基地

文章浏览阅读8.4k次,点赞7次,收藏98次。作用:实现Linux的主机与windows系列主机进行文件的传输实验环境(保证两台主机能够相互访问):1、Windows7:客户端2、centos7: 服务端(文件共享)实验案例:John(总经理) managermike、caliI(市场部) marketcela、kado(工厂部) factory管理员:administrator共享名 共享目录 用户manager /opt/manager john(rw),administrator(rw)market /opt/market @market_linuxsamba服务器配置

textmesh pro ugui 字体不失真+中文字体 + 在unity 2019中脚本调用的解决使用办法_unity textmeshpro字体更清晰-程序员宅基地

文章浏览阅读2.2k次。如果需要ui的文字不失真,或是需要文字出现在世界场景中而不是ui涂层 。那么可以毫不犹豫的使用unity插件 textmesh pro安装:点击unity的windows->package manager 选择text mesh pro 安装加入字体:在网上随便下个字体,放在资源目录resouces中,没有就创建一个目录。生成文字素材:点击 windows》textmeshpr..._unity textmeshpro字体更清晰

Java基础之成员变量与局部变量_如何定义一个局部变量-程序员宅基地

文章浏览阅读1.3k次,点赞2次,收藏7次。局部变量:定义在函数(方法)中的那些变量。局部变量只在定义它的方法(函数)中有效。成员变量:定义在类的成员位置上的变量。成员变量在整个类中都有效。(全局变量是成员变量的俗称)。成员变量又分为 实例(对象)变量 和 类变量(static静态变量)。(先了解,后面会详细讲解)class Car{String color;//color为实例变量static Stringname; //只要有关键字static修饰,name为类变量}不管是成员变量还是局部变量它们都符合java基础.._如何定义一个局部变量

【验证成功】eZ-FET Lite 5528 官方修改版_ez-fet下载器-程序员宅基地

文章浏览阅读881次。立创链接烧写步骤(同时也是launchpad板载ezfet固件恢复步骤):STEP1:找一个可以烧写5528的烧写器,launchpad板载的Ez-FET或者FET430UIF都可以,按照标识连接到目标板上。STEP2:电脑上安装UniFlash工具,下载 Ez-FET lite的资源包STEP3:解压资源包,找到eZ-FET lite rev 1.10 Release Package\Firmware\EZFET_LITE_Rev1_1_BSL_1_1.txt这个固件文件,复制出来S_ez-fet下载器

Matlab机器学习和深度学习APP之Regression Learner_matlab regression learner-程序员宅基地

文章浏览阅读1.2w次,点赞11次,收藏100次。Matlab机器学习App之Regression Learner使用笔记目录软件与数据准备Regression Learner具体使用合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入目录软件与数据准备我之前用的是matlabR2016_matlab regression learner

Maven中设置阿里云中央仓库-程序员宅基地

文章浏览阅读1.9w次,点赞2次,收藏3次。把Maven中央仓库换成阿里云后,下载速度快了很多!配置如下:修改maven根目录下的conf文件夹中的setting.xml文件,内容如下:< !-- 在mirrors 中配置 mirror --><mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>

推荐文章

热门文章

相关标签