✨ Vue2 组件通信与事件处理深度指南
This commit is contained in:
parent
e6e280d8f1
commit
f2b0e74cd2
|
@ -8,7 +8,8 @@
|
|||
<!-- <Demo4 /> -->
|
||||
<!-- <Demo6 /> -->
|
||||
<!-- <Todo /> -->
|
||||
<Demo8 />
|
||||
<!-- <Demo8 /> -->
|
||||
<Demo9 />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -19,11 +20,12 @@
|
|||
// import Demo4 from "@/views/demo4/index.vue";
|
||||
// import Demo5 from "@/views/demo5/index.vue";
|
||||
// import Todo from "@/views/todo/index.vue";
|
||||
import Demo8 from "@/views/demo8/index.vue";
|
||||
// import Demo8 from "@/views/demo8/index.vue";
|
||||
import Demo9 from "@/views/demo9/index.vue";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
// components: { Demo1, Demo2, Demo3 },
|
||||
components: { Demo8 },
|
||||
components: { Demo9 },
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
# Vue2 组件通信与事件处理深度指南
|
||||
|
||||
## 一、组件通信核心方式
|
||||
|
||||
### 1. 父子组件通信模式
|
||||
|
||||
#### Props 向下传递
|
||||
```javascript
|
||||
// 父组件
|
||||
<Child :title="pageTitle" />
|
||||
|
||||
// 子组件
|
||||
props: {
|
||||
title: String
|
||||
}
|
||||
```
|
||||
|
||||
#### Events 向上传递
|
||||
```javascript
|
||||
// 子组件
|
||||
this.$emit('update', newValue)
|
||||
|
||||
// 父组件
|
||||
<Child @update="handleUpdate" />
|
||||
```
|
||||
|
||||
### 2. 引用直接访问
|
||||
```javascript
|
||||
// 父组件
|
||||
<Child ref="childRef" />
|
||||
|
||||
methods: {
|
||||
callChildMethod() {
|
||||
this.$refs.childRef.childMethod()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 二、事件系统高级用法
|
||||
|
||||
### 1. 原生事件绑定
|
||||
```html
|
||||
<!-- 必须添加.native修饰符 -->
|
||||
<StudentInfo @click.native="handleClick" />
|
||||
```
|
||||
|
||||
### 2. 手动事件管理
|
||||
```javascript
|
||||
// 绑定事件(推荐在mounted钩子中)
|
||||
mounted() {
|
||||
this.$refs.studenInfo.$on("getStudentName", this.getStudentName)
|
||||
}
|
||||
|
||||
// 解绑事件(必须在beforeDestroy中清理)
|
||||
beforeDestroy() {
|
||||
this.$refs.studenInfo.$off("getStudentName")
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 事件参数传递
|
||||
```javascript
|
||||
// 子组件触发时可带多个参数
|
||||
this.$emit('event-name', arg1, arg2, ...)
|
||||
|
||||
// 父组件接收所有参数
|
||||
handler(arg1, arg2, ...rest) {
|
||||
// 处理参数
|
||||
}
|
||||
```
|
||||
|
||||
## 三、最佳实践建议
|
||||
|
||||
### 1. 事件命名规范
|
||||
- 使用 kebab-case 命名(如 `student-updated`)
|
||||
- 避免与原生事件重名(添加业务前缀)
|
||||
- 语义化命名(如 `form-submitted`)
|
||||
|
||||
### 2. 安全通信模式
|
||||
```javascript
|
||||
// 添加事件存在性检查
|
||||
if (this._events['custom-event']) {
|
||||
this.$emit('custom-event', data)
|
||||
}
|
||||
|
||||
// 使用try-catch包裹可能出错的事件处理
|
||||
try {
|
||||
this.$emit('critical-action', payload)
|
||||
} catch (error) {
|
||||
console.error('事件处理失败:', error)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 性能优化方案
|
||||
```javascript
|
||||
// 防抖处理高频事件
|
||||
methods: {
|
||||
handleInput: _.debounce(function() {
|
||||
this.$emit('input-changed', this.value)
|
||||
}, 300)
|
||||
}
|
||||
```
|
||||
|
||||
## 四、高级通信场景
|
||||
|
||||
### 1. 跨级组件通信
|
||||
```javascript
|
||||
// 祖先组件
|
||||
provide() {
|
||||
return {
|
||||
appData: this.sharedData
|
||||
}
|
||||
}
|
||||
|
||||
// 后代组件
|
||||
inject: ['appData']
|
||||
```
|
||||
|
||||
### 2. 动态事件处理器
|
||||
```javascript
|
||||
// 根据状态切换处理函数
|
||||
<Child @custom-event="handlerMap[currentHandler]" />
|
||||
|
||||
data() {
|
||||
return {
|
||||
currentHandler: 'default',
|
||||
handlerMap: {
|
||||
default: this.handleDefault,
|
||||
special: this.handleSpecial
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 事件总线模式
|
||||
```javascript
|
||||
// event-bus.js
|
||||
import Vue from 'vue'
|
||||
export default new Vue()
|
||||
|
||||
// 组件A
|
||||
EventBus.$emit('data-updated', payload)
|
||||
|
||||
// 组件B
|
||||
EventBus.$on('data-updated', handler)
|
||||
```
|
||||
|
||||
## 五、常见问题解决方案
|
||||
|
||||
1. **事件未触发排查**:
|
||||
- 检查组件引用是否正确(`ref` 命名)
|
||||
- 确认事件名称完全匹配(大小写敏感)
|
||||
- 验证事件绑定时机(确保在 mounted 之后)
|
||||
|
||||
2. **内存泄漏预防**:
|
||||
```javascript
|
||||
beforeDestroy() {
|
||||
// 清除所有自定义事件监听
|
||||
this.$off()
|
||||
// 清除事件总线监听
|
||||
EventBus.$off('data-updated', this.handler)
|
||||
}
|
||||
```
|
||||
|
||||
3. **异步事件处理**:
|
||||
```javascript
|
||||
// 返回Promise的事件处理
|
||||
async handleEvent() {
|
||||
try {
|
||||
await this.$nextTick()
|
||||
const result = await this.$emitAsync('async-event')
|
||||
// 处理结果
|
||||
} catch (error) {
|
||||
// 错误处理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 六、与Vue3的对比
|
||||
|
||||
| 特性 | Vue2 | Vue3 |
|
||||
| -------- | -------------- | -------------------- |
|
||||
| 事件定义 | 隐式声明 | `emits` 选项显式声明 |
|
||||
| 原生事件 | 需要 `.native` | 自动识别 |
|
||||
| 移除API | - | 移除 `$on`, `$off` |
|
||||
| 性能 | 基于观察者 | 基于Proxy的响应式 |
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>学生姓名:{{ studenName }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-primary" @click="onEmitStudentName">
|
||||
向父组件传递学生姓名
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "StudentInfo",
|
||||
data() {
|
||||
return {
|
||||
studenName: "Bunny",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onEmitStudentName() {
|
||||
this.$emit("getStudentName", this.studenName);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<h4>
|
||||
学生姓名:
|
||||
<span class="badge text-bg-secondary"> {{ studenName }}</span>
|
||||
</h4>
|
||||
|
||||
<!-- 需要在前面加上native,否则会当成自定义事件 -->
|
||||
<StudentInfo ref="studenInfo" @click.native="showMessage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import StudentInfo from "./components/SutdentInfo.vue";
|
||||
|
||||
export default {
|
||||
name: "Demo-9",
|
||||
components: { StudentInfo },
|
||||
data() {
|
||||
return {
|
||||
studenName: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/* 获取学生名 */
|
||||
getStudentName(name, ...params) {
|
||||
console.log(name, params);
|
||||
|
||||
this.studenName = name;
|
||||
},
|
||||
|
||||
/* 点击子组件显示消息 */
|
||||
showMessage() {
|
||||
alert("点击子组件触发点击事件。。。");
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.studenInfo.$on("getStudentName", this.getStudentName);
|
||||
|
||||
// 绑定事件,只能写箭头函数,否则当前this是Vue被绑定的组件
|
||||
// this.$refs.studenInfo.$on("getStudentName", (name, ...params) => {
|
||||
// console.log(name, params);
|
||||
// this.studenName = name;
|
||||
// });
|
||||
},
|
||||
};
|
||||
</script>
|
Loading…
Reference in New Issue