1. 父组件向子组件传值 props
//父组件
<template>
<div id="app">
<users v-bind:users="users"></users> //前者自定义名称便于子组件调用,后者要传递数据名
</div>
</template>
<script>
import Users from "./components/Users"
export default {
name: 'App',
data(){
return{
users:["Henry","Bucky","Emily"]
}
},
components:{
"users":Users
}
}
在子组件中使用props(可以是数组也可以是对象)接收即可。可以传多个属性。
//users子组件
<template>
<div class="hello">
<ul>
<li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props:{
users:{ //这个就是父组件中子标签自定义名字
type:Array,
required:true
}
},
data() {
return {
name : this.users // 把传过来的值赋值给新的变量
}
},
}
</script>
/*
props: ['users']
props: { users: String } //这样指定传入的类型,如果类型不对会警告
props: { users: [String, Number] } // 多个可能的类型
prosp: { users: { type: String, requires: true } } //必填的的字符串
props: {
childMsg: {
type: Array,
default: () => []
}
} // default指定默认值
如果 props 验证失败,会在控制台发出一个警告。
*/
子组件接收的父组件的值分为引用类型和普通类型两种:
普通类型:字符串(String)、数字(Number)、布尔值(Boolean)、空(Null)
引用类型:数组(Array)、对象(Object)
单向数据流
vue不推荐直接在子组件中修改父组件传来的props的值,会报错
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “result” (found in component )
export default {
name:"round-search-bar",
props:['search'], //父组件传来的值
data(){
return {
currentSearch: this.search //通过data, 定义新变量currentSearch, 这样currentSearch的值变更时,不会影响父组件传来的search的值
}
},
methods: {
doSearch(){
Util.searchAPI(this.$router,this.currentSearch)
}
},
}
2. 子组件向父组件传值
(通过 emit 事件形式)
// 子组件
<template>
<h1 @click="clicked">绑定一个点击事件</h1>
</template>
<script>
export default {
data() {
return {
info: '爸爸的爱好好收下'
};
},
methods: {
clicked() {
this.$emit("childChanged", this.info); //子组件的自定义事件
},
},
};
</script>
// 父组件
<template>
<div>
<my-child v-on:childChanged="getInfo" />
<h2>{{title}}</h2>
</div>
</template>
<script>
import MyChild from "./components/MyChild"
export default {
name: 'App',
components:{
MyChild,
},
data(){
return{
title:"我才是你爸爸"
}
},
methods:{
getInfo(e){ //声明这个函数
this.title = e;
}
},
}
</script>
父组件通过 refs 获取子组件实例
在使用选项式API时,我们可以通过this.$refs.name的方式获取指定元素或者组件,但是组合式API中就无法使用哪种方式获取。如果我们想要通过ref的方式获取组件或者元素,需要定义一个同名的Ref对象,在组件挂载后就可以访问了。
<template>
<ul class="parent list-group">
<li class="list-group-item" v-for="i in childRefs?.list" :key="i">
{{ i }}
</li>
</ul>
<!-- 子组件 ref的值与<script>中的保持一致 -->
<child-components ref="childRefs"></child-components>
<!-- 父组件 -->
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const childRefs = ref(null)
</script>
3. 任何组件间的通信 $bus 事件总线
// main.js
Vue.prototype.$eventBus = new Vue()
------------------------------------------
// 需要订阅的地方 mounted 、created 等
this.$eventBus.$on('update', val => {})
// 需要发布信息的地方
this.$eventBus.$emit('update', '更新信息')
//移除事件监听
this.$eventBus.$off('update', {})
- 通过
$on(eventName, eventHandler)
侦听一个事件 - 通过
$once(eventName, eventHandler)
一次性侦听一个事件 - 通过
$off(eventName, eventHandler)
停止侦听一个事件
Vue3中移除了事件总线,但是可以借助于第三方工具来完成,Vue官方推荐mitt[2]或tiny-emitter[3];
在大多数情况下不推荐使用全局事件总线的方式来实现组件通信,虽然比较简单粗暴,但是长久来说维护事件总线是一个大难题,所以这里就不展开讲解了,具体可以阅读具体工具的文档
4. vue3 v-model方式 组件中使用
v-model是Vue中一个比较出色的语法糖,就比如下面这段代码
<ChildComponent v-model:title="pageTitle" />
就是下面这段代码的简写形势
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
v-model确实简便了不少,现在我们就来看一下上面那个demo,如何用v-model实现。
子组件:
<template>
<div class="child-wrap input-group">
<input
v-model="value"
type="text"
class="form-control"
placeholder="请输入"
/>
<div class="input-group-append">
<button @click="handleAdd" class="btn btn-primary" type="button">
添加
</button>
</div>
</div>
</template>
<script setup>
import { ref, defineEmits, defineProps } from 'vue'
const value = ref('')
const props = defineProps({
list: {
type: Array,
default: () => [],
},
})
const emits = defineEmits(['update:list'])
// 添加操作
const handleAdd = () => {
const arr = props.list
arr.push(value.value)
emits('update:list', arr)
value.value = ''
}
</script>
在子组件中我们首先定义props和emits,然后添加完成之后emit指定事件。
注:update:是Vue中的固定写法,表示props中的某个属性名。
父组件中使用就比较简单,代码如下:
<template>
<!-- 父组件 -->
<ul class="parent list-group">
<li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
</ul>
<!-- 子组件 -->
<child-components v-model:list="list"></child-components>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript', 'HTML', 'CSS'])
</script>