vue3-组件之间的通信

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>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值