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 += 10console.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 += 10console.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",{// 存储数组 :statestate: () => {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>