提到“响应式”三个字,大家立刻想到啥?响应式布局?响应式编程?
从字面意思可以看出,具有“响应式”特征的事物会根据条件变化,使得目标自动作出对应变化。比如在“响应式布局”中,页面根据不同设备尺寸自动显示不同样式。
Vue.js 中的响应式也是一样,当数据发生变化后,使用到该数据的视图耶会相应进行自动更新。
接下来我根据个人理解,和大家一起探索下 Vue.js 中的响应式原理,如有错误,欢迎指点 ~~
一、Vue.js 响应式的使用
现在有个很简单的需求,点击页面中 “leo” 文本后,文本内容修改为“你好,前端自习课”。
我们可以直接操作 DOM,来完成这个需求:
<span id="name">leo</span>
const node = document.querySelector('#name')
node.innerText = '你好,前端自习课';
实现起来比较简单,当我们需要修改的数据有很多时(比如相同数据被多处引用),这样的操作将变得复杂。
既然说到 Vue.js,我们就来看看 Vue.js 怎么实现上面需求:
<template>
<div id="app">
<span @click="setName">{
{ name }}</span>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
name: "leo",
};
},
methods: {
setName() {
this.name = "你好,前端自习课";
},
},
};
</script>
观察上面代码,我们通过改变数据,来自动更新视图。当我们有多个地方引用这个 name
时,视图都会自动更新。
<template>
<div id="app">
<span @click="setName">{
{ name }}</span>
<span>{
{ name }}</span>
<span>{
{ name }}</span>
<span>{
{ name }}</span>
</div>
</template>
当我们使用目前主流的前端框架 Vue.js 和 React 开发业务时,只需关注页面数据如何变化,因为数据变化后,视图也会自动更新,这让我们从繁杂的 DOM 操作中解脱出来,提高开发效率。
二、回顾观察者模式
前面反复提到“通过改变数据,来自动更新视图”,换个说法就是“数据改变后,使用该数据的地方被动发生响应,更新视图”。
是不是有种熟悉的感觉?数据无需关注自身被多少对象引用,只需在数据变化时,通知到引用的对象即可,引用的对象作出响应。恩,有种观察者模式的味道?
关于观察者模式,可阅读我之前写的 《图解设计模式之观察者模式(TypeScript)》。
1. 观察者模式流程
观察者模式表示一种“一对多”的关系,n 个观察者关注 1 个被观察者,被观察者可以主动通知所有观察者。接下图:
在这张图中,粉丝想及时收到“前端自习课”最新文章,只需关注即可,“前端自习课”有新文章,会主动推送给每个粉丝。该过程中,“前端自习课”是被观察者,每位“粉丝”是观察者。
2. 观察者模式核心
观察者模式核心组成包括:n 个观察者和 1 个被观察者。这里实现一个简单观察者模式:
2.1 定义接口
// 观察目标接口
interface ISubject {
addObserver: (observer: Observer) => void; // 添加观察者
removeObserver: (observer: Observer) => void; // 移除观察者
notify: () => void; // 通知观察者
}
// 观察者接口
interface IObserver {
update: () => void;
}
2.2 实现被观察者类
// 实现被观察者类
class Subject implements ISubject {
private observers: IObserver[] = [];
public addObserver(observer: IObserver): void {
this.observers.push(observer);
}
public removeObserver(observer: IObserver): void {
const idx: number = this.observers.indexOf(observer);
~idx && this.observers.splice(idx, 1);
}
public notify(): void {
this.observers.forEach(observer => {
observer.update();
});
}
}
2.3 实现观察者类
// 实现观察者类
class Observer implements IObserver {
constructor(private name: string) { }
update(): void {
console.log(`${this.name} has been notified.`);
}
}
2.4 测试代码
function useObserver(){
const subject: ISubject = new Subject(