vue 组件间通信分为 :
父组件向子组件通信
子组件向父组件通信
兄弟间组件通信
父组件向子组件通信
父组件向子组件通信的关键是defineProps函数
父组件向子组件传递一个字符串,子组件接收这个字符串并展示出来
father.vue
<script setup lang="ts">
import Son from './Son.vue'
</script>
<template>
<Son msg="这信息来自父组件" /></Son>
</template>
son.vue
<script setup lang="ts">
defineProps<{msg:string}>()
</script>
<template>
<div class="son">
子组件内容:
<p></p>
<div>{{msg}}</div>
</div>
</template>
这里要特别注意的是 defineProps 在 typescript 的专用写法:defineProps<>() ,而且 defineProps 是在 setup 语法糖才能使用, defineProps无须引入。
<template>
<h1>{{ msg }}</h1>
<div @click="clickThis">1111</div>
</template>
<script setup lang="ts">
defineProps<{ // 采用ts专有声明,无默认值
msg: string,
num?: number
}>()
// 采用ts专有声明,有默认值
interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
defineProps({ // 非ts专有声明
msg: String,
num: {
type:Number,
default: ''
}
})
</script>
<style scoped lang="less">
</style>
defineEmits
子组件向父组件事件传递
<template>
<div @click="clickThis">点我</div>
</template>
<script setup lang="ts">
/*ts专有*/
const emit= defineEmits<{
(e: 'click', num: number): void
}>()
/*非ts专有*/
const emit= defineEmits(['click'])
const clickThis = () => {
emit('click',2)
}
</script>
<style scoped lang="less">
</style>
子组件向父组件通信
子组件向父组件通信的关键是defineEmits函数
Son.vue 通过 defineEmits 定义事件传递方法 toFather
<script setup lang="ts">
const emit = defineEmits<{(e:'toFather',msg:string):void}>()
const click = () =>{
emit('toFather','来自子组件信息')
}
</script>
<template>
<div class="son">
子组件内容:
<p></p>
<button @click="click">
点击传信息给父组件
</button>
</div>
</template>
defineExpose的用法
在vue2.x中我们可以通过this. r e f s . x x x 或 者 t h i s . refs.xxx或者 this. refs.xxx或者this.parent 链获取到的组件的公开实例,
但是使用
为了在
假如我们要在子组件里暴露一个handleClick2方法,我们要先定义这个方法
const handleClick2 = () => {
a.value = 3
obj.name = '我叫改变'
};
然后整个
// defineExpose 统一暴露
defineExpose({
a,
obj,
handleClick2
})
因为如果defineExpose代码行在上,handleClick2申明在下,会报错
//定义对象属性
interface defineObj {
readonly name: string; //只读属性
age: number; //必填
sex?: string; //选填
call(): string; //有返回值,类型为string
action(): void; //必填、无返回值
[propName: string]: any; //任意属性
//需要注意的是,一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性
}
const obj = reactive<defineObj>({
name: "abc", //只读,不可修改
age: 18, //sex:'男',
a: "a",
b: 9,
c: true,
call: () => "call",
action: function () {
console.log("void接口");
},
o: { id: 1 },
});
defineExpose
暴露自己的属性供父组件使用
子
const count = ref(0);
defineExpose({
count,
});
父
<HelloWorld ref="child" />
const child = ref(null);
onMounted(() => {
console.log("child", child.value.count);
});
组件实战
父组件
<template>
<HelloWorld :msg="msg" @change="change"/>
<p v-if="state.msg1!==''"> {{state.msg1}}</p>
</template>
<script lang="ts">
import { defineComponent,ref,reactive } from 'vue';
import HelloWorld from './components/HelloWorld.vue';
export default defineComponent({
name: 'App',
components: {
HelloWorld
},
setup(){
let msg=ref("天下无敌")
let state=reactive({
msg1:""
});
let change=(val:string)=>{
console.log("子组件传参过来了",val)
state.msg1=val
console.log(state.msg1)
}
return{
msg,
change,
state
}
}
});
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
子组件
<template>
<div class="hello" @click="change">
{{msg}}
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'HelloWorld',
props: {
msg: String,
},
setup(props,context){
let change=()=>{
console.log("数据正在改变")
context.emit('change','hellowoolad')
}
return{
change
}
}
});
</script>
<style scoped>
</style>