文章目录
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组件:
Vue3
在setup
函数上提供了两个参数,一个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
vue3在
setup函数上提供了两个参数,一个
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"
//接收attrs
const 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>