vue3 组件通信

343 阅读1分钟

一,props父传子

props 可以实现父子组件通信,props数据还是只读的!单向数据流

// 父组件
给子组件添加属性的方式传值
<HelloWorld msg="Vue" />

// 子组件接收
在使用 <script setup> 的单文件组件中,props 可以使用 defineProps() 宏来声明:
defineProps({  msg: String })

在没有使用 <script setup> 的组件中,prop 可以使用 props 选项来声明:
export default {
  props: ['msg'],  setup(props) {
    // setup() 接收 props 作为第一个参数
    console.log(props.msg)  }
}

二,子传父-自定义事件

// 子组件 在子组件内部通过emit触发事件
let $emit = defineEmits(['changeBtn'])
const handler = () => { $emit('changeBtn', '子组件数据')}

在没有使用 <script setup> 的组件中export default {
  emits: ['changeBtn'],  setup(props, ctx) {
    ctx.emit('changeBtn')  }
}


// 父组件
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  const changeBtn = (val) => {  console.log(val)}
</script>
template>  
  <HelloWorld msg="Vue" @changeBtn="changeBtn" />
</template>

三,全局事件总线-推荐使用mitt 插件

www.npmjs.com/package/mit…

// 总线 bus文件
import mitt from 'mitt';
const $bus = mitt();
export default $bus

// 兄弟组件1
<script setup>
  import $bus from '../bus/index'
  const handler = () => { $bus.emit('changeBtn', '兄弟组件数据')}
</script>
<template>  
  <h1 @click="handler">兄弟组件1</h1>
</template>

// 兄弟组件2
<script setup>
  import $bus from '../bus/index' 
  import { onMounted } from 'vue'
  onMounted(() => { $bus.on('changeBtn', (val)=> {    console.log(val)  })})
</script>
<template>
  <h1>兄弟组件2</h1>
</template>

四,v-model 父子组件数据同步

可写多个v-model

// 父组件 - 写法1
<script setup>
  import { ref } from "vue"
  import HelloWorld from "./components/HelloWorld.vue"
  const msg = ref("vue")
</script>
<template>  
  <HelloWorld v-model="msg" />
</template>

// 父组件 - 写法2
<script setup>
  import { ref } from "vue"
  import HelloWorld from "./components/HelloWorld.vue"
  const msg = ref("vue")
</script>
<template>
  <HelloWorld v-model:msg="msg" />
</template>

// 子组件
// 默认值 --     modelValue
// 1
<script setup>
  defineProps(['modelValue'])
  const $emit = defineEmits(['update:modelValue'])
  const handel = ()=> { $emit('update:modelValue',123)}
</script>
<template>
  <h1 @click="handel">{{ modelValue }}</h1>
</template>

// 2
<script setup>
  defineProps(['msg'])
  const $emit = defineEmits(['update:msg'])
  const handel = ()=> { $emit('update:msg',123)}
</script>
<template>
  <h1 @click="handel">{{ msg }}</h1>
</template>

新版>>>   defineModel
<script setup>  
 import { defineModel } from 'vue'  
 const modelValue = defineModel()
</script>


五,useAttrs

可以获取组件标签身上的属性和事件

props和useAttrs都可以获取,如果用props接收了,则useAttrs就接收不到了

// 父组件
<script setup>
  import { ref } from "vue"
  import HelloWorld from "./components/HelloWorld.vue"
  const msg = ref("vue")
  const change = () => {  alert("vue")}
</script>
<template>
  <HelloWorld type="error" :title="msg" @click="change" />
</template>

// 子组件
<script setup>
  import { useAttrs } from "vue"
  const $attrs = useAttrs()
  const props = defineProps(["title"])
</script>
<template>
  <div :="$attrs">12345678</div>
</template>

六,ref和$parent

ref可以获取真实的dom节点,可以获取到子组件实例

$parent可以在子组件内获取父组件的实例

组件内部数据是对外关闭的,想让外部访问可通过defineExpose方法对外暴露

// 父组件
<script setup>
  import { ref } from "vue"
  import HelloWorld from "./components/HelloWorld.vue"
  const msg = ref("vue")
  defineExpose({msg})
  const son = ref()
  const onChange = () => {    console.log(son)  }</script><template>  <HelloWorld ref="son" />  <div @click="onChange">按钮</div></template>

// 子组件
<script setup>
  import { ref } from "vue"
  const money = ref(10000)
  const onChange = ($parent) => { console.log($parent)}
  // 组件内部数据是对外关闭的,想让外部访问可通过defineExpose方法对外暴露
  defineExpose({money})
</script>
<template>
  <div @click="onChange($parent)">111111</div>
</template>

七,provide-inject

// 父组件
<script setup>  
  import { ref, provide } from "vue"  
  import child from "./components/HelloWorld.vue"  
  const msg = ref("vue")  
  provide("msg", msg)
</script>
<template>
  <child />
</template>

// 子组件
<template>
  <div>儿子组件</div>
  <grandson />
</template>

<script setup>
  import { inject } from "vue"  
  import grandson from "./grandson.vue"  
  const msg = inject("msg")  
  console.log("儿子组件", msg)
</script>

// 孙子组件
<template>
  <div>孙子组件</div>
</template>

<script setup>
  import { inject } from "vue"
  const msg = inject("msg")
  console.log("孙子组件", msg)
</script>

八,pinia

1,选项式 API

import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

2,组合式 API

import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() {
    count.value++
  }
  return { count, increment }
})