Vue 2.0 中依赖注入 provide/inject组合实战

--------------------------------------------------------------------------------

先来看看官网的介绍:

Vue 2.0 中依赖注入 provide/inject组合实战

简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件得资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱。这个就是这对选项要干的事情

provide和inject需要配合使用,它们的含义如下:

provide        ;一个对象或返回一个对象的函数,该对象包含可注入起子孙的属性,可以使用ES6的Symbols作为key(只有原生支持Symbol才可以)
inject         ;一个字符串数组或一个对象
                 ;字符串数组    ;provide对象里哪些属性可用
                ;一个对象        ;key是本地的绑定名,value是provide里对应的对象名,也可以是一个对象,此时from属性是provide里对应的对象名,default属性是不存在时的默认值

来个实例就明显了:

<!DOCTYPE html>   <!--例1-->     <html lang="en"> <head> <meta charset="UTF-8"> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <title>Document</title> </head> <body> <div><child></child></div> <script> Vue.component('child',{ inject:['message'], template:'<p>{{message}}</p>' }) new Vue({ el:'#app',provide:{message:'Hello Vue!'} }) </script> </body> </html>

输出:Hello Vue!,对应的DOM节点渲染为:

是不是感觉和props的传值差不多,我们在中间再嵌套一层组件就知道他的用处了,例如:

<!DOCTYPE html>   <!--例2-->     <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> </head> <body> <div><test></test></div> <script> Vue.component('child',{ inject:['message'], template:'<p>{{message}}</p>' }) Vue.component('test',{ template:`<div><child></child></div>` }) new Vue({ el:'#app',provide:{message:'Hello Vue!'} }) </script> </body> </html>

输出:Hello Vue!,对应的DOM节点渲染为:

就是这个用处吧,多层嵌套时还是很方便的

源码分析

--------------------------------------------------------------------------------

provide/inject组合的源码分为三个部分,分别是组件注册、Vue实例化和组件实例化的过程,如下:

组件注册时

注册时会执行Vue.extend()(第4770行),内部会执行mergeOptions()合并一些属性,mergeOptions如下:

function mergeOptions ( //第1451行 parent, child, vm ) { { checkComponents(child); } if (typeof child === 'function') { child = child.options; } normalizeProps(child, vm); normalizeInject(child, vm); //对inject进行一次规范化 normalizeDirectives(child); var extendsFrom = child.extends; if (extendsFrom) { parent = mergeOptions(parent, extendsFrom, 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; 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 }

normalizeInject定义如下:

function normalizeInject (options, vm) { //第1398行 var inject = options.inject; if (!inject) { return } var normalized = options.inject = {}; if (Array.isArray(inject)) { //如果inject是一个数组 for (var i = 0; i < inject.length; i++) { //遍历inject normalized[inject[i]] = { from: inject[i] }; //保存到normalized里面,例如:{foo: {from: "foo"}} } } else if (isPlainObject(inject)) { //如果inject是一个对象 for (var key in inject) { var val = inject[key]; normalized[key] = isPlainObject(val) ? extend({ from: key }, val) : { from: val }; } } else { warn( "Invalid value for option \"inject\": expected an Array or an Object, " + "but got " + (toRawType(inject)) + ".", vm ); } }

对于例1来说,mergeOptions()之后inject等于:{message: {from: "message"}},如下:

Vue实例化时

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/d2521ea65bcc3c110be5456aab3d3cee.html