Vue 提供了mixins 和 extends 来在组件里直接合并一些特定的属性。
用法如下:

var mixin = {created: function () { console.log(1) }
}
var vm = new Vue({created: function () { console.log(2) },mixins: [mixin]
})
// => 1
// => 2
var CompA = { ... }
var CompB = {extends: CompA,...
}

以上两者的用法来自vue官方案例,最大的区别就是extends传入的是一个组件属性对象,mixins传入的是n个组件属性对象组成的数组。

这里我们会有一个疑问,当我们注入想动的组件属性到当前组件,合并的机制是什么?是组件覆盖mixins或者extends 还是后者覆盖前者,还是两者共存。这是本文说明的重点。我们看代码:

mergeField是合并的核心代码,他会根据属性名,在合并方法合集strats里去找一个特定属性key的合并方法。调用合并方法进行合并操作。然后把合并的结果返回给vm实例。

// vue实例在初始化的时候会调用该合并方法vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm);
function mergeOptions (parent,child,vm) {{checkComponents(child);}if (typeof child === 'function') {child = child.options;}normalizeProps(child, vm);normalizeInject(child, vm);normalizeDirectives(child);if (!child._base) {// 初始先合并extends和mixins的属性到 _base 对象上if (child.extends) {parent = mergeOptions(parent, child.extends, vm); }if (child.mixins) {for (var i = 0, l = child.mixins.length; i < l; i++) {parent = mergeOptions(parent, child.mixins[i], vm);}}}var options = {};var key;// 先处理_base 和mixins 或者extends 混合后的内容for (key in parent) { mergeField(key);}// 再将组件上原来的属性内容和上面的进行混合for (key in child) {if (!hasOwn(parent, key)) {mergeField(key);}}function mergeField (key) {// 通过属性名寻找对应的合并策略var strat = strats[key] || defaultStrat;options[key] = strat(parent[key], child[key], vm, key);}return options}

下面将展示针对不同属性的合并策略对应的源代码:

// 这个是属性里data和组件里data的合并方式

strats.data = function (parentVal,childVal,vm) {if (!vm) {if (childVal && typeof childVal !== 'function') {warn('The "data" option should be a function ' +'that returns a per-instance value in component ' +'definitions.',vm);return parentVal}return mergeDataOrFn(parentVal, childVal)}return mergeDataOrFn(parentVal, childVal, vm)};

这个是属性里 props 、methods、inject、computed的合并方法

strats.props =
strats.methods =
strats.inject =
strats.computed = function (parentVal,childVal,vm,key
) {if (childVal && "development" !== 'production') {assertObjectType(key, childVal, vm);}if (!parentVal) { return childVal }var ret = Object.create(null);extend(ret, parentVal);// childVal 覆盖 ret里的parentValif (childVal) { extend(ret, childVal); }return ret
};

这个是对el和propsData的覆盖方法

strats.el = strats.propsData = function (parent, child, vm, key) {if (!vm) {warn("option \"" + key + "\" can only be used during instance " +'creation with the `new` keyword.');}return defaultStrat(parent, child)};

这是对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];}// 按watch的key合并回掉函数到数组中,供后面顺序执行ret[key$1] = parent? parent.concat(child): Array.isArray(child) ? child : [child];}return ret};

这是对provide的合并方法

strats.provide = mergeDataOrFn;

生命周期属性的覆盖方法

  var LIFECYCLE_HOOKS = ['beforeCreate','created','beforeMount','mounted','beforeUpdate','updated','beforeDestroy','destroyed','activated','deactivated','errorCaptured','serverPrefetch'];
LIFECYCLE_HOOKS.forEach(function (hook) {strats[hook] = mergeHook;});function mergeHook (parentVal,childVal) {var res = childVal? parentVal? parentVal.concat(childVal): Array.isArray(childVal)? childVal: [childVal]: parentVal;return res? dedupeHooks(res): res}

属性中 三种vue内部类型(组件,指令,过滤器)的合并方法

 var ASSET_TYPES = ['component','directive','filter'];
ASSET_TYPES.forEach(function (type) {strats[type + 's'] = mergeAssets;});

上面的多种策略对应的最终合并函数如下:

 // 合并顺序是// to里加入只有from中特有的属性,to和from里都有的属性,保留to里的,最后返回tofunction mergeData (to, from) {if (!from) { return to }var key, toVal, fromVal;var keys = hasSymbol? Reflect.ownKeys(from): Object.keys(from);for (var i = 0; i < keys.length; i++) {key = keys[i];// in case the object is already observed...if (key === '__ob__') { continue }toVal = to[key];fromVal = from[key];if (!hasOwn(to, key)) {set(to, key, fromVal);} else if (toVal !== fromVal &&isPlainObject(toVal) &&isPlainObject(fromVal)) {mergeData(toVal, fromVal);}}return to}
// 合并 vue中data或者reject,他们是一个函数,所以合并函数返回值
function mergeDataOrFn (parentVal,childVal,vm) {if (!vm) {// in a Vue.extend merge, both should be functionsif (!childVal) {return parentVal}if (!parentVal) {return childVal}// when parentVal & childVal are both present,// we need to return a function that returns the// merged result of both functions... no need to// check if parentVal is a function here because// it has to be a function to pass previous merges.return function mergedDataFn () {return mergeData(typeof childVal === 'function' ? childVal.call(this, this) : childVal,typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal)}} else {return function mergedInstanceDataFn () {// instance mergevar instanceData = typeof childVal === 'function'? childVal.call(vm, vm): childVal;var defaultData = typeof parentVal === 'function'? parentVal.call(vm, vm): parentVal;if (instanceData) {return mergeData(instanceData, defaultData)} else {return defaultData}}}}
// 默认的合并策略,优先使用childVal,childVal没有才使用parentValvar defaultStrat = function (parentVal, childVal) {return childVal === undefined? parentVal: childVal};

// to里有的将被_from覆盖,to里没有的form有的,to里将添加。function extend (to, _from) {for (var key in _from) {to[key] = _from[key];}return to}

总结:

属性名称 合并策略 对应合并函数
data mixins/extends 只会将自己有的但是组件上没有内容混合到组件上,重复定义默认使用组件上的
如果data里的值是对象,将递归内部对象继续按照该策略合并
mergeDataOrFn,mergeData
provide 同上 mergeDataOrFn,mergeData
props mixins/extends 只会将自己有的但是组件上没有内容混合到组件上 extend
methods 同上 extend
inject 同上 extend
computed 同上 extend
组件,过滤器,指令属性 同上 extend
el 同上 defaultStrat
propsData 同上 defaultStrat
watch 合并watch监控的回掉方法
执行顺序是先mixins/extends里watch定义的回调,然后是组件的回掉
strats.watch
HOOKS 生命周期钩子 同一种钩子的回调函数会被合并成数组
执行顺序是先mixins/extends里定义的钩子函数,然后才是组件里定义的
mergeHook

mixins和extends 的合并策略都是按照上面的表格来合并的。

Vue mixins 和 extends 使用详解相关推荐

  1. keep alive PHP,vue中keep-alive使用方法详解

    这次给大家带来vue中keep-alive使用方法详解,vue中keep-alive使用的注意事项有哪些,下面就是实战案例,一起来看一下. 1.keep-alive的作用以及好处 在做电商有关的项目中 ...

  2. php动态写入vue,Vue自定义动态组件使用详解

    这次给大家带来Vue自定义动态组件使用详解,Vue自定义动态组件的注意事项有哪些,下面就是实战案例,一起来看一下. 现在基于vue的UI组件库有很多,比如iview,element-ui等.但有时候这 ...

  3. Vue的生命周期过程详解

    Vue的生命周期 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.销毁等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁的 ...

  4. Vue 中的 ref 属性详解

    Vue 中的 ref 属性详解 我们先来读一下vue的官方文档 我们来分析官方文档 首先ref的引用是相当于一个DOM节点(如果是子组件则指向的是其实例),而且是一个string类型的值. 通俗的将就 ...

  5. 《前端》权限链接--vue前端权限控制方案详解附demo_feiyu_may的博客-CSDN博客_vue 前端权限

    前端权限控制 - 潘正 - 博客园  https://www.cnblogs.com/guchengnan/p/11800947.html vue前端权限控制方案详解附demo_feiyu_may的博 ...

  6. vue里页面的缓存详解

    关于vue里页面的缓存详解 实用的例子ABC 往下查看 keep-alive是vue内置的一个组件,可以使被它包含的组件处于保留状态,或避免被重新渲染. 用法: 在keep-alive标签内部添加 i ...

  7. vue连接后端本地接口_详解vue配置后台接口方式

    详解vue配置后台接口方式 在vueAdmin项目中有两种方式配置后端接口的方式,在此做下记录 第一种(代理方式) 在工程目录下 > config > index.js - 修改为如下配置 ...

  8. vue webpack 访问php,实例详解vue-cli优化的webpack配置

    最近的项目度过了开始忙碌的基建期,也慢慢轻松下来,准备记录一下自己最近webpack优化的措施,希望有温故知新的效果.本文主要介绍了详解基于vue-cli优化的webpack配置,小编觉得挺不错的,现 ...

  9. vue 时间插件_Vue3 插件开发详解尝鲜版「值得收藏」

    作者:lishuai 转发链接:https://segmentfault.com/a/1190000022757326 前言 vue3.0-beta 版本已经发布了一段时间了,正式版本据说在年中发布( ...

最新文章

  1. 简单介绍基于PostgreSql 别名区分大小写的问题
  2. 数据结构基础(21) --DFS与BFS
  3. 会计师要计算机学的,会计师要具备哪些能力条件
  4. springMVC的@RequestParam是必须滴
  5. 初级数据分析师需要哪些必备技能?
  6. c#对象集合去重_C# List 对象去重
  7. Boyer-Moore 投票算法
  8. 典型方法_裴礼文老师编数学分析中的典型问题与方法练习参考答案的说明
  9. HBase的Shell命令和JavaAPI
  10. WCF技术剖析之六:为什么在基于ASP.NET应用寄宿(Hosting)下配置的BaseAddress无效...
  11. ubuntu 安装php mcrypt扩展
  12. NOD32 AntiVirus v2.70.16杀毒软件
  13. Maven使用本地jar包(三种方式)
  14. 扬声器安装程序unknown,电脑无声音
  15. jpeg-snoo-图片信息分析工具
  16. Hazelcast Jet DAG原理
  17. 并发编程(四)---设计模式
  18. 屠龙传说世界【全自动】辅助脚本
  19. Pandas 日期处理:生成及去除工作日与节假日
  20. Re:从零开始的Spring Security Oauth2(二)

热门文章

  1. iview-admin登录请求分析
  2. 【TensorFlow】(四)tf.feature_column.embedding_column()函数
  3. 众多APP青睐邀请有礼活动,怎么才能更完善?
  4. 在谷歌浏览器中执行 JavaScript(二)
  5. QString的indexOf匹配问题
  6. Excel 如何批量删除自定义的单元格样式
  7. qmessagebox 设置显示屏幕中间_简单又实用,Macbook外接显示器有那些骚操作
  8. 【周光权:利用计算机信息技术实施危害行为定性问题】
  9. Windows XP 用户:计算机感染震荡波 (Sasser) 蠕虫时应采取的措施(转载)
  10. 防沉迷系统的设计与实现