Vue3组件通讯

一、父传子

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

它有三个概念 stategetteraction,相当于组件中的: datacomputedmethods

// 引入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中的数据

  1. 可以直接修改:countStore.sum = 666
  2. 也可以批量修改:countStore.$patch({
      sum:999,
      school:'atguigu'
    })  
  3. 通过action进行修改,action中定义自己业务逻辑即可。
  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值