一、父-子传递
1. props
- vue2
//传递
<Child :count="count" :userInfo="userInfo" :changeCount="changeCount"></Child>
//接收 多种方式
数组形式:props: ['count', 'userInfo', 'changeCount']
对象形式:props: {count: Number,userInfo: Object,changeCount: Function }
配置对象形式:
props: {
count: {
type: Number,
required: true, // 必填
default: 4 // 默认值
// required 和 default 是互斥的,如果必填还设置默认值没有意义 },
userInfo: {type: Object, default() { return { name: '老六', age: 22} } },
changeCount: {type: Function,required: true}
},
- vue3
//传递
<child-components :list="list"></child-components>
//接收
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
list: {
type: Array,
default: () => []
}
})
</script>
2. v-model
- vue2
//传递
<CustomInput v-model="keyword"> </CustomInput>
//接收
<input type="text" :value="value" @input="changeValue">
props: ['value'],
methods: {
changeValue(e) {
this.$emit('input', e.target.value);
}
}
3. .Sync 父子组件同步数据
- vue2
//传递
<Child1 :msg.sync="string"></Child1>
data() {
return {
string: "我爱你",
};
},
接收(调用)
<button @click="changeParentMsg">修改父组件传过来的数据</button>
props: ['msg'],
methods: {
changeParentMsg() {
this.$emit('update:msg', "666")
}
}
- vue3
//传递
<ChildComponent v-model:title="pageTitle" />
//接收(调用)
<script setup>
import { defineEmits } from 'vue'
const emits = defineEmits(['add'])
const handleSubmit = () => {
const arr = props.list
arr.push(value.value)
emits('update:list', arr)
value.value = ''
}
</script>
4. refs
- vue2
$refs可以获取到组件实例,拿到组件实例可以拿到组件中的数据,在标签上使用的时候获取到的是标签
- vu3
//父组件
<div>{{chileRefs?.count}}/div>
<child-components ref="childRefs"></child-components>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const childRefs = ref(null)
</script>
//子组件
<script setup>
import { ref, defineExpose } from 'vue'
const count = ref(20)
const handleAdd = () => {
count.value=50
}
defineExpose({ count })
注意:默认情况下,setup 组件是关闭的,通过模板 ref 获取组件的公共实例。
如果需要公开,需要通过defineExpose API 公开。
</script>
5.slot
- vue2
// 子组件
<template>
<div class="box">
<slot>header</slot>
<div>--------------------------------</div>
<ul>
<li v-for="(todo, index) in todos" :key="todo.id">
<slot name="content" :row="todo" :$index="index" msg="hello">内容</slot>
</li>
</ul>
<div>--------------------------------</div>
<slot name="footer">footer</slot>
</div>
</template>
// 父组件
<template>
<div class="box">
<List :todos="todos">
<!-- v-slot:default 可以省略,是默认的普通插槽 -->
<template v-slot:default>
父组件传的Header
</template>
<!-- # 是v-slot指令的简写 -->
<template #footer>
父组件传的Footer
</template>
<!--
data是一个对象,这个对象中放的数据是子组件绑定在slot标签上的属性组成的对象
-->
<template v-slot:content="data">
<div :style="{ background: data.row.isComplete ? 'green' : '' }">
内容: {{ data.row.text }} -
是否完成: {{ data.row.isComplete ? '完成' : '未完成' }} -
msg: {{ data.msg }}
</div>
</template>
</List>
</div>
</template>
二、子-父传递
1.emit
- vue2
//传递
<Event1 :count="count" @changeCount="changeCount"></Event1>
//接收(调用)
<button @click="$emit('changeCount')">修改父组件的count</button>
$emit('changeCount', 50)
参数一:触发的事件类型 参数二: 传递的参数
- vue3
//传递
<child-components @add="handleAdd"></child-components>
//接收(调用)
<button @click="handleSubmit" class="btn btn-primary" type="button"> add</button>
//js
<script setup>
import { defineEmits } from 'vue'
const emits = defineEmits(['add'])
const handleSubmit = () => {
emits('add', value.value)
value.value = ''
}
</script>
三、跨组件
1. EvenBus 事件总线
- vue2
//安装
new Vue({
beforeCreate() {
Vue.prototype.$bus = this; // 安装总线
},
mounted() {
this.$bus.$on('receiveParams', this.receiveParams)
},
methods: {
receiveParams(params) {
console.log('接收到的参数', params);
}
}
}
//接收(调用)
<button @click="$bus.$emit('receiveParams', 25)">传给Child2参数</button>
- vue3
Vue 3 中移除了 eventBus,但可以借助第三方工具来完成。
Vue 官方推荐使用 mitt 或 tiny-emitter。
在大多数情况下,不建议使用全局事件总线来实现组件通信。
虽然比较简单粗暴,但是维护事件总线从长远来看是 个大问题,这里就不解释了。
2. provide与inject
provide/inject是 Vue 中提供的一对 API。无论层级多深,API 都可以实现父组件到子组件的数据传递。
- vue2
//传递
provide() {
return {
content1: this.content1,
content2: this.content2,
changeContent1: this.changeContent1,
changeContent2: this.changeContent2
}
},
//接收
inject: ['content1', 'content2', 'changeContent1', 'changeContent2']
- vue3
//传递
<script setup>
import { ref, provide } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript', 'HTML', 'CSS'])
const value = ref('')
provide('list', list.value)
const handleAdd = () => {
list.value.push(value.value)
value.value = ''
}
</script>
//接收
<template>
<ul class="parent list-group">
<li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
</ul>
</template>
<script setup>
import { inject } from 'vue'
const list = inject('list')
</script>
注意:使用 provide 进行数据传输时,尽量使用 readonly 封装数据,避免子组件修改父组件传递的数据。
3. vuex/pinia
Vuex 和 Pinia 是 Vue 3 中的状态管理工具,使用这两个工具可以轻松实现组件通信。