vue-java-tutorials/vue2-tutorials/import-script/5-Vue中的数据代理.md

147 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Vue2 数据代理机制详解
## 一、核心概念
Vue2 中的数据代理是指 Vue 实例vm代理其 `data` 对象中属性的访问和修改操作。通过这种机制,我们可以直接通过 `vm.xxx` 访问 `data` 中的属性,而不需要写 `vm._data.xxx`
## 二、代码示例解析
```html
<div id="app">
Vue中的数据代理: <span>{{name}}</span>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
name: "代理..."
}
});
</script>
```
## 三、实现原理
### 1. 数据存储结构
- 原始 `data` 对象被存储在 `vm._data` 属性中
- 通过 `Object.defineProperty``data` 的属性代理到 Vue 实例上
### 2. 验证方法
```javascript
// 验证代理关系
const externalData = { name: "代理..." };
const vm = new Vue({
el: "#app",
data: externalData
});
console.log(vm._data === externalData); // true
console.log(vm.name === vm._data.name); // true
```
### 3. 代理实现机制
Vue 内部大致执行了以下操作:
```javascript
// 伪代码展示代理原理
Object.keys(data).forEach(key => {
Object.defineProperty(vm, key, {
get() {
return vm._data[key];
},
set(value) {
vm._data[key] = value;
}
});
});
```
## 四、数据流图示
```
模板访问
vm.name (代理访问)
vm._data.name (实际数据存储)
数据劫持 (响应式系统)
```
## 五、关键特性
| 特性 | 说明 | 示例 |
| ---------- | ---------------------- | ------------------------------ |
| 直接访问 | 省略 `_data` 前缀 | `vm.name` 代替 `vm._data.name` |
| 响应式绑定 | 代理属性也是响应式的 | 修改 `vm.name` 会触发视图更新 |
| 数据隔离 | `_data` 保存原始数据 | 防止直接修改破坏响应式 |
| 统一入口 | 提供一致的数据访问方式 | 简化模板和方法的编写 |
## 六、与数据劫持的关系
1. **数据代理**
- 解决的是访问便捷性问题(`vm.xxx` vs `vm._data.xxx`
- 通过 `Object.defineProperty` 实现属性转发
2. **数据劫持**
- 解决的是响应式问题(数据变化触发视图更新)
-`vm._data` 上实现,通过重写 getter/setter
3. **协作流程**
- 模板访问 `{{name}}` → 触发代理 getter
- 代理 getter 访问 `_data.name` → 触发劫持 getter
- 建立依赖收集关系
## 七、注意事项
1. **新增属性**
- 直接 `vm.newProp = value` 不会成为响应式
- 必须使用 `Vue.set` 或预先声明
2. **性能影响**
- 每个代理属性都会产生一定的内存开销
- 大型项目应考虑分模块管理数据
3. **调试技巧**
- 通过 `vm._data` 查看原始数据
- 使用 Vue Devtools 观察数据变化
4. **与 Vue3 区别**
- Vue3 使用 Proxy 实现更完善的代理
- 可以检测属性添加/删除操作
## 八、扩展应用
### 1. 自定义代理逻辑
```javascript
// 在Vue实例上添加自定义代理
created() {
Object.defineProperty(this, 'fullName', {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(value) {
const parts = value.split(' ');
this.firstName = parts[0];
this.lastName = parts[1] || '';
}
});
}
```
### 2. 代理模式应用
```javascript
// 实现组件间的数据代理
const proxyMixin = {
methods: {
proxy(prop) {
return {
get: () => this[prop],
set: (val) => this[prop] = val
};
}
}
};
```