Skip to content

通信

vue3

defineProps

const emitEvent = defineEmits(['emitCarousel'])
function emitCarousel(item) {
  emitEvent('emitCarousel', item)
}

父组件通过 ref 获取子组件实例,调用子组件defineExpose暴露的方法。

子组件:
const list = ref(['html','css'])
defineExpose({list})

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

const childRef = ref(null)
onMounted(()=>{
    console.log(childRef.value.list)
})

provide 用于提供可以被后代组件注入的值。

inject 注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值

import { provide, ref } from 'vue'
const val = ref(100)
function updateVal(value: number) {
  val.value -= value
}
provide('commonObj', { val, updateVal })

// 接收
import { inject } from 'vue'
const { val, updateVal } = inject('commonObj', { val: 0, updateVal: (x: number) => {} })

<div>{{ val }}</div>
<button @click="updateVal(5)">修改</button>

为注入值设置默认值:

inject('testValue', 'defaultValue');

属性透传

包含父作用域里除 class 和 style 除外的非 props 属性集合

在js中使用:

import { useAttrs } from "vue"

const attrs = useAttrs()
console.log(attrs)

在template中使用:

{{ $attrs }}

多层透传,当前组件的子组件subComp就能获取到$attrs,defineProps也能接收到透传的属性:

<subComp v-bind="$attrs" />

状态管理

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => {
    return {
      count: 0
    }
  },
  // 也可以定义为
  // state: () => ({ count: 0 })
  getters: {
    double: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++
    }
  }
})

import { useCounterStore } from '@/store/counter'
const counter = useCounterStore()
counter.$patch({
  count: counter.count + 1
})
// 或
// counter.$patch((state) => {
//   state.count = counter.count + 1
// })
// counter.increment()

适用于无直接关系的组件

npm install mitt


// eventBus.js
import mitt from 'mitt';
export default mitt();

// 组件A 发送消息
import bus from '../utils/eventBus';
bus.emit('bus-message', { username: 'xhh' });

// 组件B 监听消息
import bus from '../utils/eventBus';
onMounted(() => {
  bus.on('bus-message', (data) => {
    console.log('接收消息:', data);
  });
});
onUnmounted(() => {
  bus.off('bus-message');
  // bus.all.clear() // 解绑所有事件
});

$refs, $parent

$refs获取通过ref属性定义的组件实例:

// 父
<div @click="fn($refs)">所有带ref的组件实例</div>

function fn(refs:{[key:string]:any}) {
  for (let key in refs) {
    console.log(refs[key])
    refs[key].keywords = 'test data' // 子组件的keywords改变了
  }
}

// 子
let keywords = ref('')
defineExpose({ keywords })

alt text

$parent获取父组件实例:

// 父
let name = ref('xhh')
defineExpose({ name })


// 子
<div @click="fn($parent)">获取父</div>
function fn(parent:any) {
  parent.name = 'x-h-h' // 父组件name改变了
}

补充:

let obj = reactive({
  a: 1,
  b: ref(6)
})
console.log(obj.a) // 1

// 当访问obj.b时,底层会自动读取value属性,因为b是在obj这个响应式对象中
console.log(obj.b) // 6

都遵循同源策略:只有在相同的协议、域名和端口下,数据才能被访问。

window.addEventListener('storage', function(e) {
    console.log('监听storage变化:', e.key, e.newValue, e.oldValue)
})

import { createApp } from 'vue'
const app = createApp(App)
app.config.globalProperties.msg = 'test'

import { getCurrentInstance } from "vue"
const { proxy } = getCurrentInstance() // 使用proxy,类似于vue2的this
console.log(proxy.msg) // test

‌BroadcastChannel API‌ 是 HTML5 引入的一个 Web API,允许同一源(同一域名、协议和端口)下的多个浏览器窗口、标签页、iframe 或服务工作线程之间进行消息传递。

const sendMessage = () => {
  // 创建 BroadcastChannel 实例
  const channel = new BroadcastChannel("channelName")

  // 发送消息
  channel.postMessage("origin Message")
}

// 接收消息
const channel = new BroadcastChannel("channelName")
channel.onmessage = (event) => {
    console.log("收到的消息:", event.data)
}

vue2

props
$emit()

<child ref="child"></child>

const child = this.$refs.child
child.someMethod("调用子组件的方法")

$attrs:包含父作用域里除 class 和 style 除外的非 props 属性集合。通过 this.$attrs 获取父作用域中所有符合条件的属性集合,然后还要继续传给子组件内部的其他组件,就可以通过 v-bind="$attrs"

$listeners:包含父作用域里 .native 除外的监听事件集合。如果还要继续传给子组件内部的其他组件,就可以通过 v-on="$linteners"

// 父组件
<template>
    <child :name="name" title="123"></child>
</template
export default{
    data() {
        return {
            name: "xhh"
        }
    }
}

// 子组件
<template>
    // 继续传给孙组件
    <sun-child v-bind="$attrs"></sun-child>
</template>
export default{
    props: ["name"], // 这里可以接收,也可以不接收
    mounted(){
        // 如果props接收了 name 就是 { title: 123 },否则就是{ name: "xhh", title: 123 }
        console.log(this.$attrs)
    }
}

Vue.prototype.$bus = new Vue()

$bus.$emit()
$bus.$on()
$bus.$off()

状态管理

// 子组件
<template>
    <div>
        <slot :user="user"></slot>
    </div>
</template>
export default{
    data(){
        return {
            user: {
                name: "xhh"
            }
        }
    }
}

// 父组件
<template>
    <div>
        <child v-slot="slotProps">
            {{ slotProps.user.name }}
        </child>
    </div>
</template>