Vue mixins 和 extends 使用详解
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 使用详解相关推荐
- keep alive PHP,vue中keep-alive使用方法详解
这次给大家带来vue中keep-alive使用方法详解,vue中keep-alive使用的注意事项有哪些,下面就是实战案例,一起来看一下. 1.keep-alive的作用以及好处 在做电商有关的项目中 ...
- php动态写入vue,Vue自定义动态组件使用详解
这次给大家带来Vue自定义动态组件使用详解,Vue自定义动态组件的注意事项有哪些,下面就是实战案例,一起来看一下. 现在基于vue的UI组件库有很多,比如iview,element-ui等.但有时候这 ...
- Vue的生命周期过程详解
Vue的生命周期 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.销毁等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁的 ...
- Vue 中的 ref 属性详解
Vue 中的 ref 属性详解 我们先来读一下vue的官方文档 我们来分析官方文档 首先ref的引用是相当于一个DOM节点(如果是子组件则指向的是其实例),而且是一个string类型的值. 通俗的将就 ...
- 《前端》权限链接--vue前端权限控制方案详解附demo_feiyu_may的博客-CSDN博客_vue 前端权限
前端权限控制 - 潘正 - 博客园 https://www.cnblogs.com/guchengnan/p/11800947.html vue前端权限控制方案详解附demo_feiyu_may的博 ...
- vue里页面的缓存详解
关于vue里页面的缓存详解 实用的例子ABC 往下查看 keep-alive是vue内置的一个组件,可以使被它包含的组件处于保留状态,或避免被重新渲染. 用法: 在keep-alive标签内部添加 i ...
- vue连接后端本地接口_详解vue配置后台接口方式
详解vue配置后台接口方式 在vueAdmin项目中有两种方式配置后端接口的方式,在此做下记录 第一种(代理方式) 在工程目录下 > config > index.js - 修改为如下配置 ...
- vue webpack 访问php,实例详解vue-cli优化的webpack配置
最近的项目度过了开始忙碌的基建期,也慢慢轻松下来,准备记录一下自己最近webpack优化的措施,希望有温故知新的效果.本文主要介绍了详解基于vue-cli优化的webpack配置,小编觉得挺不错的,现 ...
- vue 时间插件_Vue3 插件开发详解尝鲜版「值得收藏」
作者:lishuai 转发链接:https://segmentfault.com/a/1190000022757326 前言 vue3.0-beta 版本已经发布了一段时间了,正式版本据说在年中发布( ...
最新文章
- 简单介绍基于PostgreSql 别名区分大小写的问题
- 数据结构基础(21) --DFS与BFS
- 会计师要计算机学的,会计师要具备哪些能力条件
- springMVC的@RequestParam是必须滴
- 初级数据分析师需要哪些必备技能?
- c#对象集合去重_C# List 对象去重
- Boyer-Moore 投票算法
- 典型方法_裴礼文老师编数学分析中的典型问题与方法练习参考答案的说明
- HBase的Shell命令和JavaAPI
- WCF技术剖析之六:为什么在基于ASP.NET应用寄宿(Hosting)下配置的BaseAddress无效...
- ubuntu 安装php mcrypt扩展
- NOD32 AntiVirus v2.70.16杀毒软件
- Maven使用本地jar包(三种方式)
- 扬声器安装程序unknown,电脑无声音
- jpeg-snoo-图片信息分析工具
- Hazelcast Jet DAG原理
- 并发编程(四)---设计模式
- 屠龙传说世界【全自动】辅助脚本
- Pandas 日期处理:生成及去除工作日与节假日
- Re:从零开始的Spring Security Oauth2(二)
热门文章
- iview-admin登录请求分析
- 【TensorFlow】(四)tf.feature_column.embedding_column()函数
- 众多APP青睐邀请有礼活动,怎么才能更完善?
- 在谷歌浏览器中执行 JavaScript(二)
- QString的indexOf匹配问题
- Excel 如何批量删除自定义的单元格样式
- qmessagebox 设置显示屏幕中间_简单又实用,Macbook外接显示器有那些骚操作
- 【周光权:利用计算机信息技术实施危害行为定性问题】
- Windows XP 用户:计算机感染震荡波 (Sasser) 蠕虫时应采取的措施(转载)
- 防沉迷系统的设计与实现