-
provide和inject在Vue中使用
2020-12-11 10:43:24provide和inject在Vue中使用 应用背景 大家在写vue项目中不知道遇到过组件嵌套比较深的情况?你是不是还在使用props和$emit一层一层的传?或者使用vuex呢?但是有可能有些项目中用不到vuex的,咋整呢? 我也不知道,你去...provide和inject在Vue中使用
应用背景
大家在写vue项目中不知道遇到过组件嵌套比较深的情况?你是不是还在使用props和$emit一层一层的传?或者使用vuex呢?但是有可能有些项目中用不到vuex的,咋整呢? 我也不知道,你去别处找找吧!
官网描述
类型:
-
provide:Object | () => Object
-
inject:Array | { [key: string]: string | Symbol | Object }
-
详细:
provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。
provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的 property。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作。
inject 选项应该是:
-
一个字符串数组,或
-
一个对象,对象的 key 是本地的绑定名,value 是:
-
在可用的注入内容中搜索用的 key (字符串或 Symbol),或
-
一个对象,该对象的:
- from property 是在可用的注入内容中搜索用的 key (字符串或 Symbol)
- default property 是降级情况下使用的 value
-
提示:c这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
看代码吧
这是文件目录
祖师爷: index.vue<template> <div class="grandPa"> 祖师爷 : <span>姓名: {{ nameObj.name }}, 年龄: <i>{{ age }}</i>, 性别: <i>{{ city }}</i></span> <child /> <br> <br> <el-button type="primary" plain @click="changeName">变化场景</el-button> </div> </template> <script> import child from './com/exampleCom/parent' export default { name: 'ProvideGrandPa', components: { child }, data: function () { return { nameObj: { name: '曹操' }, age: 23, city: '男' } }, // 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的property。 provide () { return { nameObj: this.nameObj, // 传入一个可监听的对象 cityFn: () => this.city, // 通过computed来计算注入的值 age: this.age // 直接传值 } }, methods: { changeName () { if (this.nameObj.name === '曹操') { this.nameObj.name = '蔡文姬' this.city = '女' this.age = 24 } else { this.nameObj.name = '曹操' this.city = '男' this.age = 23 } } } } </script> <style lang="scss" scoped> .grandPa{ width: 600px; height:100px; line-height: 100px; border: 2px solid #f99; padding:0 10px; text-align: center; margin:50px auto; span{ font-size: 20px; } .blue{ color: blue; } } </style>
bus: parent
<template> <div class="parent"> bus: <strong>中转</strong> <son /> </div> </template> <script> import Son from './son' export default { name: 'ProvideParent', components: { Son } } </script> <style lang="scss" scoped> .parent{ height:100px; line-height: 100px; border: 2px solid #feafef; padding:0 10px; margin-top: 20px; strong{ font-size: 20px; } } </style>
孙子: son
<template> <div class="son"> 孙子 : <strong>姓名: {{ nameObj.name }}, 年龄: <i class="blue">{{ age }}</i>, 性别: <i class="yellow">{{ city }}</i></strong> </div> </template> <script> export default { name: 'ProvideSon', // inject 来获取的值 可以是一个字符串数组、也可以是一个对象 inject: ['nameObj', 'age', 'cityFn'], // inject: { // nameObj: 'nameObj', // age: 'age', // cityFn: 'cityFn' // }, computed: { city () { return this.cityFn() } }, created () { console.log('nameObj', this.nameObj, this.age, this.cityFn) } } </script> <style lang="scss" scoped> .son{ height:100px; line-height: 100px; padding:0 10px; margin: 20px; border: 1px solid #49e2af; strong{ font-size: 20px; } .blue{ color: blue; } } </style>
运行结果: 点击前
运行结果: 点击后
大家点击后是不是就验证了一个问题,通过观察年龄就可以得出上文提到的: provide 和 inject 绑定并不是可响应的。game over,再会!
-
-
vue provide inject vue依赖注入 vue跨多组件通讯
2020-11-20 17:23:39vue进阶实战课目录vue进阶实战课目录
provide inject跨多组件通讯
ref
和
$parent / $children` 在跨级通信时是有弊端的。当组件 A 和组件 B 中间隔了数代(甚至不确定具体级别)时,以往会借助 Vuex 这样的解决方案,不得不引入三方库来支持。本次介绍一种无依赖的组件通信方法:Vue.js 内置的 provide / inject 接口。
provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。vue的组件传值常用三种方式,1.prop传值2.$parent / $children传值3.provide inject
注意!provide和inject只能传值或提供方法给子组件,子组件不能调用父组件方法和数据!!例如 父组件的provide 子组件都能获取到,但子组件provide 父组件是拿不到的。
<!-- --> <template> <div> <div class="alert alert-primary" v-show="show"> 消息提示 </div> <div class="btn btn-primary" @click="rename(123)">edit children</div> <demo></demo> </div> </template> <script> import demo from './demo-item.vue'; export default { // 无法获取子组件方法和数据 inject:['title','rename'], provide() { return { show: this.show, showHide: this.showHide } }, components: { demo }, data() { return { show: false }; }, methods: { showHide(data){ this.show = data } }, watch: { }, computed: { }, created() { console.log(this.title) }, mounted() { } }; </script> <style> </style>
子组件
<!-- --> <template> <div> <h5>{{title}}</h5> <button class="btn btn-danger" @click="showHide(true)"> 显示main组件里的消息提示框 </button> <button class="btn btn-warning" @click="showHide(false)"> 隐藏main组件里的消息提示框 </button> </div> </template> <script> export default { inject:['show','showHide'], provide(){ return { title:this.title, rename:this.rename } }, components: {}, data() { return { title: "我是父组件的标题" }; }, methods: { rename(data) { this.title = data } }, watch: { }, computed: { }, created() { // console.log(this.show) }, mounted() { } }; </script> <style> </style>
-
java依赖注入inject_Vue实战指南之依赖注入(provide / inject)
2021-03-09 09:40:00不论组件层次有多深,这个简直太爽了,不用再关心dom层级,只要在祖先组件内部就可以一直使用祖先组件提供的provide 用法 下面贴出一部分select的实现: provide:Object | () => Object inject:Array | { [key: ...案例
UI美眉说咱家的选项菜单太丑了,小哥哥能不能美化一下呀,洒家自然是说小意思啦~
自定义一个select组件,so easy~
简单粗暴型:
option作为数据进来就ok啦。
然后发现下列问题:
key-value,不是所有的接口都是id-name
option要disabled 怎么办?
option存在几种情况怎么办?
...
回头看看原生的写法是这样:
Vue
React
Angular
还要加个el-option组件,灵活自由型:
Vue
React
Angular
好啦,这样设计就能完美解决之前的几个问题。
接着要解决选择了某一个el-option,怎么告诉el-select,$parent是一种选择,那么el-select当前的值又怎么告诉el-option你被选中了呢~ 笔者没有继续去深究,因为看到了APIprovide/inject
官方说明:
允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深(这也是使用$parent不好实现的地方),并在起上下游关系成立的时间里始终生效。
不论组件层次有多深,这个简直太爽了,不用再关心dom层级,只要在祖先组件内部就可以一直使用祖先组件提供的provide
用法
下面贴出一部分select的实现:
provide:Object | () => Object
inject:Array | { [key: string]: string | Symbol | Object }
el-select
export default {
name: "el-select",
provide() {
return {
select: this
};
}
}
el-option
export default {
name:'el-option',
inject:['select'],
created(){
if(this.select.value===this.value){
this.select.label=this.label;
}
}
}
总结
provide/inject 是解决组件之间的通信问题的利器,不受层级结构的限制。
但也不是随便去滥用,通信代表着耦合:
-
provide vue 响应式_vue新特性provide/inject深入学习
2020-12-29 10:08:00provide/inject深入学习本文深入探究provide,inject在官网porivide, inject的介绍中, 有这样的一段话:provide和inject绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性...provide/inject深入学习
本文深入探究provide,inject
在官网porivide, inject的介绍中, 有这样的一段话:
provide和inject绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
本文将深入探究这句话的意思.
父引用和子引用
在无provide和inject时代, 一般通过组件中$parent(父引用)和$children(子组件列表)来实现在组件树上进行跨组件状态或者属性的引用, 在子组件中通过递归或者循环获取$parent的方式的得到祖先组件的数据, 由于获取到的数据是可响应的,使用时自然也就是响应式的。如在子组件中有代码:
computed: {
count() {
return (this.$parent || {}).count;
},
user() {
return (this.$parent || {}).user;
},
},
当父组件的count(基本类型)或者user(引用类型)发生改变时, 会自动更新子组件的computed。这在组合组件(类似select和option)中非常有用, 可以把一些子组件共有的特性抽取到父组件中去进行统一设置, 如el-form中的label-width就可以为所有的子组件el-form-item设置一个默认的label-width。
实际使用时,不会直接对this.$parent获取目标组件, 因为这样耦合性太高, 一般通过循环或者递归查找某种特征的组件,具体可以查看element-ui的emitter中冒泡中是如何查找目标组件触发事件.
$children是不支持响应式的.
provide/inject传递数据
利用provide/inject机制也可以在组件树中数据自上而下进行传递: 在祖先组件中通过provide中暴露一些数据, 子组件获取这些数据. 如祖先组件中:
props: {
count: Number,
user: Object,
},
data() {
return {
grade: {
number: 12,
},
};
},
provide() {
return {
count: this.count,
user: this.user,
grade: this.grade,
};
},
其中, user是外部组件通过props传递给父组件的数据, 结构为:
{
name: ''.
age: 0,
address: {
number: 0,
}
}
在子组件中, 通过inject获取这些数据:
{
inject: ['count', 'user', 'grade'],
created () {
console.log(this.count);
}
// ...
}
provide/inject响应式特性深入探究
对上章节中provide/inject的案例进行响应式研究, 可以发现user,grade都是响应式数据结构,count不是。接着依次改变grade.number,user.address.number,user.age,user.address, 会发现子组件能接受到的响应式数据,但当改变了grade,user,count时, 子组件不能响应式渲染页面, 且改变grade,user`的属性也会发现不会响应式渲染。
其中count由于是一个不可监听的对象, 没有在子组件中动态渲染, 符合期望。其后在改变grade.number, user.address.number, user.age, user.address时, 子组件可以动态渲染改变值,这是由于这些属性都在一个可监听对象中。改变grade, user的后,发现子组件没有动态渲染, 证明grade, user是不可响应的,这是由于grade, user不在一个可监听的对象里面。 grade, user在哪呢? 在provide的声明中, 返回了一个对象:
provide() {
return {
count: this.count,
user: this.user,
grade: this.grade,
};
}
grade, user就在这个对象里面, 该对象不是可监听对象, 所以导致grade, user不是响应式的. 首先的解决方案就是, 将这个对象作为一个响应式的,可以在data中声明一个容器字段, 用于包装需要传递的数据, 如:
data() {
return {
context: {
user: '',
count: 0,
grade: '',
},
grade: {
number: 12,
},
};
},
watch: {
user(val) {
this.context.user = val;
},
count(val) {
this.context.count = val;
},
grade(val) {
this.context.grade = val;
},
},
created() {
this.context.user = this.user;
this.context.count = this.count;
this.context.grade = this.grade;
},
为什么这样写, 是由于provide/inject机制不支持响应式编程的,后续对provide返回的对象直接修改不会重新刷新provide/inject机制, 也就是provide返回的对象的最顶层的响应机制会失效,且无法对对象顶层属性进行操作。这个机制会导致以下三种方式不能实现响应式传递:
上文中的context不能在computed中声明。因为每次computed都会返回一个新的值(引用),而provide只会记录一开始的context的那个引用, 后续数据发生变更, 新的context不会被刷新到provide中去。
上文中的context就算data中声明的, 但如果在某个地方执行了this.context = {...}, 新的context也不会被更新在provide, provide中的context永远是在初始化时复制给他的那个引用。这会导致在父组件中context可以动态刷新, 但是子组件中的context不会动态刷新。
直接在provide函数中返回上文中的context,那么user, grade就会成为顶层属性,在created中进行的重新赋值操作和后续的重新赋值操作都不会响应到provide中, 将会失去响应式。
按照上面的写法, 发现grade, user已经能够动态在子组件中渲染了。由上得到结论:要想provide传递的数据一直是可响应的, 需要provide传递的每一个属性的值都是一个引用不变的可监听对象。
每次维护context太麻烦了, 有没有简便方法? 可以这样写:
provide() {
return {
group: this,
};
}
直接将父组件的引用放在provide返回对象的一个属性中, this代表当前实例, 引用实不会发生变化的, 且this中大多数属性都是响应式的。但需要注意带$前缀的属性大多数都不是响应式属性,如$el,子组件在使用这些属性时, 不会动态渲染。如果父组件有更大的作用域时,比如同时为多种类型子组件服务,或者允许第三方子组件inject使用时, 建议不要直接传递this, 而是在provide中暴露特定的api。但是按照上文中维护一个特定的context对象太繁琐了,可以使用函数来保证引用不变(推荐使用该方式):
provide() {
return {
getContext: () => ({
user: this.user,
grade: this.grade,
})
};
}
在子组件中:
inject: ['getContext'],
computed: {
context() {
return this.getContext();
}
}
原理
本章节从源码的角度来解密provide为什么有如此怪异的特性.
provide/inject为什么具备响应式, 因为它的实现机制也是通过$parent实现的。provide会在初始化时放到一个_provided的属性中,子组件在访问inject的值时, 会通过$parent属性向上查找所有祖先节点的_provided获取第一个有目标属性的值, 因此子组件跟父组件是共享一个变量,如果这个变量是引用类型的话, 在子组件中改变这个值, 父组件中该值也会发生了变化。
为什么provide返回的对象的最顶层的响应机制会失效? 在查找inject的值时, 会将目标_provide的单个属性拿出来, 放在一个不是响应式的对象中。从设计上也是合理的,provide的是一个数据集, 而不是一个数据,子组件inject到的数据可能从多个provide中挑选的集合, 故父组件的provide没有必要维持这个数据集的响应式 。
-
provide vue 响应式_Vue provide inject 怎么实现数据响应式
2020-12-30 03:22:13官网给出实例,说本身是不支持数据响应式的, 但是可以传入响应式数据,那么provide,inject就可以实现响应式。我这里理解应该没错哈我自己写的demo,做了如下更改parent 页面:export default {provide(){return {foo... -
2020-02-17 用provide / inject解决vue相同路由不刷新的问题
2020-02-17 04:54:01要点: app.vue //模板: <router-view v-if="isRouterAlive"></router-view> //Vue代码: export default { name: "App", data() { return { isRouterAlive: true ...provide() { ... -
vue provide inject
2021-04-09 18:50:49vue中祖先组件传递 后代组件层层传递 过于麻烦 可以用provide inject 祖先中 provide(){ return{ namess:this.name } }, data(){ return{ name:'provide inject' } }, 后代组件 props: { numActive: ... -
provide vue 响应式_provide inject 跨组件传参 + 响应式数据
2020-12-29 10:08:00父组件与子组件的传参,使用的是props,如果是父组件与孙子组件传参,大部分可能会采用递归的方式,也就是子组件props...provide有父组件设置,inject由子组件接收,他们的特性:祖先组件不需要知道哪些后代组件使... -
provide vue 响应式_Vue.js中provide/inject实现响应式数据更新的方法示例
2020-12-20 04:55:25Vue.js中provide/inject实现响应式数据更新的方法示例发布于 2020-4-17|复制链接摘记: vue.js官方文档:https://cn.vuejs.org/v2/api/#provide-inject首先假设我们在祖辈时候传入进来是个动态的数据,官方不是说如果... -
vue provide / inject
2019-06-12 09:56:44vue 使用 provide,inject。2.2.0 新增provide / inject 介绍provide 用法inject 用法实现 provide / inject 可监听 provide / inject 介绍 1. provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于... -
vue3 provide inject
2021-04-13 17:19:15## provide inject方法一 事件在父组件执行 父组件 import {provide} from "vue"; setup(){ let provideName = ref(100) provide('name',provideName) //事件来控制 const changevals = () => { ... -
Vue provide&inject
2019-05-10 11:39:40通过学习element ui collapase 组件,来学习provide和inject provide 提供出来 inject 注入进来 由父级组件提供出来,子级组件注入 a.el-collapse 父组件, 提供provide <template> <div class="el-... -
vue provide inject传值
2020-08-05 11:14:491、parent组件使用provide提供一个injectData,son组件通过inject获取到parent注入的数据,以上就是它的最简用法 2、provide/inject这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论... -
Vue 2.x折腾记 - (18) 用Vue的Inject Provide结合Event Bus来实现局部的状态维护
2019-04-18 17:57:07那最终的方案就是Vue的eventbus了 效果图 只展示部分功能,实际原型要复杂的多; 原型大体是这样的 实现原理 其实就是各个组件独立维护自己的状态,组件的默认值从外部传入; 而内部通过watch在immediate立即... -
聊聊Vue中provide/inject的应用详解
2020-12-13 12:49:42众所周知,在组件式开发中,最大的痛点就在于...今天,我们就来聊聊 Vue 中 provide/inject 的应用。 何为 provide/inject provide/inject 是 Vue 在 2.2.0 版本新增的 API,官网介绍如下: 这对选项需要一起使用, -
Vue通过provide inject实现组件通信
2020-11-19 18:23:25provide/inject是Vue.js2.2.0版本后新增的API: provide:Object | () => Object//一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。 inject:Array<string> | { [key: string]: string | Symbol | ... -
vue中数据传递的inject 和provide
2020-02-24 20:03:05处理Vuex 还有一种数据存储传递方案 ...provide / inject 2.2.0 新增 类型: provide:Object | () => Object inject:Array<string> | { [key: string]: string | Symbol | Object ... -
vue组件通讯之provide / inject
2018-12-20 17:22:00vue的组件通讯方式我们熟知的有props $emit bus vuex,另外就是provide/inject provide/inject是 Vue.js 2.2.0 版本后新增的 API,在文档中这样介绍 : 这对选项需要一起使用,以允许一个祖先组件向其所有子孙... -
vue 中provide的用法_vue中的provide和inject
2021-01-13 09:39:11阅读element-ui源码,发现在设计子组时件用到了inject属性,随即查了一下官方文档,得知vue在2.2.0版本里新增了provide / inject:provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序... -
vue 页面刷新 provide inject
2020-10-15 11:27:41vue 单页面刷新方法一( provide inject )路由跳转(不太推荐使用。本质就是跳转空白页之后再回来,地址栏会有一个快速的切换) 方法一( provide inject ) 修改app.vue中的代码 //HTML 部分 //原本 <router-... -
vue 中provide的用法_vue中provide和inject使用
2020-12-22 09:01:591、provide/inject有什么用?...vue提供了provide和inject帮助我们解决多层次嵌套嵌套通信问题。在provide中指定要传递给子孙组件的数据,子孙组件通过inject注入祖父组件传递过来的数据。其实,... -
vue3.0 provide和inject
2020-07-25 21:55:51import {provide,inject} from 'vue'; setup() { provide('xx','1234') const data=inject('xx',该参数为默认值); 使用ref来保证provided和injected之间值的响应: 如果注入一个响应式对象,则它的... -
vue 中provide的用法_Vue多级组件provide/inject使用详解
2020-12-22 09:01:56这次给大家带来Vue多级组件provide/inject使用详解,Vue多级组件provide/inject使用的注意事项有哪些,下面就是实战案例,一起来看一下。provide / inject 是 2.2 新增的方法,可以以一个祖先组件向所有子孙后代注入... -
vue的provide和inject特性
2019-07-10 15:57:50注意: provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。 参考: vue的provide和inject特性 provide与inject实用技巧 -
vue provide和inject使用
2018-11-21 16:35:00provide和inject使用场景也是组件传值,尤其是祖父组件--孙组件等有跨度的组件间传值,单向传值(由provide的组件传递给inject的组件)。 provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其...