> 文章列表 > 09-vue3组件间数据共享

09-vue3组件间数据共享

09-vue3组件间数据共享

文章目录

    • 1.props
      • 1.1普通的setup写法
      • 1.2在setup语法糖写法
      • 1.3修改父组件传递过来的属性
    • 2.$emit
      • 2.1setup写法
      • 2.2setup语法糖写法
    • 3.ref
    • 4.attrs
      • 4.1setup中获取
      • 4.2setup语法糖获取
    • 5. provide / inject

1.props

vue2中组件间数据共享大概有这几种方式:

props 和 $emit、v-model、 .sync、 ref、$bus、$attrs、$listeners、$parent、$children、$root、provide、inject、vuex

在vue3中数据共享的方式要分成几种情况,由于在组合式api中vue2语法也可以使用,但是官方不推荐这种混合的语法,所以我们只讨论在组合式api中进行组件间数据共享.大致分成两种情况,普通的setup写法和setup的语法糖形式写法

用 props 传数据给子组件

1.1普通的setup写法

one.vue组件:

<template><div><h3>父组件</h3><!-- 第一步在子组件的UI标签上,绑定自义定属性,自定义属性的值就是要传递给子组件的值 --><two :coffe="coffe" :title1="title1" :tea="tea"></two></div>
</template>
<script>
import {ref,reactive,toRaw} from "vue"
import two from "./two"
export default {components:{two},setup(props) {const coffe=ref("厚乳拿铁!");const title1=ref("我是父组件数据");const tea=toRaw(reactive(["乌龙茶","西湖龙井"])) ; return {coffe,title1,tea}}
}
</script>

two.vue组件:

<template><div><h3>子组件</h3><p>接收父组件传递过来的值:{{coffe}}---{{tea}}---{{title1}}</p></div>
</template>
<script>
export default {//第二步:在子组件中使用props接收父组件传值过来的//如果在子组件中不接收父组件传递过来的数据,setup(props)中的props参数是没有值的//props的写法有两种:对象和数组/ props:{coffe:{type:String,//传递的数据类型required:true, //是否必须要传递default:'coffe' //默认值},tea:{type:Array,required:true,default:'tea'},title1:{type:String}},*///props数组的简写形式props:["coffe","tea","title1"],setup(props) {console.log(props);} 
}
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qMSVR9wI-1681265288949)(/uploads/vue3/images/m_7972e64344b3356bc4b11a0f75c5616d_r.png)]

1.2在setup语法糖写法

父组件Home.vue组件:

<template><div class="home"><h3>home.vue组件</h3><child :isshow="isshow" :money="money"></child></div>
</template><script setup>
import {ref,reactive} from "vue";import child from "./child"const isshow=ref(false);const money=ref("我这有一些钱拿去花吧!")</script>

子组件child.vue组件

<template><div><h3>child.vue组件</h3><p>接收父组件传递过来的数据(setup语法糖):----{{money}}</p><p><button @click="toggle">控制盒子的显示和隐藏</button> </p><div class="child-box" v-if="isshow"></div></div>
</template>
<script setup>
//defineProps:在语法糖中不需要引入 直接使用
const props=defineProps({isshow:Boolean,money:{type:String,default:''}
})
console.log(props) //Proxy {isshow: false, money: '我这有一些钱拿去花吧!'}const toggle=()=>{//想要使用传递过来的数据:props.属性   console.log(props.isshow); //false//点击按钮让child-box盒子显示//需要修改父组件传递过来的isshow属性,这时会报一个警告:reactivity.esm-bundler.js?89dc:521 Set operation on key "isshow" failed: target is readonly. //props.isshow=true;
}
</script>
<style lang="scss" scoped>
.child-box{width: 200px;height: 200px;background: purple;
}</style>

1.3修改父组件传递过来的属性

<script setup>
//defineProps:在语法糖中不需要引入 直接使用
const props=defineProps({isshow:Boolean,money:{type:String,default:''}
})const toggle=()=>{//想要使用传递过来的数据:props.属性   console.log(props.isshow); //false//点击按钮让child-box盒子显示//需要修改父组件传递过来的isshow属性,这时会报一个警告:reactivity.esm-bundler.js?89dc:521 Set operation on key "isshow" failed: 		//target is readonly. props.isshow=true;
}
</script>

由于vue是单向数据流,父组件传递给子组件的属性,子组件只能使用不能修改,在vue2中可以使用.sync修饰符.但是在vue3中v-bind的.sync修饰符和组件的model选项被删除了.在vue3中我们可以直接使用v-model语法糖进项绑定,绑定属性发生了变化,属性名是 modelValue, 事件名是:update:modelValue.

在one.vue中:

<template lang=""><div><h3>父组件</h3><p>count的值为:{{count}}</p><!-- 如果想要获取原生事件对象:加入绑定事件函数fn fn(e) {e就是事件对象}如果绑定的是js表达式,提供的是一个默认的变量$event 如果想要获取自定义事件绑定函数fn fn(data){ data触发自定义事件的参数}如果绑定的是js表达式 此时 $event代表触发自定义事件的传参 --><two :modelValue="count"  @update:modelValue="count=$event" ></two></div>
</template>
<script>
import {ref,reactive,toRaw} from "vue"
import two from "./two"
export default {components:{two},setup(props) {const count=ref(100)return {count}}
}
</script>

two.vue组件:

Vue3setup函数上提供了两个参数,一个props,一个是context下面的emit方法,分别来处理输入和输出。

<template lang=""><div><h3>子组件</h3><p><button @click="changModelValue">点击修改count</button> </p></div>
</template>
<script>
export default {props:["modelValue"],setup(props,{emit}) {const changModelValue=()=>{//改变父组件传递过来的数据emit("update:modelValue",200)}return {changModelValue}} 
}
</script>

可以简写为v-model

 <!-- :modelValue="count"   @update:modelValue="count=$event"可以简写为v-model="count" --><two :coffe="coffe" :title1="title1" :tea="tea" v-model:count="count"  ></two>const changModelValue=()=>{emit("update:count",200)}

setup语法糖的写法:

//定义抛出事件的名字 
//defineEmits适用于 Vue3.2版本,不需要引入
const emit=defineEmits(["update:count"])const changModelValue=()=>{emit("update:count",200)}

2.$emit

子组件向父组件传值可以使用$emit

vue3setup函数上提供了两个参数,一个props,一个是context下面的emit`方法,分别来处理输入和输出。

2.1setup写法

子组件two.vue

<template><div><h3>子组件</h3><p>子组件向父组件传值</p><p><button @click="myclick">点击向父组件传递数据</button> </p></div>
</template><script>
import {ref,reactive} from "vue"
export default {setup(props,{emit}) {const movie={name:'这个杀手不太冷静',price:56}const myclick=()=>{emit("send",movie)}return {myclick}} 
}
</script>

父组件one.vue:

<template><div><two @send="resiveMovie"  ></two><p>接收从子组件传递过来的值:{{resiveData.film}}</p></div>
</template><script>
import {ref,reactive,toRaw} from "vue"
import two from "./two"
export default {components:{two},setup(props) {const resiveData=reactive({})const resiveMovie=(film)=>{console.log(film)resiveData.film=film;}return {coffe,resiveMovie,resiveData}}
</script>

2.2setup语法糖写法

child.vue子组件:

<template><div><p><input type="text" v-model="str"  @input="changStr" /></p></div>
</template><script setup>
import {ref} from "vue"
const emit=defineEmits(["sendStr"])
const str=ref("")
const changStr=()=>{emit("sendStr",str)
}
</script>

home.vue父组件:

<template><div><p>接收子组件传递过来的数据:{{message}}</p><child  @sendStr="reaiveStr"  ></child></div>
</template><script setup>
import {ref} from "vue"
const message=ref("")
const reaiveStr=(msg)=>{message.value=msg
}
</script>

3.ref

子组件child.vue

//向外部暴露属性或者方法适用于Vue3.2版本, 不需要引入defineExpose({childName: "这是子组件的属性",someMethod(){console.log("这是子组件的方法")}})

父组件home.vue

<template><child  :money="money"   v-model:isshow="isshow" @sendStr="reaiveStr"  ref="childCom"   ></child><p><button @click="handlerClick">点击获取子组件</button> </p>
</template>
<script setup>const childCom=ref(null);const handlerClick = () => {console.log(childCom.value)console.log(childCom.value.childName) // 获取子组件对外暴露的属性childCom.value.someMethod() // 调用子组件对外暴露的方法}
</script>

4.attrs

attrs:包含父作用域里除 class 和 style 除外的非 props 属性集合

4.1setup中获取

父组件:

<template><two :coffe="coffe" :title1="title1" :tea="tea" class="demo" ></two>
</template>

子组件:

<script>props:["coffe"],setup(props,{emit,attrs}) {console.log("attrs",attrs) //{title1: '我是父组件数据', tea: Array(2), class: 'demo'}}
</script>

4.2setup语法糖获取

父组件:

<template><child  :money="money" ></child>
</template>

子组件:

<script setup>import {ref,useAttrs} from "vue"
//接收attrsconst attrs = useAttrs();console.log("attrs",attrs) //{money: '我这有一些钱拿去花吧!}
</script>

5. provide / inject

provide / inject 为依赖注入

provide:可以让我们指定想要提供给后代组件的数据或

inject:在任何后代组件中接收想要添加在这个组件上的数据,不管组件嵌套多深都可以直接拿来用

// Parent.vue
<script setup>import { provide } from "vue"provide("people",{name:"张三",age:18});provide("id","1005678");
</script>// Child.vue
<script setup>import { inject } from "vue"const people=inject("people"); //{ "name": "张三", "age": 18 }
const id=inject("id"); //id:1005678
</script>