一、Provide Inject
通常,当我们需要将数据从父组件传递到子组件时,我们使用props。想象一下这样的机构:你有一些深嵌套的组件,而你只需要来自深嵌套子组件中父组件的某些内容。在这种情况下,你任然需要将prop传递到整个组件链中,这可能会很烦人。
对于这种情况,我们可以使用provide和inject对父组件可以作为其所有子组件的依赖项提供程序,而不管组件层次结构有多深。这个特性有两个部分:父组件有一个provide选项来提供数据,子组件有一个inject选项来开始使用这个数据。
-
非组合是API中的写法:
定义一个子组件Location.vue,使用inject接收app根组件传递的值
<template> <div class="location"> <h3>Location组件</h3> App组件的Title={{title}} <br>App组件里面的userInfo: {{userinfo.username}}--{{userinfo.age}} </div> </template> <script> export default { name: "", inject:['title','userinfo'], data() { return {} }, methods: {} } </script> <style lang="scss" scoped> .location{ text-align: center; } </style>
定义一个组件Home.vue,调用子组件Location.vue
<template> <div> <h2>Home组件</h2> <br> <v-location></v-location> </div> </template> <script> import Location from "@/components/Location"; export default { name: "", data() { return {} }, components:{ "v-location":Location, }, methods: {} } </script> <style lang="scss" scoped> h2{ text-align: center; } </style>
在根组件App.vue中调用Home.vue组件,并使用provide传值,并且定义方法改变titile的值,运行发现,改变的值并不会传递到Location.vue组件
<template> <h1>我是app根组件</h1> <button @click="setTitle">改变title</button> <br> {{title}} <hr> <v-home></v-home> </template> <script> import Home from "@/components/Home"; export default { name: "App", data(){ return{ title:"app组件里面的titile" } }, provide(){ return{ title:this.title, userinfo:{ username:"张三", age:20 } } }, components: { "v-home": Home, }, methods: { setTitle(){ this.title="改变后的app根组件标题" } } } </script> <style lang="scss" scoped> h1 { text-align: center; } </style>
-
组合式API中的写法
Provide:
在setup()中使用provide时,我们首先从vue显示导入provide方法。这使我们能够调用provide时来定义每个property。
provide函数允许你通过两个参数定义property:
- property的name(类型)
- property的value
语法:provide(“key”,value);
将上面的例子按如下方式重构:则实现了同步改变
Location.vue
<template> <div class="location"> <h3>Location组件</h3> App组件传递的的Title={{title}} <br> App组件传递的userinfo: <br> {{userinfo.username}}--{{userinfo.age}} <br> 双向数据绑定: <br> <input type="text" v-model="userinfo.username" placeholder="username"/> <br> <input type="text" v-model="userinfo.age" placeholder="age"/> <br>{{userinfo.username}}--{{userinfo.age}} </div> </template> <script> import {inject} from "vue" export default { name: "", setup(){ let title=inject("title"); let userinfo=inject("userinfo"); return { title, userinfo } }, methods: {} } </script> <style lang="scss" scoped> .location{ text-align: center; } </style>
App.vue
<template> <h1>我是app根组件</h1> <button @click="setTitle">改变title</button> <br> {{ title }} <br> 双向数据绑定: <br> <input type="text" v-model="userinfo.username" placeholder="username"/> <br> <input type="text" v-model="userinfo.age" placeholder="age"/> <br>{{userinfo.username}}--{{userinfo.age}} <hr> <v-home></v-home> </template> <script> import Home from "@/components/Home"; import {ref,reactive,provide} from "vue"; export default { name: "App", setup() { let title = ref("app根组件里面的title"); provide("title",title); let userinfo=reactive({ username:"张三", age:20 }); provide("userinfo",userinfo); let setTitle=()=>{ title.value="改变后的title"; }; return { title, userinfo, setTitle } }, components: { "v-home": Home, } } </script> <style lang="scss" scoped> h1 { text-align: center; } </style>
运行时,我们点击App.vue组件的按钮,改变title的值,Location.vue组件里面的值跟着改变。
在App.vue里面用v-model双向数据绑定,文本框的值改变时,对应的Locaiton.vue的值也跟着改变。
在Location.vue里面用v-model双向数据绑定,文本框的值改变时,App.vue组件里面的值也跟着改变。
注意:
对比以前父子组件使用props接收值时,子组件时无法改变父组件的值的。
provide inject实现父子组件传值的时候,子组件改变数据也会影响父组件。