在上一篇文章的demo中,我们成功的制作了简单的todolist,本篇我们来了解下父子组件传值的操作。
本篇依旧采用vite+vue3+ts的组合,以及使用ant-design-vue的UI组件,对于这套组合和UI组件的项目部署,本篇不再讲解有需要了解的可以看《vite+vue3+ts简单例子todolist》。
下边我们直接来看下父子组件传值。
在vue2中我们使用属性和props的组合,在vite+vue3+ts里边也是一样用使用属性,只是在接收时候使用的是defineProps。
我们先来父组件的代码Father.vue
<template>
<div>
<h2>这是父组件h2>
<h4>下方是子组件的内容h4>
<SonVue :msg="msg" />
div>
template>
<script setup lang="ts">
import SonVue from './Son.vue';
import { ref } from 'vue';
// 传给子组件的内容
const msg = ref('这是父组件传给子组件的内容');
script>
<style scoped>style>
然后就是子组件中获取传入的值了,也就是defineProps在vite+vue3中的使用了,Son.vue代码:
<template>
<div>
<h3>这是子组件接收的父组件信息h3>
<p>{{props.msg}}p>
div>
template>
<script setup lang="ts">
// defineProps 接收父组件传入的值,使用方式分为ts的用法和非ts的用法
// 非ts的用法
const props = defineProps({
msg: {
type: String,
default: ''
}
});
script>
<style scoped>style>
上边是defineProps非ts的用法,下边使用ts的写法
<template>
<div>
<h3>这是子组件接收的父组件信息h3>
<p>{{props.msg}}p>
div>
template>
<script setup lang="ts">
// defineProps 接收父组件传入的值,使用方式分为ts的用法和非ts的用法
// 非ts的用法
/* const props = defineProps({
msg: {
type: String,
default: ''
}
}); */
// ts的用法
interface PropsType {
msg: string
}
const props = withDefaults(defineProps<PropsType>(), {
msg: '' // 默认值
});
script>
<style scoped>style>
上边是父组件传值到子组件defineProps的使用,下边我们再来看下子组件传值父组件的方式,与vue2也是一样使用事件的方式,只是这里使用了defineEmits,下边我们看下defineEmits的使用。
Father.vue
<template>
<div>
<h2>这是父组件h2>
<div>
<h4>子组件触发父组件接收的值h4>
<p>{{receiveMsg}}p>
div>
<h4>下方是子组件的内容h4>
<SonVue @onReceiveMsg="onReceiveMsg" />
div>
template>
<script setup lang="ts">
import SonVue from './Son.vue';
import { ref } from 'vue';
// 接收子组件的传入的值
const receiveMsg = ref('');
// 子组件触发的方法
const onReceiveMsg = (params:string) => {
console.log('接收子组件的值', params);
receiveMsg.value = params;
}
script>
<style scoped>style>
子组件使用defineEmits触发父组件的方法
非ts的用法,Son.vue代码:
<template>
<div>
<h3>这是子组件接收的父组件信息h3>
<a-input v-model:value="inputVal" placeholder="请输入传给父组件的值" />
<a-button @click="sendMsg">点击传值给父组件参数a-button>
div>
template>
<script setup lang="ts">
import { Button as AButton, Input as AInput } from "ant-design-vue";
import { ref } from 'vue'
const inputVal = ref('');
// 子组件通过defineEmits触发父组件的方法
// 非ts的用法
const emit = defineEmits(["onReceiveMsg"]);
const sendMsg = () => {
// 传input值给父组件
emit("onReceiveMsg", inputVal.value);
}
script>
<style scoped>style>
使用ts的用法,Son.vue
<template>
<div>
<h3>这是子组件接收的父组件信息h3>
<a-input v-model:value="inputVal" placeholder="请输入传给父组件的值" />
<a-button @click="sendMsg">点击传值给父组件参数a-button>
div>
template>
<script setup lang="ts">
import { Button as AButton, Input as AInput } from "ant-design-vue";
import { ref } from 'vue'
const inputVal = ref('');
// 子组件通过defineEmits触发父组件的方法
// 非ts的用法
// const emit = defineEmits(["onReceiveMsg"]);
// ts的用法
interface EmitType {
(e: "onReceiveMsg", params: string): void
}
const emit = defineEmits<EmitType>();
const sendMsg = () => {
// 传input值给父组件
emit("onReceiveMsg", inputVal.value);
}
script>
<style scoped>style>
在vue3中增加了暴露组件自己属性的方法,让子组件暴露自己的属性,然后父组件应用,也类似子组件直接传值给父组件了。
这里我们先来子组件的代码
Son.vue:
<template>
<div>
<h3>这是子组件接收的父组件信息h3>
<a-input v-model:value="inputVal" placeholder="请输入传给父组件的值" />
div>
template>
<script setup lang="ts">
import { Input as AInput } from "ant-design-vue";
import { ref } from 'vue'
const inputVal = ref('');
// 子组件通过defineExpose暴露自己的属性
// 子组件暴露的方法
const exposeFun = (name:string) => {
console.log('子组件暴露自己的属性', name);
}
// 使用defineExpose暴露inputVal和exposeFun
defineExpose({
inputVal,
exposeFun
});
script>
<style scoped>style>
然后是父组件调用子组件暴露出来的属性
<template>
<div>
<h2>这是父组件h2>
<div>
<a-button @click="useSonExpose" >使用子组暴露的属性a-button>
<h4>子组件触发父组件接收的值h4>
<p>{{receiveMsg}}p>
div>
<h4>下方是子组件的内容h4>
<SonVue ref="sonRef" />
div>
template>
<script setup lang="ts">
import {Button as AButton} from 'ant-design-vue';
import SonVue from './Son.vue';
import { ref } from 'vue';
// 接收子组件的传入的值
const receiveMsg = ref('');
// 父组件接收子组件暴露的方法,使用子组件的ref
const sonRef = ref<{
inputVal: string;
exposeFun(name:string): void;
}>();
// 使用子组件暴露的内容
const useSonExpose = () => {
// 由于ts认为inputVal可能位undefined不能赋值给string的reveiveMsg
// 因此使用了一个断言
receiveMsg.value = sonRef.value?.inputVal as string;
// 触发子组件暴露的方法
sonRef.value?.exposeFun('父组件');
}
script>
<style scoped>style>
以上就是vue3中父子组件传值的方法,defineProps和defineEmits以及defineExpose的使用。
上边我们介绍了父子组件的传值方法,这里我们再来介绍下vue3中对属性监听watch的用法,我们先来构建一个组件的架子,里边有ref和reactive的方式声明的变量,因为两种方式的监听有点区别:
Watch.vue基础代码
<template>
<div>
<h3>Watch用法h3>
<a-input v-model:value="inputVal" @keydown.enter="onInput" />
<ol>
<li v-for="(item, index) in data.list" >{{item}}li>
ol>
div>
template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import {Input as AInput} from 'ant-design-vue';
const inputVal = ref('');
const data = reactive<{
list: string[]
}>({
list: []
});
const onInput = () => {
if(inputVal.value){
data.list.push(inputVal.value);
inputVal.value = '';
}
};
script>
<style scoped>style>
然后使用watch对inputVal和list的监听
<template>
<div>
<h3>Watch用法h3>
<a-input v-model:value="inputVal" @keydown.enter="onInput" />
<ol>
<li v-for="(item, index) in data.list" >{{item}}li>
ol>
div>
template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue';
import {Input as AInput} from 'ant-design-vue';
const inputVal = ref('');
const data = reactive<{
list: string[],
name: string
}>({
list: [],
name: ''
});
const onInput = () => {
if(inputVal.value){
data.list.push(inputVal.value);
data.name = inputVal.value;
inputVal.value = '';
}
};
// watch监听ref声明属性的变化
watch(inputVal, (newVal, oldVal)=> {
console.log('watch监听inputVal的变化 newVal ------>', newVal);
console.log('watch监听inputVal的变化 oldVal ------>', oldVal);
});
// watch监听reactive声明属性的变化
watch(() => data.name, (newVal, oldVal)=> {
console.log('watch监听data.name的变化 newVal ------>', newVal);
console.log('watch监听data.name的变化 oldVal ------>', oldVal);
});
watch(()=> data.list, (newVal, oldVal)=> {
console.log('watch监听data.list的变化 newVal ------>', newVal);
console.log('watch监听data.list的变化 oldVal ------>', oldVal);
}, {deep: true});
// vue3的watch也可以同时监听多个
watch([inputVal, ()=> data.name],(newVal, oldVal) => {
console.log('watch监听inputVal和data.name的变化 newVal ------>', newVal);
console.log('watch监听inputVal和data.name的变化 oldVal ------>', oldVal);
});
script>
<style scoped>style>
在对list数组的监听中需要加上deep才能监听到数组的变化,因此又加入了data.name可以和inputVal对比使用,这就是vue3中watch的用法了。
以上就是本文的内容了,后边有空在给路由的使用和生命周期钩子函数整理出来,对于vite+vue3+ts的这套组合开发项目也就不成问题了,对于vue3中使用的vuex感觉既然有了好用的pinia可以作为了解,项目中可以使用pinia来处理store,如果对pinia不了解可以来看《新的好朋友Pinia,引领状态管理新时代》进一步了解。
如有疑问可以留言,也可以到QQ群一起探讨:
QQ群1: 657011407, QQ群2: 492593055,也可以到微信找我 shenzhipeng1023