前言
- 常网IT源码上线啦!
- 本篇录入吊打面试官专栏,希望能祝君拿下Offer一臂之力,各位看官感兴趣可移步🚶。
- 有人说面试造火箭,进去拧螺丝;其实个人觉得问的问题是项目中涉及的点 || 热门的技术栈都是很好的面试体验,不要是旁门左道冷门的知识,实际上并不会用到的。
- 接下来想分享一些自己在项目中遇到的技术选型以及问题场景。
先别急着把自己打磨成一颗光滑的鹅卵石。先花点时间,搞清楚自己到底是什么材料。是坚硬的花岗岩,还是温润的美玉。然后,再去找到那条能让你闪闪发光的赛道。每一朵花,都有自己的花期和花香。

一、前言
vue3的组件通信对比vue2做了哪些更新,且听我一一道来。
直入正文。
关于vue3对组件通信做了哪些升级?
二、事件系统的新特性
Vue3 中,所有绑定在组件上的事件默认都是原生 DOM 事件,这与 Vue2 的行为不同:
java
<Event1 @click="handler2"></Event1>
事件冒泡机制:当点击子组件内部的按钮时,事件会冒泡到根节点触发父组件绑定的事件处理器。例如以下结构:
java
// 子组件 Event1.vue
<div class="son">
<p>我是子组件1</p>
<button>点击我也执行</button>
</div>
点击按钮会触发父组件的 handler2
,因为事件会冒泡到根 <div>
元素。
还记得vue2吗?
这种写法自定义事件,可以通过.native修饰符变为原生DOM事件。
现在vue3不用了。
原生的DOM事件不管是放在标签身上、组件标签身上都是原生DOM事件
事件覆盖也一样。
当子组件通过 emit
触发同名事件时,会覆盖原生事件:
java
// 子组件中
const emit = defineEmits(['click'])
emit('click') // 这会覆盖原生 click 事件
三、全局事件总线替代方案
Vue3 移除了 $on
和 $off
API,推荐使用 mitt 库实现事件总线:
java
import mitt from 'mitt'
// 创建事件总线
const emitter = mitt()
// 发送事件
emitter.emit('eventName', payload)
// 监听事件
emitter.on('eventName', (payload) => {
// 处理事件
})
// 取消监听
emitter.off('eventName', handler)
四、v-model 的演进
Vue3 的 v-model 实现方式:
java
<Child1 v-model="value"></Child1>
等价于:
java
<Child1 :modelValue="value" @update:modelValue="newValue => value = newValue"></Child1>
Vue3 支持多个 v-model 绑定:
java
<Child1 v-model:pageNo="pageNo" v-model:pagesize="pagesize"></Child1>
Vue 3.4 引入了 defineModel
宏,简化双向绑定:
java
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>父组件Dignity的 v-model 值为: {{ model }}</div>
<button @click="update">Increment</button>
</template>
实现原理:
defineModel()
会被编译为 props 和 emits:
java
const props = defineProps({ modelValue: Number })
const emit = defineEmits(['update:modelValue'])
defineModel
是一个便利宏,其返回的值是一个 ref
。它可以像其他 ref
一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用。
响应式代理:返回的 model
实际上是一个计算属性:
java
const model = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
})
五、属性透传与组件通信
useAttrs 方法
获取未声明的 props 和事件:
java
import { useAttrs } from 'vue'
let $attrs = useAttrs()
使用 $attrs
批量传递属性:
java
<el-button :="$attrs"></el-button>
优先级规则 :已通过 defineProps
声明的属性不会出现在 $attrs
中。
子组件暴露数据:
java
let name = ref('Dignity_')
defineExpose({
name
})
父组件访问子组件:
java
const child = ref()
// 访问子组件暴露的数据
console.log(child.value.name)
子组件访问父组件:$parent
六、Pinia 状态管理
vue3的pinia相当于vue2的vuex
只有state、actions、getters
选项式 API
java
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
组合式 API
可以用到vue3的语法来配合pinia,computed就是getters,ref就是state,至于actions就是一个函数
java
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useTodoStore = defineStore('todo', () => {
const todos = ref([])
const count = computed(() => todos.value.length)
function addTodo(todo) {
todos.value.push(todo)
}
return { todos, count, addTodo }
})
七、插槽
作用域插槽
可以传递数据的插槽,子组件可以将数据回传给父组件,父组件可以决定这些回传的数据是以何种结构或者外观在子组件内部去展示!
子组件实现
java
<template>
<ul>
<li v-for="(item, index) in todos" :key="item.id">
<slot :row="item" :index="index"></slot>
</li>
</ul>
</template>
<script setup>
defineProps(["todos"])
</script>
父组件使用
java
<Test1 :todos="todos">
<template v-slot="{ row, index }">
<p :style="{ color: row.done ? 'green' : 'red' }">
{{ row.title }}--{{ index }}
</p>
</template>
</Test1>
具名插槽与默认插槽
java
<!-- 子组件 -->
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
</div>
</template>
<!-- 父组件使用 -->
<ChildComponent>
<template #header>
<h1>这是标题</h1>
</template>
<p>这是默认插槽内容</p>
</ChildComponent>
至此撒花~
后记
事件处理:优先使用 emits 明确组件通信接口
状态管理:简单场景用 reactive/ref,复杂场景用 Pinia
组件设计:
-
使用 defineProps/defineEmits 明确组件接口
-
通过 defineExpose 控制暴露内容
-
合理使用插槽增强组件灵活性
性能优化:
-
避免不必要的属性透传
-
合理使用 computed 缓存派生状态
-
对于大型列表,考虑作用域插槽的性能优势
我们在实际项目中或多或少遇到一些奇奇怪怪的问题。
自己也会对一些写法的思考,为什么不行🤔,又为什么行了?
最后,祝君能拿下满意的offer。
我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车
👍 如果对您有帮助,您的点赞是我前进的润滑剂。
以往推荐
别在傻傻分不清any void never unknown的场景啦
vue2和Vue3和React的diff算法展开说说:从原理到优化策略
玩转Vue插槽:从基础到高级应用场景(内含为何Vue 2 不支持多根节点)