一、props (父-->子)
//父组件
<template>
<div>
<h1>我是父组件</h1>
<child :name="name" age = "12"></child>
</div>
</template>
<script setup lang="ts">
import child from './child.vue'
import { ref } from 'vue'
const name = ref('父亲名字')
</script>
//子组件
<template>
<div>
<h1>我是子组件2</h1>
<p>我收到了父组件的数据:{{ name }}</p>
<p>{{ props.age }}</p>
</div>
</template>
<script setup lang="ts">
const props = defineProps(["name", "age"]);
</script>
二、自定义事件(子-->父)
//父组件
<template>
<div>
<h1>我是父组件</h1>
<child @mimi="tingmimi"></child>
<p>我听到了子组件的秘密 : {{ msg }}</p>
</div>
</template>
<script setup lang="ts">
import child from './child.vue'
import { ref } from 'vue'
let msg =ref('还没听到秘密')
const tingmimi = function(message:any){
msg.value = message
}
</script>
//子组件
<template>
<div>
<h1>我是子组件2</h1>
<button @click="saymimi">点我给父组件说我的秘密</button>
</div>
</template>
<script setup lang="ts">
let $emit = defineEmits(['mimi'])
const saymimi = function(){
$emit('mimi', '是邓紫棋的我的秘密啦')
}
</script>
当子组件中的saymimi
函数被调用时,会触发父组件中的tingmimi
方法,并将参数'是邓紫棋的我的秘密啦'
传递给它
defineEmits([‘mimi’])定义了子组件可以触发的一个名为mimi的事件,通过$emits(‘mimi’,'数据')触发mimi事件,将参数:’数据‘传给父组件;父组件使用自定义事件@mimi="tingmimi"来接受子组件传来的’数据‘。
三、mitt全局事件总线(兄弟间)
安装mitt
npm i mitt
在utils文件创建mitt.ts文件
import mitt from 'mitt'
const $bus = mitt()
export default $bus
在两个子组件都引入mitt文件
<template>
<div>
<h1>我是子组件1</h1>
<p>我收到了来自兄弟的信息:{{ message}}</p>
</div>
</template>
<script setup lang="ts">
import $bus from '../utils/mitt';
import {ref} from 'vue'
let message = ref('还不知道呢')
$bus.on('mimi',(msg:any)=>{
message.value = msg
})
</script>
<template>
<div>
<h1>我是子组件2</h1>
<button @click="sayborder">点我给兄弟发秘密</button>
</div>
</template>
<script setup lang="ts">
import $bus from '../utils/mitt';
const sayborder = function(){
$bus.emit('mimi',{mimi:"遗产全都给我了"})
}
</script>
四、v-model (父子组件数据同步)
相当于给子组件绑定props,同时绑定了自定义事件
需要添加update:前缀:defineEmits(['update:money'])
<template>
<div>
<h1>我是父组件</h1>
<p>我的财产:{{ money1 }}</p>
<child v-model:money = money1></child>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
let money1 = ref(122000)
</script>
<template>
<div>
<h1>我是子组件</h1>
<input type="text" v-model="value.money">
<p>父亲的钱{{ money }}</p>
<button @click="sayborder()">点我偷掉父亲的钱</button>
</div>
</template>
<script setup lang="ts">
const value = defineProps(['money'])
const $emit = defineEmits(['update:money'])
const sayborder =function(){
$emit('update:money',value.money-200)
}
</script>
五、useAttrs(父-->子)
<template>
<div>
<h1>我是父组件</h1>
<child :money = money></child>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
const money = ref(122000)
</script>
<template>
<div>
<h1>我是子组件</h1>
<p>收到了父亲的财产{{ money }}</p>
</div>
</template>
<script setup lang="ts">
import { useAttrs} from 'vue';
let $arrts = useAttrs()
let {money} = $arrts
</script>
六、ref与$parent(父-->子、子-->父)
当父组件渲染时,子组件可能还没有完成加载和渲染。因此,在父组件中直接获取子组件的数据时,子组件可能还没有准备好数据,导致获取到的是旧的数据或者undefined。例如刚开始money显示的是undefined。想要拿到组件数据前提是改组件将数据暴露出去了。
ref:父-->子
<template>
<div>
<h1>我是父组件</h1>
<child ref="mychildref"></child>
<p>原来的生活费是{{ money }}</p>
<button @click ="addmoney">点我给儿子涨生活费</button>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
const mychildref = ref()
const money = ref()
const addmoney=function(){
money.value = mychildref.value.money
mychildref.value.money += 200
}
</script>
<template>
<div>
<h1>我是子组件</h1>
<p>我今年{{ age }}岁</p>
<p>我的生活费{{ money }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const age = ref(12)
const money = ref(200)
defineExpose({
age,
money
}
</script>
$parent:子-->父
<template>
<div>
<h1>我是父组件</h1>
<p>我的财产:{{ money }}</p>
<child ></child>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import child from './child.vue';
const money = ref(122000)
defineExpose({
money
})
</script>
<template>
<div>
<h1>我是子组件</h1>
<p>父亲原来的钱{{ money1 }}</p>
<button @click="sayborder($parent)">点我偷掉父亲100块</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const money1 = ref()
const sayborder =function($parent:any){
money1.value = $parent.money
$parent.money-=100
}
</script>
七、provide与inject(爷-->孙)
使用provide和inject方法实现爷爷组件和孙子组件通信时,孙子组件修改接收到的数据会影响爷爷组件的数据,这是因为provide和inject是基于Vue的响应式系统实现的。
当爷爷组件通过provide将数据传递给后代组件时,这些数据会被Vue的响应式系统进行跟踪。当孙子组件通过inject接收到这些数据时,它们实际上是响应式的,即它们与爷爷组件中的数据建立了引用关系。
因此,当孙子组件修改接收到的数据时,实际上是直接修改了爷爷组件中的数据,这就导致了爷爷组件的数据也会发生变化。
这种影响是由于provide和inject的特性决定的,它们提供了一种方便的方式来在组件之间共享数据,但也需要注意数据的修改可能会影响到其他组件。
<template>
<div>
<h1>我是爷爷组件</h1>
<p>爷爷给孙子红包{{ money }}</p>
<child></child>
</div>
</template>
<script setup lang="ts">
import child from './child.vue';
import { provide,ref } from 'vue';
const money = ref('1000')
provide('hongbao',money)
</script>
<template>
<div>
<h1>我是孙子组件</h1>
<p>我爷爷给我红包{{ money }}</p>
<button @click="sayborder">点我看看剩多少钱</button>
</div>
</template>
<script setup lang="ts">
import { inject,ref } from 'vue';
let money = ref(inject('hongbao') as number)
const sayborder = function(){
money.value= 500
}
</script>
八、pinia
安装pinia :npm i pinia
//main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
//选项式
import {defineStore} from 'pinia'
let useInfoStore = defineStore('info',{
state:()=>{
return {
money:1000
}
},
actions:{
handle(){
this.money +=100
}
},
getter:{}
})
export default useInfoStore
//组合式
import {defineStore} from 'pinia'
import {ref} from 'vue'
let useCountStore = defineStore('Count',()=>{
let count = ref(100)
let countAdd = function(){
count.value +=100
}
return { count,countAdd}
})
export default useCountStore
组件中使用
<template>
<div>
<p>我在pinia的财产:{{ money }}</p>
<button @click="add">点我money加100</button>
</div>
</template>
<script setup lang="ts">
import useInfoStore from '../store/user'
const info = useInfoStore()
const money = info.money
const add = function(){
info.handle()
}
</script>
九、slot插槽
默认插槽
<template>
<div>
<h1>我是父组件</h1>
<hr>
<child >
<div><h1>我是solt传的</h1></div>
</child>
</div>
</template>
<script setup lang="ts">
import child from './child.vue';
</script>
<template>
<div>
<h1>我是子组件</h1>
<slot></slot>
<button >点我num加10</button>
</div>
</template>
<script setup lang="ts">
</script>
具名插槽
<template>
<div>
<h1>我是父组件</h1>
<hr>
<child >
<template v-slot:abc>
<div>
<h1>我是名字‘abc’solt传的</h1>
</div>
</template>
<template #bbb>//v-slot:可以简写成#
<div>
<h1>我是名字‘bbb’solt传的</h1>
</div>
</template>
</child>
</div>
</template>
<script setup lang="ts">
import child from './child.vue';
</script>
<template>
<div>
<h1>我是子组件</h1>
<slot name="abc"></slot>
<button >点我num加10</button>
<slot name="bbb"></slot>
</div>
</template>
<script setup lang="ts">
</script>
作用域插槽
在父组件中可以访问子组件中的数据。作用域插槽通过v-slot
指令和slot-scope
属性来实现。
<template>
<div>
<h1>我是父组件</h1>
<hr>
<child :arr =arr>
<template v-slot="{$son,$index}">
<div>
<h1>我是solt传的</h1>
<p>儿子叫{{ $son.name }}--{{ $index }}</p>
<p>儿子{{ $son.id }}岁</p>
</div>
</template>
</child>
</div>
</template>
<script setup lang="ts">
import child from './child.vue';
const arr = [{id:1,name:'a'},{id:2,name:'b'},{id:3,name:'c'}]
</script>
<template>
<div>
<h1>我是子组件</h1>
<ul>
<li v-for="(item,index) in arr " :key="index">
/*需要使用$符命名*/
<slot :$son="item" :$index="index"></slot>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
defineProps(['arr'])
</script>