vue3 组件通信

2024-08-01  本文已影响0人  洪锦一

Vue3 组件通信和 Vue2 的区别:

常见搭配形式

1. props

props是使用频率最高的一种通信方式,常用与 :父 ↔ 子
父传子:属性值是非函数
子传父:属性值是函数

<child :name="name"/>
let name = ref('zs')
// 子组件接收
defineProps(['name'])
// 父组件
<child :getName="getName" />
const getName= (value) => {
  console.log(value);
}

// 子组件
defineProps(['getName'])
<el-button @click="getName('我是子组件的值')">传值给父组件</el-button>

2. 自定义事件

概述:自定义事件常用于:子 => 父

// 父组件
<child @send-name="getName" />

const getName = (v1, v2) => {
  console.log(v1, v2);
}

//子组件
<el-button @click="handleSend">传值给父组件</el-button>

const $emits = defineEmits(['send-name'])

const handleSend = ()=>{
    $emits('send-name','参数1','参数2')
}

3. mitt

与消息订阅与发布(pubsub)功能类似,可以实现任意组件间通信

安装:npm i mitt

//utils/emitter.js

// 引入 mitt 
import mitt from "mitt";

// 创建 mitt
const emitter = mitt()

// 暴露 mitt
export default emitter
import emitter from "@/utils/emitter";
const handleSend = () => {
  emitter.emit('send-name', { name: '参数1' })
}
import emitter from "@/utils/emitter";
// 绑定事件
emitter.on('send-name', (obj) => {
  console.log(obj)
})

// 卸载
onUnmounted(()=>{
   emitter.off('send-name')
})
// 绑定事件
  emitter.on('abc',(value)=>{
    console.log('abc事件被触发',value)
  })
  emitter.on('xyz',(value)=>{
    console.log('xyz事件被触发',value)
  })

  setInterval(() => {
    // 触发事件
    emitter.emit('abc',666)
    emitter.emit('xyz',777)
  }, 1000);

  setTimeout(() => {
    // 清理事件
    emitter.all.clear()
  }, 3000); 

4. v-model

实现 父↔子 之间相互通信。

// 父组件
<child v-model="name" />
// v-modle 本质 上面的是下面的简写
<child :modelValue="name" @update:model-value="name = $event" />

let name = ref('my name is zs')

// 子组件 child
<input type="text" :value="modelValue" @input="emit('update:model-value',$event.target.value)">

defineProps(['modelValue'])
const emit = defineEmits(['update:model-value'])
// 父组件
<child v-model:name1="name1" v-model:name2="name2" />
let name1 = ref('zs')
let name2 = ref('ls')

// 子组件
<el-button @click="handleChange">开始传值</el-button>

defineProps(['name1', 'name2'])

const emit = defineEmits(['update:name1', 'update:name2'])

const handleChange = () => {
    emit('update:name1','zs1')
    emit('update:name2','ls1')
}

5. $attrs

$attrs用于实现当前组件的父组件,向当前组件的子组件通信(祖→孙)。
$attrs是一个对象,包含所有父组件传入的标签属性。
$attrs会自动排除props中声明的属性

// 父
<child :name1="name1" :name2="name2" :name3="name3" />
let name1 = ref('name1')
let name2 = ref('name2')
let name3 = ref('name3')
// 子
<son v-bind="$attrs" />
defineProps(['name1'])
// 孙
defineProps(['name2', 'name3'])

6. refs、parent

$refs用于 :父→子。 值为对象,包含所有被ref属性标识的DOM元素或组件实例。
$parent用于:子→父。 值为对象,当前组件的父组件实例对象。

// 父组件
<child ref="childRef" />

let childRef = ref()

const getChild = () => {
  console.log(childRef.value.age);
  console.log(childRef.value.name);
}

// 子组件
let name = ref('zs')
let age = ref(16)

defineExpose({ name, age })
// 父组件
let parentAge = ref(12)
const printName = () => {
  console.log('我是名称');
}
defineExpose({ parentAge,hanshu: printName })

// 子组件
<button @click="getParent($parent)">年龄-1</button>

const getParent = (parent) => {
    parent.hanshu()
    parent.parentAge-=1
}

7. provide、inject

实现祖孙组件直接通信
在祖先组件中通过provide配置向后代组件提供数据
在后代组件中通过inject配置来声明接收数据

// 祖组件
let name = ref('zs')
let age = ref(18)
const updateAge = () => {
  age.value += 1
}
provide('name', name)
provide('ageContent', { age, updateAge })

// 孙组件
let name = inject('name')
let { age, updateAge } = inject('ageContent')

setInterval(() => {
  updateAge()
}, 1000);

8. pinia

vue3 pinia

9. slot

// 父组件
<child title="默认插槽">
   <ul>
       <li v-for="i in 10" :key="i">{{i}}</li>
   </ul>
</child>

// 子组件
<div class="child">
    <h3>{{title}}</h3>
    <slot></slot>
</div>
defineProps(['title'])
// 父组件 v-slot: 可以简写成#
<child title="默认插槽">
  <template #c1>
    我是c1内容
  </template>
  <template v-slot:c2>
    我是c2内容
  </template>
</child>

// 子组件
<div class="child">
    <h3>{{title}}</h3>
    <slot name='c1'></slot>
    <slot name='c2'></slot>
</div>
defineProps(['title'])

数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。

// 父组件 
<div class="parent">
  <child v-slot="params">
    <ul>
      <li v-for="item in params.dataList" :key="item.age">{{item.name}}</li>
    </ul>
  </child>

  <child v-slot:default="params">
    <ol>
      <li v-for="item in params.dataList" :key="item.age">{{item.name}}</li>
    </ol>
  </child>

  <child #default="params">
    <dl>
      <dt>{{ params.title }}</dt>
      <dd v-for="item in params.dataList" :key="item.age">{{item.name}}</dd>
    </dl>
  </child>
</div>

// 子组件
<div class="child">
  <slot :dataList="dataList" title="作用域插槽"></slot>
</div>

<script setup>
 let dataList = reactive([
    { name: 'zs', age: 11 },
    { name: 'ls', age: 22 },
    { name: 'wu', age: 33 },
  ])
</script>

总结

上一篇 下一篇

猜你喜欢

热点阅读