0

0

Vue.js源码学习provide 和 inject

小云云

小云云

发布时间:2018-02-24 14:25:58

|

1855人浏览过

|

来源于php中文网

原创

vue.js2.2.0+ 版本中添加加了 provide 和 inject 选项。他们成对出现,用于父级组件向下传递数据。 

源码位置

和之前一样,初始化的方法都是在 Vue 的 _init 方法中的。

  // src/core/instance/init.js
  Vue.prototype._init = function (options?: Object) {
    ……
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
  }

这里找到 initInjectionsinitProvide 方法,这就是 provideinject 的初始化方法了。这两个方法都是在 src/core/instance/inject.js 中。

provide

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作。

先看源码:

// src/core/instance/inject.jsexport function initProvide (vm: Component) {
  const provide = vm.$options.provide  if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)
      : provide
  }
}

provide 是向下传递数据的选项。这里先拿到 provide 选项中的内容,如果有 provide 选项,将 provide 选项传递给 vm._provided 变为 Vue 实例全局数据。
这里看一下例子更清楚,下例中传入数据 foo,数据内容为 bar

立即学习前端免费学习笔记(深入)”;

var Provider = {
  provide: {
    foo: 'bar'
  },  // ...}

inject

inject 选项应该是一个字符串数组或一个对象,该对象的 key 代表了本地绑定的名称,value 为其 key (字符串或 Symbol) 以在可用的注入中搜索。

源码

// src/core/instance/inject.jsexport function initInjections (vm: Component) {
  const result = resolveInject(vm.$options.inject, vm)  if (result) {
    observerState.shouldConvert = false
    Object.keys(result).forEach(key => {
      defineReactive(vm, key, result[key])
    })
    observerState.shouldConvert = true
  }
}

简化后的源码可以看到,首先通过 resolveInject 方法获取 inject 选项搜索结果,如果有搜索结果,遍历搜索结果并为其中的数据添加 setter 和 getter。
接着来看下 resolveInject 方法:

export function resolveInject (inject: any, vm: Component): ?Object {
  if (inject) {    // inject 是 :any 类型因为流没有智能到能够指出缓存
    const result = Object.create(null)    // 获取 inject 选项的 key 数组
    const keys = hasSymbol
      ? Reflect.ownKeys(inject).filter(key => {        /* istanbul ignore next */
        return Object.getOwnPropertyDescriptor(inject, key).enumerable
      })
      : Object.keys(inject)    for (let i = 0; i < keys.length; i++) {      const key = keys[i]      const provideKey = inject[key].from      let source = vm      while (source) {        if (source._provided && provideKey in source._provided) {
          result[key] = source._provided[provideKey]          break
        }
        source = source.$parent
      }      if (!source) {        if ('default' in inject[key]) {          const provideDefault = inject[key].default
          result[key] = typeof provideDefault === 'function'
            ? provideDefault.call(vm)
            : provideDefault
        } else if (process.env.NODE_ENV !== 'production') {
          warn(`Injection "${key}" not found`, vm)
        }
      }
    }    return result
  }
}

获取 inject 选项的 key 数组,遍历 key 数组,通过向上冒泡来查找 provide 中是否有 key 与 inject 选项中 from 属性同名的,如果有,则将这个数据传递给 result;如果没有,检查 inject 是否有 default 选项设定默认值或者默认方法,如果有则将默认值返传给 result,最终返回 result 对象。
所以,inject 的写法应该是有 default 默认值的:

XYCMS企业建站系统7.4
XYCMS企业建站系统7.4

XYCMS快速建站系统是由站长XY亲手编译的,作为站长,做网站不可能凭空而造,站长也是经过长期学习和借鉴别人的成功经验成就了XYCMS,现在网络上建站源码很多,尤其是ASP网站源码,但事事必有弊端,作为ASP老牌建站首选,XYCMS也融合了网络上广大CXY的看家本领,不敢说完美,但求稳定。方便、简洁、容易上手等优点已经吸引了许多用户的一致好评。 XY的目标:打造最稳定、安全的建站系统,XYCMS已

下载
const Child = {
  inject: {
    foo: { default: 'foo' }
  }
}

或者是有 from 查找键和 default 默认值的:

const Child = {
  inject: {
    foo: {
      from: 'bar',      default: 'foo'
    }
  }
}

或者为 default 默认值设定一个工厂方法:

const Child = {
  inject: {
    foo: {
      from: 'bar',      default: () => [1, 2, 3]
    }
  }
}

好吧,我承认这就是引用的官网的三个例子~ 不过意思到就好啦。
这里我有个疑问,既然在源码中主动去识别了 from 和 default,官网上说是

2.5.0+ 的注入可以通过设置默认值使其变成可选项:

那么如下写法还可用吗?

var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }  // ...}

为此,我们去查查 2.2.0 版本的Vue是怎么写的?

export function initInjections (vm: Component) {
  const provide = vm.$options.provide  const inject: any = vm.$options.inject  if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)
      : provide
  }  if (inject) {    // inject is :any because flow is not smart enough to figure out cached
    // isArray here
    const isArray = Array.isArray(inject)    const keys = isArray
      ? inject
      : hasSymbol
        ? Reflect.ownKeys(inject)
        : Object.keys(inject)    for (let i = 0; i < keys.length; i++) {      const key = keys[i]      const provideKey = isArray ? key : inject[key]      let source = vm      while (source) {        if (source._provided && source._provided[provideKey]) {
          vm[key] = source._provided[provideKey]          break
        }
        source = source.$parent
      }
    }
  }
}

从中可以看到,在这个版本 provide 和 inject 是一起初始化的。之后,将 provide 传给 vm._provide ,在获取 inject 选项的时候代码判断了 inject 是否为数组,如果是数组直接遍历数组,之后查找 provide 的代码差不多。
所以我推测: 2.5.0+ 之后不能再使用数组形式的 inject 来搜索 provide 了。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
vue.js为什么报错
vue.js为什么报错

vue.js报错的原因:1、语法错误;2、组件使用不当;3、数据绑定问题;4、生命周期钩子使用不当;5、插件或依赖问题;6、路由配置错误;7、异步操作处理不当等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

120

2024.03.11

vue.js插槽有哪些用
vue.js插槽有哪些用

vue.js插槽的作用:1、提高组件的可重用性;2、实现组件的灵活布局;3、实现组件间的数据传递和交互;4、促进组件的解耦和模块化。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

174

2024.03.11

vue.js怎么带参数跳转
vue.js怎么带参数跳转

vue.js带参数跳转的方法:1、定义路由;2、在组件中使用路由参数;3、进行带参数的跳转。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

91

2024.03.11

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1498

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

623

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

592

2024.03.22

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

6

2026.01.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.2万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.5万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号