一、父传子
1. props
父组件
<template>
<Child :fatherVal="fatherVal"/>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
import {ref} from "vue";
const fatherVal = ref<string>('money')
</script>
<style scoped>
</style>
子组件
<template>
<div>
子组件中使用父组件的属性:{{fatherVal}}
</div>
</template>
<script setup lang="ts">
defineProps(['fatherVal'])
</script>
<style scoped>
</style>
2.v-model
父组件:
<template>
<Child v-model="fatherData"/>
<!-- 和上面的v-model等价-->
<Child :modelValue="fatherData" @update:modelValue="handle"/>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
import {ref} from "vue";
const fatherData = ref<number>(34)
const handle = (value:number) => {
fatherData.value = value
}
</script>
<style scoped>
</style>
子组件
<template>
<div>
父组件中的内容
<h3>{{ modelValue }}</h3>
<button @click="$emit('update:modelValue', modelValue+1)">修改父组件的值</button>
</div>
</template>
<script setup lang="ts">
defineProps(['modelValue'])
const $emit = defineEmits(['update:modelValue'])
</script>
<style scoped>
</style>
3.$refs
父组件
<template>
<Child ref="child1"/>
<Child ref="child2"/>
<br>
<button @click="changeChildrenVal($refs)">修改children中的属性</button>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
import {ref} from "vue";
const changeChildrenVal = (refs : {[key:string]:any}) => {
for(let key in refs) {
refs[key].childVal += 3
}
}
</script>
<style scoped>
</style>
子组件
子组件中需要使用defineExpose暴露出对应的数据
<template>
<div>
<div>
子组件中的属性:{{childVal}}
</div>
<br>
</div>
</template>
<script setup lang="ts">
import {ref} from "vue";
const childVal = ref(23)
//把变量暴露出去
defineExpose({childVal})
</script>
<style scoped>
</style>
4.具名插槽、默认插槽
a.默认插槽
父组件
<template>
<Child>
<h3> 父组件中定义的内容,传到子组件中!!!</h3>
</Child>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
</script>
<style scoped>
</style>
子组件
<template>
<h2>子组件中的内容</h2>
<slot></slot>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
b.具名插槽
父组件
<template>
<Child>
<h3> 父组件中定义的内容,传到子组件中!!!</h3>
<template v-slot:slot1>
<h2>
位置1的内容
</h2>
</template>
<!-- 这里的slot是简写-->
<template #slot2>
<h3>
位置2的内容
</h3>
</template>
</Child>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
</script>
<style scoped>
</style>
子组件
<template>
<h2>子组件中的内容</h2>
<slot name="slot1"></slot>
<slot name="slot2"></slot>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
二、子传父
1. 自定义事件
<template>
<Child :fatherData="fatherData" @handel="handle"></Child>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
import {ref} from "vue";
const fatherData = ref<number>(34)
const handle = (value:number) => {
console.log(value)
fatherData.value = value
}
</script>
<style scoped>
</style>
子组件
<template>
<div>
父组件中的内容
<h3>{{ fatherData }}</h3>
<button @click="$emit('handel', fatherData+1)">修改父组件的值</button>
</div>
</template>
<script setup lang="ts">
defineProps(['fatherData'])
const $emit = defineEmits(['handel'])
</script>
<style scoped>
</style>
2.v-model
子组件通过父组件提供的方法,对父组件中的数据进行改变,与自定义事件类似。
<template>
<div>
父组件中的内容
<h3>{{ modelValue }}</h3>
<button @click="$emit('update:modelValue', modelValue+1)">修改父组件的值</button>
</div>
</template>
<script setup lang="ts">
defineProps(['modelValue'])
const $emit = defineEmits(['update:modelValue'])
</script>
<style scoped>
</style>
3.$parent
父组件
<template>
父组件中的数据:{{fatherData}}
<Child ></Child>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
import {ref} from "vue";
const fatherData = ref<number>(34)
defineExpose({fatherData})
</script>
<style scoped>
</style>
子组件
<template>
<div>
<button @click="handel($parent)">修改父组件的值</button>
</div>
</template>
<script setup lang="ts">
const handel = (parent:any) => {
parent.fatherData -= 1
}
</script>
<style scoped>
</style>
4.作用域插槽
数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
父组件
<template>
<Child v-slot="params">
<div >
子组件中的数据:{{ params.data + params.other }}
</div>
</Child>
</template>
<script setup lang="ts">
import Child from "@/components/Child.vue";
</script>
<style scoped>
</style>
子组件
<template>
<h2>子组件中的内容</h2>
<slot :data="data" other="哈哈"/>
</template>
<script setup lang="ts">
import {ref} from "vue";
const data = ref('子组件中的数据')
</script>
<style scoped>
</style>
三、祖传孙、孙传祖
1.$attr
这种方法需要通过子组件,因为父通过自定义属性传给子组件的数据,如果子组件不使用defineProps接受,这些数据都会放在$attr中,这样就可以使用v-bind,把数据传给孙组件。
父组件
<template>
<div class="father">
<h3>父组件</h3>
<Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import { ref } from "vue";
let a = ref(1)
let b = ref(2)
let c = ref(3)
let d = ref(4)
function updateA(value:number){
a.value = value
}
</script>
<style scoped/>
子组件
<template>
<div class="child">
<h3>子组件</h3>
<GrandChild v-bind="$attrs"/>
</div>
</template>
<script setup lang="ts" name="Child">
import GrandChild from './GrandChild.vue'
</script>
<style scoped>
</style>
孙组件
<template>
<div class="grand-child">
<h3>孙组件</h3>
<h4>a:{{ a }}</h4>
<h4>b:{{ b }}</h4>
<h4>c:{{ c }}</h4>
<h4>d:{{ d }}</h4>
<h4>x:{{ x }}</h4>
<h4>y:{{ y }}</h4>
<button @click="updateA(666)">点我更新A</button>
</div>
</template>
<script setup lang="ts" name="GrandChild">
defineProps(['a','b','c','d','x','y','updateA'])
</script>
<style scoped>
</style>
2.provide、inject
父组件
<template>
<div class="father">
<h3>父组件</h3>
<Child :a="a" v-bind="{x:100,y:200}" :updateA="updateA"/>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from './Child.vue'
import {provide, ref} from "vue";
let a = ref(1)
function updateA(value:number){
a.value = value
}
provide('dataContext',{a,updateA})
</script>
<style scoped/>
孙组件
<template>
<div class="grand-child">
<h3>孙组件</h3>
<h4>a:{{ a }}</h4>
<button @click="updateA(666)">点我更新A</button>
</div>
</template>
<script setup lang="ts" name="GrandChild">
import {inject} from "vue";
let{ a , updateA } = inject('dataContext',{a:0,updateA:(x:number)=>{}});
</script>
<style scoped>
</style>
四、兄弟间、任意组件
1.mitt
引入miit
npm install mitt
创建对应的ts文件
import mitt from "mitt";
const emitter = mitt()
//暴露默认的mitt
export default emitter
组件1
<template>
<div class="father">
<h3>父组件</h3>
{{dataA}}
<Child/>
</div>
</template>
<script setup lang="ts" name="Father">
import {onUnmounted, ref} from "vue";
import emitter from '@/utils/emitter';
import Child from "@/components/Child.vue";
const dataA = ref<number>(23)
emitter.on('changeData',(val:number) => {
dataA.value = val;
})
//组件卸载时,一定要解绑对应的事件
onUnmounted(()=>{
emitter.off('changeData')
})
</script>
<style scoped/>
组件2
<template>
<div class="child">
<h3>子组件</h3>
<button @click="changeFatherData">修改父组件的值</button>
</div>
</template>
<script setup lang="ts" name="Child">
import emitter from '@/utils/emitter'
function changeFatherData() {
emitter.emit('changeData',23)
}
</script>
<style scoped>
</style>
2.pinia
1.安装 : npm install pinia
2.在vue中使用pinia
import { createApp } from 'vue'
import App from './App.vue'
/* 引入createPinia,用于创建pinia */
import { createPinia } from 'pinia'
/* 创建pinia */
const pinia = createPinia()
const app = createApp(App)
/* 使用插件 */{}
app.use(pinia)
app.mount('#app')
3.创建对应的store
它有三个概念 state
、getter
、action
,相当于组件中的: data
、 computed
和 methods
。
// 引入defineStore用于创建store
import {defineStore} from 'pinia'
// 定义并暴露一个store
export const useCountStore = defineStore('count',{
// 动作
actions:{},
// 状态
state(){
return {
sum:6
}
},
// 计算
getters:{}
})
4.在组件中使用定义的store
// 引入对应的useXxxxxStore
import {useSumStore} from '@/store/sum'
// 调用useXxxxxStore得到对应的store
const sumStore = useSumStore()
5.在组件中修改store中的数据
- 可以直接修改:countStore.sum = 666
- 也可以批量修改:countStore.$patch({
sum:999,
school:'atguigu'
}) - 通过action进行修改,action中定义自己业务逻辑即可。