Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f2b0e74

Browse filesBrowse files
committed
✨ Vue2 组件通信与事件处理深度指南
1 parent e6e280d commit f2b0e74
Copy full SHA for f2b0e74

File tree

Expand file treeCollapse file tree

4 files changed

+269
-3
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+269
-3
lines changed

‎vue2-tutorials/single-file/demo2/src/App.vue

Copy file name to clipboardExpand all lines: vue2-tutorials/single-file/demo2/src/App.vue
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
<!-- <Demo4 /> -->
99
<!-- <Demo6 /> -->
1010
<!-- <Todo /> -->
11-
<Demo8 />
11+
<!-- <Demo8 /> -->
12+
<Demo9 />
1213
</div>
1314
</template>
1415

@@ -19,11 +20,12 @@
1920
// import Demo4 from "@/views/demo4/index.vue";
2021
// import Demo5 from "@/views/demo5/index.vue";
2122
// import Todo from "@/views/todo/index.vue";
22-
import Demo8 from "@/views/demo8/index.vue";
23+
// import Demo8 from "@/views/demo8/index.vue";
24+
import Demo9 from "@/views/demo9/index.vue";
2325
2426
export default {
2527
name: "App",
2628
// components: { Demo1, Demo2, Demo3 },
27-
components: { Demo8 },
29+
components: { Demo9 },
2830
};
2931
</script>
+186Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# Vue2 组件通信与事件处理深度指南
2+
3+
## 一、组件通信核心方式
4+
5+
### 1. 父子组件通信模式
6+
7+
#### Props 向下传递
8+
```javascript
9+
// 父组件
10+
<Child :title="pageTitle" />
11+
12+
// 子组件
13+
props: {
14+
title: String
15+
}
16+
```
17+
18+
#### Events 向上传递
19+
```javascript
20+
// 子组件
21+
this.$emit('update', newValue)
22+
23+
// 父组件
24+
<Child @update="handleUpdate" />
25+
```
26+
27+
### 2. 引用直接访问
28+
```javascript
29+
// 父组件
30+
<Child ref="childRef" />
31+
32+
methods: {
33+
callChildMethod() {
34+
this.$refs.childRef.childMethod()
35+
}
36+
}
37+
```
38+
39+
## 二、事件系统高级用法
40+
41+
### 1. 原生事件绑定
42+
```html
43+
<!-- 必须添加.native修饰符 -->
44+
<StudentInfo @click.native="handleClick" />
45+
```
46+
47+
### 2. 手动事件管理
48+
```javascript
49+
// 绑定事件(推荐在mounted钩子中)
50+
mounted() {
51+
this.$refs.studenInfo.$on("getStudentName", this.getStudentName)
52+
}
53+
54+
// 解绑事件(必须在beforeDestroy中清理)
55+
beforeDestroy() {
56+
this.$refs.studenInfo.$off("getStudentName")
57+
}
58+
```
59+
60+
### 3. 事件参数传递
61+
```javascript
62+
// 子组件触发时可带多个参数
63+
this.$emit('event-name', arg1, arg2, ...)
64+
65+
// 父组件接收所有参数
66+
handler(arg1, arg2, ...rest) {
67+
// 处理参数
68+
}
69+
```
70+
71+
## 三、最佳实践建议
72+
73+
### 1. 事件命名规范
74+
- 使用 kebab-case 命名(如 `student-updated`
75+
- 避免与原生事件重名(添加业务前缀)
76+
- 语义化命名(如 `form-submitted`
77+
78+
### 2. 安全通信模式
79+
```javascript
80+
// 添加事件存在性检查
81+
if (this._events['custom-event']) {
82+
this.$emit('custom-event', data)
83+
}
84+
85+
// 使用try-catch包裹可能出错的事件处理
86+
try {
87+
this.$emit('critical-action', payload)
88+
} catch (error) {
89+
console.error('事件处理失败:', error)
90+
}
91+
```
92+
93+
### 3. 性能优化方案
94+
```javascript
95+
// 防抖处理高频事件
96+
methods: {
97+
handleInput: _.debounce(function() {
98+
this.$emit('input-changed', this.value)
99+
}, 300)
100+
}
101+
```
102+
103+
## 四、高级通信场景
104+
105+
### 1. 跨级组件通信
106+
```javascript
107+
// 祖先组件
108+
provide() {
109+
return {
110+
appData: this.sharedData
111+
}
112+
}
113+
114+
// 后代组件
115+
inject: ['appData']
116+
```
117+
118+
### 2. 动态事件处理器
119+
```javascript
120+
// 根据状态切换处理函数
121+
<Child @custom-event="handlerMap[currentHandler]" />
122+
123+
data() {
124+
return {
125+
currentHandler: 'default',
126+
handlerMap: {
127+
default: this.handleDefault,
128+
special: this.handleSpecial
129+
}
130+
}
131+
}
132+
```
133+
134+
### 3. 事件总线模式
135+
```javascript
136+
// event-bus.js
137+
import Vue from 'vue'
138+
export default new Vue()
139+
140+
// 组件A
141+
EventBus.$emit('data-updated', payload)
142+
143+
// 组件B
144+
EventBus.$on('data-updated', handler)
145+
```
146+
147+
## 五、常见问题解决方案
148+
149+
1. **事件未触发排查**
150+
- 检查组件引用是否正确(`ref` 命名)
151+
- 确认事件名称完全匹配(大小写敏感)
152+
- 验证事件绑定时机(确保在 mounted 之后)
153+
154+
2. **内存泄漏预防**
155+
```javascript
156+
beforeDestroy() {
157+
// 清除所有自定义事件监听
158+
this.$off()
159+
// 清除事件总线监听
160+
EventBus.$off('data-updated', this.handler)
161+
}
162+
```
163+
164+
3. **异步事件处理**
165+
```javascript
166+
// 返回Promise的事件处理
167+
async handleEvent() {
168+
try {
169+
await this.$nextTick()
170+
const result = await this.$emitAsync('async-event')
171+
// 处理结果
172+
} catch (error) {
173+
// 错误处理
174+
}
175+
}
176+
```
177+
178+
## 六、与Vue3的对比
179+
180+
| 特性 | Vue2 | Vue3 |
181+
| -------- | -------------- | -------------------- |
182+
| 事件定义 | 隐式声明 | `emits` 选项显式声明 |
183+
| 原生事件 | 需要 `.native` | 自动识别 |
184+
| 移除API | - | 移除 `$on`, `$off` |
185+
| 性能 | 基于观察者 | 基于Proxy的响应式 |
186+
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<template>
2+
<div class="card">
3+
<div class="card-header">
4+
<h3>学生姓名:{{ studenName }}</h3>
5+
</div>
6+
7+
<div class="card-body">
8+
<div class="btn-group">
9+
<button class="btn btn-primary" @click="onEmitStudentName">
10+
向父组件传递学生姓名
11+
</button>
12+
</div>
13+
</div>
14+
</div>
15+
</template>
16+
17+
<script>
18+
export default {
19+
name: "StudentInfo",
20+
data() {
21+
return {
22+
studenName: "Bunny",
23+
};
24+
},
25+
methods: {
26+
onEmitStudentName() {
27+
this.$emit("getStudentName", this.studenName);
28+
},
29+
},
30+
};
31+
</script>
+47Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<template>
2+
<div class="container">
3+
<h4>
4+
学生姓名:
5+
<span class="badge text-bg-secondary"> {{ studenName }}</span>
6+
</h4>
7+
8+
<!-- 需要在前面加上native,否则会当成自定义事件 -->
9+
<StudentInfo ref="studenInfo" @click.native="showMessage" />
10+
</div>
11+
</template>
12+
13+
<script>
14+
import StudentInfo from "./components/SutdentInfo.vue";
15+
16+
export default {
17+
name: "Demo-9",
18+
components: { StudentInfo },
19+
data() {
20+
return {
21+
studenName: "",
22+
};
23+
},
24+
methods: {
25+
/* 获取学生名 */
26+
getStudentName(name, ...params) {
27+
console.log(name, params);
28+
29+
this.studenName = name;
30+
},
31+
32+
/* 点击子组件显示消息 */
33+
showMessage() {
34+
alert("点击子组件触发点击事件。。。");
35+
},
36+
},
37+
mounted() {
38+
this.$refs.studenInfo.$on("getStudentName", this.getStudentName);
39+
40+
// 绑定事件,只能写箭头函数,否则当前this是Vue被绑定的组件
41+
// this.$refs.studenInfo.$on("getStudentName", (name, ...params) => {
42+
// console.log(name, params);
43+
// this.studenName = name;
44+
// });
45+
},
46+
};
47+
</script>

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.