Vue 2 核心原理解析与实践指南
一、Vue 2 的响应式系统
Vue 的响应式系统是其最核心的特性之一,它允许开发者以声明式的方式编写数据绑定,而无需手动操作 DOM。这一切都依赖于 Vue 的响应式系统。
1.1 数据劫持(Object.defineProperty
)
Vue 2 使用 Object.defineProperty
来实现数据的响应式。当数据发生变化时,Vue 能够自动检测到这些变化,并触发视图的更新。
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
console.log(`Getting ${key}`);
return val;
},
set: function reactiveSetter(newVal) {
console.log(`Setting ${key} to ${newVal}`);
val = newVal;
}
});
}
const data = { name: 'Vue' };
defineReactive(data, 'name', data.name);
console.log(data.name); // 输出:Getting name
data.name = 'Vue.js'; // 输出:Setting name to Vue.js
在实际的 Vue 中,defineReactive
方法会递归地应用于对象的所有属性,确保整个对象都是响应式的。
1.2 观察者模式
Vue 的响应式系统基于观察者模式。当数据发生变化时,会通知所有依赖该数据的视图更新。Vue 使用 Dep
(依赖)和 Watcher
(观察者)来实现这一机制。
Dep:每个响应式属性都有一个
Dep
实例,用于存储所有依赖该属性的Watcher
。Watcher:每个 DOM 节点或计算属性都有一个
Watcher
实例,用于监听数据的变化并触发更新。
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
class Watcher {
constructor(vm, key, cb) {
this.vm = vm;
this.key = key;
this.cb = cb;
this.value = vm[key]; // 触发 getter,添加自己到 Dep
}
update() {
const value = this.vm[this.key];
if (value !== this.value) {
this.value = value;
this.cb.call(this.vm, value);
}
}
}
const data = { name: 'Vue' };
const dep = new Dep();
Object.defineProperty(data, 'name', {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
dep.addSub(new Watcher(data, 'name', (newValue) => {
console.log(`Name changed to ${newValue}`);
}));
return data.name;
},
set: function reactiveSetter(newVal) {
data.name = newVal;
dep.notify();
}
});
data.name = 'Vue.js'; // 输出:Name changed to Vue.js
二、虚拟 DOM 与 DOM 更新
Vue 使用虚拟 DOM(Virtual DOM)来优化 DOM 操作,减少直接操作 DOM 的性能开销。
2.1 虚拟 DOM 的概念
虚拟 DOM 是真实 DOM 的 JavaScript 对象表示,它是一个轻量级的 JavaScript 对象树,用于描述页面的结构。Vue 通过比较虚拟 DOM 的变化,计算出最小的 DOM 操作来更新页面。
const vnode = {
tag: 'div',
attrs: { id: 'app' },
children: [
{ tag: 'h1', children: ['Hello, Vue!'] },
{ tag: 'p', children: ['This is a paragraph.'] }
]
};
2.2 虚拟 DOM 的渲染
Vue 使用 render
函数将虚拟 DOM 转换为真实 DOM。当数据发生变化时,Vue 会重新生成新的虚拟 DOM,并通过 diff
算法比较新旧虚拟 DOM 的差异,然后将差异应用到真实 DOM 上。
function render(vnode, container) {
if (vnode === null) {
container.innerHTML = '';
} else {
if (container.firstChild) {
updateDOM(container.firstChild, vnode);
} else {
container.appendChild(createElement(vnode));
}
}
}
function createElement(vnode) {
const el = document.createElement(vnode.tag);
if (vnode.attrs) {
Object.keys(vnode.attrs).forEach(key => {
el.setAttribute(key, vnode.attrs[key]);
});
}
vnode.children.forEach(child => {
el.appendChild(createElement(child));
});
return el;
}
function updateDOM(el, vnode) {
// 更新 DOM 属性
if (vnode.attrs) {
Object.keys(vnode.attrs).forEach(key => {
el.setAttribute(key, vnode.attrs[key]);
});
}
// 更新子节点
const children = el.childNodes;
vnode.children.forEach((child, index) => {
if (index < children.length) {
updateDOM(children[index], child);
} else {
el.appendChild(createElement(child));
}
});
// 删除多余的子节点
while (children.length > vnode.children.length) {
el.removeChild(children[children.length - 1]);
}
}
三、组件系统
Vue 的组件系统是其另一个核心特性,它允许开发者将页面拆分为可复用的组件,提高代码的可维护性和可读性。
3.1 组件的定义
组件是 Vue 的基本构建块,可以通过 Vue.extend
或 Vue.component
定义。
Vue.component('my-component', {
template: '<div>Hello, {{ name }}!</div>',
data() {
return { name: 'Vue' };
}
});
new Vue({
el: '#app'
});
3.2 组件的生命周期
Vue 组件有一个完整的生命周期钩子,允许开发者在组件的各个阶段执行自定义逻辑。
beforeCreate
:实例初始化之后,数据观测和事件配置之前。created
:实例创建完成后。beforeMount
:挂载开始之前,模板编译完成,但尚未挂载到 DOM 上。mounted
:挂载完成后。beforeUpdate
:数据更新时,虚拟 DOM 打补丁之前。updated
:虚拟 DOM 打补丁完成后。beforeDestroy
:销毁之前。destroyed
:销毁完成后。
Vue.component('my-component', {
template: '<div>Hello, {{ name }}!</div>',
data() {
return { name: 'Vue' };
},
beforeCreate() {
console.log('beforeCreate');
},
created() {
console.log('created');
},
beforeMount() {
console.log('beforeMount');
},
mounted() {
console.log('mounted');
},
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
beforeDestroy() {
console.log('beforeDestroy');
},
destroyed() {
console.log('destroyed');
}
});
四、事件处理与自定义指令
Vue 提供了强大的事件处理机制和自定义指令功能,允许开发者以声明式的方式处理用户交互和 DOM 操作。
4.1 事件处理
Vue 使用 v-on
或 @
指令绑定事件处理器。
<div id="app">
<button v-on:click="handleClick">Click me</button>
</div>
new Vue({
el: '#app',
methods: {
handleClick() {
alert('Button clicked!');
}
}
});
4.2 自定义指令
Vue 允许开发者定义自己的指令,以扩展 HTML 的功能。
Vue.directive('focus', {
// When the bound element is inserted into the DOM...
inserted(el) {
// Focus the element
el.focus();
}
});
new Vue({
el: '#app'
});
<div id="app">
<input v-focus>
</div>
- 本文标签: vue
- 本文链接: https://tp0.top/article/18