1、父 传 子:props
父: 传入 msg 和 school信息
<Demo msg="圣墟" school="陈东" />
子:接收 信息,可直接{{msg}} 使用
const props = defineProps(['msg','school'])
2、子传父(自定义事件)
父: 使用自定义事件xxx 和 事件触发的函数handler
<Demo msg="圣墟" school="陈东" @xxx="handler"/>
function handler(p1,p2){
console.log(p1,p2)
}
子:
定义自定义事件xxx,当点击school时触发点击事件 handler,handler 触发自定义事件,将参数 传给父组件
<template>
<div>
<h2 @click="handler">school:{{ school }}</h2>
</div>
</template>
<script setup>
import { reactive } from "vue";
const props = defineProps(['msg','school'])
let a1 = defineEmits(["xxx"]) // 定义自定义事件
function handler(){
a1("xxx",1,2,3)
}
3、全局总线通信(组件相互通信 ,mitt)
1、安装mitt
npm install --save mitt
2、新建 mitt.ts文件
// 引入 mitt插件:mitt是一个方法,返回bus对象
import mitt from "mitt";
const $bus = mitt()
export default $bus
3、发消息方
<template>
<div>
<h1>子组件1</h1>
<button @click="sendMsg"> 点我给组件传递参数</button>
</div>
</template>
<script setup>
import $bus from "../bus";
function sendMsg(){
$bus.emit('msg',{info:"我是你大哥"})
}
</script>
<style>
</style>
4、收消息方
import $bus from '../bus';
import {onMounted} from "vue"
// 组件挂载完毕后 接收兄弟组件传的数据
onMounted(() => {
$bus.on("msg",(msg) =>{
console.log(msg)
})
})
4、useAttrs获取父组件使用子组件的属性值
父:
使用子组件,并给予属性 type等
<HintButton type="primary" size ='small' :icon="Edit" title="编辑按钮" @click="handler"></HintButton>
子:通过useAttrs方法获取属性数组
<template>
<el-button type="AttrArr.type" >123</el-button>
<el-button :="AttrArr" >123</el-button>
>
</template>
<script setup lang="ts">
// 引入 useAttrs方法,获取组件传递的属性和事件
import {useAttrs} from 'vue'
let AttrArr = useAttrs();
console.log(AttrArr)
</script>
注意 useAttrs 和 props 都可以实现此功能 但 props优先级更高,当 props 获取一个值时,这个值 useAttrs 就拿不到了
5、ref & $parent
ref :可以获取真实dom节点 和 子组件的实例 vc(获取其数据和方法)
子组件
<template>
<h1>son 的钱数{{ money }}</h1>
</template>
<script setup lang="ts">
import { ref } from 'vue';
let money = ref(666)
const fly = ()=>{
console.log('i can fly')
}
// 组件内部数据默认对外关闭,别人不能访问,
// defineExpose 配置对外暴露数据
defineExpose({
money,
fly
})
</script>
<style>
</style>
父组件
<template>
<h1>father has {{ money }}</h1>
<HintButton ref="son"></HintButton>
<button @click="getMoney">点我借儿子 10块钱</button>
</template>
<script setup lang ="ts">
import HintButton from './HintButton.vue';
import { ref } from 'vue';
let money = ref(10000)
// 获取子组件的 实例VC
let son = ref()
const getMoney = ()=>{
money.value += 10
console.log(son.value)
son.value.money -= 10 // 获取 子组件数据
son.value.fly() // 调用子组件的方法
}
</script>
<style></style>
$parent:可以在 子组件内部获取 父组件的实例
子组件
注意:子组件可以被多次引用,所以可能有多个父组件,此时 获取到的父组件:哪个父组件触发了这个子组件的点击事件,参数就是哪个父组件
<template>
<h1>son 的钱数{{ money }}</h1>
<!-- ($parent) 获取父组件 实例 -->
<button @click="getMoney($parent)">点我 老爸给我10钱</button>
</template>
<script setup lang="ts">
import { ref } from 'vue';
let money = ref(666)
// 参数是父组件 VC
// 注意:子组件可以被多次引用,所以可能有多个父组件,此时 获取到的父组件:哪个父组件触发了这个子组件的点击事件,参数就是哪个父组件
const getMoney = ($parent)=>{
money.value += 10
console.log($parent)
$parent.money -= 10
}
</script>
<style>
</style>
父组件
<template>
<h1>father has {{ money }}</h1>
<HintButton ></HintButton>
</template>
<script setup lang ="ts">
import HintButton from './HintButton.vue';
import { ref } from 'vue';
let money = ref(10000)
// 对外暴露数据
defineExpose({
money
})
</script>
<style></style>
6、provide & inject(子获取父传的数据)
父组件
provide 方法 发送数据
<template>
<h1>father has {{ money }}</h1>
<HintButton ></HintButton>
</template>
<script setup lang ="ts">
import HintButton from './HintButton.vue';
import { ref ,provide} from 'vue';
let money = ref(10000)
provide("money",money.value)
</script>
<style></style>
子组件
inject方法接收数据(可修改父组件数据)
<template>
<h1>son 的钱数{{ money }}</h1>
<!-- -->
</template>
<script setup lang="ts">
import { ref,inject } from 'vue';
let money = ref(666)
console.log("儿子知道你有多少钱了",inject("money"))
</script>
<style>
</style>
7、pinia 实现仓库数据供组件调用
1、选项式
1、src下创建 store 文件夹,下创建 index.ts 总仓库
import { createPinia } from "pinia";
// 创建大仓库
let store = createPinia();
// 对外暴露仓库
export default store
2、同目录下创建 子仓库info.ts
state:存放数据
actions:定义仓库的方法,组件可以调用
getter:计算属性数据
// 定义info小仓库
import { defineStore } from "pinia";
// 第一个参数 小仓库的名字 第二个参数 小仓库配置的对象
let infoStore = defineStore("info",{
// 存储数组 :state
state: () => {
return {
count:99,
arr : [1,2,3,4,5,6]
}
},
// 定义仓库的方法
actions:{
updateInfoStore(a:number,b:number){
this.count += (a+b)
}
},
// 计算属性:数组求和
getters:{
Sum(){
let sum:any = this.arr.reduce((prev:number,next:number) =>{
return prev + next
},0)
return sum
}
}
})
// 对外暴露小仓库
export default infoStore
3、main.ts
// 引入 仓库
import store from './store'
app.use(store)
4、组件使用仓库数据 方法
<template>
<!-- 使用仓库数据 -->
<h1>{{ infoStore1.count }}</h1>
<h1>{{ infoStore1.Sum }}</h1>
<button @click="updateInfoStore">修改仓库数据</button>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// 导入 仓库对象
import infoStore from '@/store/info';
// 定义仓库对象
let infoStore1 = infoStore()
const updateInfoStore = () =>{
// 调用仓库方法
infoStore1.updateInfoStore(1,2)
}
</script>
<style>
</style>
2、组合式 写法
1、store下创建 todo.ts
import { defineStore } from "pinia";
import { computed, ref } from "vue";
// 创建小仓库
let todoStore = defineStore("todo",() =>{
let arr = [{id:1,title:'car'},{id:2,title:'bus'}]
let todos = ref(arr)
// 组合式 计算属性
const count = computed(() =>{
return arr.length
})
// 返回一个对象,属性和方法为组件所用
return {
arr,
count,
todos,
updateTodo(a:any){ // 组合式方法
this.arr.push(a)
}
}
})
export default todoStore
2、组件使用组合式
<template>
<p @click="updateTodo">{{ todo.todos }}</p>
<h1>数组的大小:{{ todo.count }}</h1>
</template>
<script setup lang="ts">
import { ref,computed } from 'vue';
// 导入 仓库对象
import todoStore from '@/store/todo';
let todo = todoStore()
const updateTodo = () =>{
let a = {id:3,title:"plan"}
todo.updateTodo(a)
}
</script>
<style>
</style>
3、总仓库 index.ts 和main.ts 同 选项式
8、插槽(父 = > 子)
1、默认插槽
父组件:
<son>
<div>我是默认插槽 </div>
</son>
子组件:son
<div>
<slot></slot> // 使用父组件的插槽内容
</div>
2、具名插槽
父组件:
<son>
<template v-slot:a> //可以用#a替换
<div>填入组件A部分的结构</div>
</template>
<template v-slot:b>//可以用#b替换
<div>填入组件B部分的结构</div>
</template>
</son>
子组件:son
<div>
<slot name="a"></slot>
<slot name="b"></slot>
</div>
</template>
3、作用域插槽
子组件数据由父组件提供,
但是子组件内部决定不了自身结构与外观(样式),由父组件决定
示例:
父组件将数组对象传给 子组件,子组件对数组进行遍历 列表展示
并把每行数据传给父组件 ,由父组件觉得样式(已经做的 green。没做的 red)
子组件
<template>
<div>
<h1>todo</h1>
<ul>
<!--组件内部遍历数组-->
<li v-for="(item,index) in todos" :key="item.id">
<!--作用域插槽将数据回传给父组件-->
<slot :$row="item" :$index="index"></slot>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
defineProps(['todos']);//接受父组件传递过来的数据
</script>
<style scoped>
</style>
父组件:
<template>
<div>
<h1>slot</h1>
<Todo :todos="todos">
<template v-slot="{$row,$index}">
<!--父组件决定子组件的结构与外观-->
<span :style="{color:$row.done?'green':'red'}">{{$row.title}}</span>
</template>
</Todo>
</div>
</template>
<script setup lang="ts">
import Todo from "./Todo.vue";
import { ref } from "vue";
//父组件内部数据
let todos = ref([
{ id: 1, title: "吃饭", done: true },
{ id: 2, title: "睡觉", done: false },
{ id: 3, title: "打豆豆", done: true },
]);
</script>
<style scoped>
</style>