1.1 前端框架的好处
最开始学习前端框架的时候(我第一个框架是 react)并不理解框架能带来什么,只是因为大家都在用框架,最实际的一个用途就是所有企业几乎都在用框架,不用框架就 out 了.随着使用的深入我逐渐理解到框架的好处:
1.2 前端框架的根本意义
简单来说,前端框架的根本意义是解决了UI 与状态同步问题。
在 vue 中我们如果要在todos中添加一条,只需要app4.todos.push({ text: '新项目' }),这时由于 Vue 内置的响应式系统会自动帮我们进行 UI 与状态的同步工作.
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
]
}
})
//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
如果我们用 JQuery 或者 JS 进行操作,免不了一大堆li.appendChild、document.createElement等 dom 操作,我们需要一长串 DOM 操作保证状态与 UI 的同步,其中一个环节出错就会导致 BUG,手动操作的缺点如下:
不管是 vue 的数据劫持、angular 的脏检测还是 React 的组件级 reRender都是帮助我们解决 ui 与状态同步问题的利器。
这也解释了Backbone作为前端框架鼻祖在之后落寞的原因,Backbone只是引入了 MVC 的思想,并没有解决 View 与 Modal 同步的问题,相比于现代的三大框架直接操作 Modal 就可以同步 UI 的特性, Backbone 仍然与 JQuery 绑定,在 View 里操作 Dom来达到同步 UI 的目的,这显然是不符合现代前端框架设计要求的。
UI 在 MVVM 中指的是 View,状态在 MVVM 中指的是 Modal,而保证 View 和 Modal 同步的是 View-Modal。
Vue 通过一个响应式系统保证了View 与 Modal的同步,由于要兼容IE,Vue 选择了 Object.defineProperty作为响应式系统的实现,但是如果不考虑 IE 用户的话,Object.defineProperty并不是一个好的选择target=https%3A%2F%2Fjuejin.im%2Fpost%2F5acd0c8a6fb9a028da7cdfaf)。
我们将用 Proxy 实现一个响应式系统。
一个响应式系统离不开发布订阅模式,因为我们需要一个 Dep保存订阅者,并在 Observer 发生变化时通知保存在 Dep 中的订阅者,让订阅者得知变化并更新视图,这样才能保证视图与状态的同步。
/**
* [subs description] 订阅器,储存订阅者,通知订阅者
* @type {Map}
*/
export default class Dep {
constructor() {
// 我们用 hash 储存订阅者
this.subs = new Map();
}
// 添加订阅者
addSub(key, sub) {
// 取出键为 key 的订阅者
const currentSub = this.subs.get(key);
// 如果能取出说明有相同的 key 的订阅者已经存在,直接添加
if (currentSub) {
currentSub.add(sub);
} else {
// 用 Set 数据结构储存,保证唯一值
this.subs.set(key, new Set([sub]));
}
}
// 通知
notify(key) {
// 触发键为 key 的订阅者们
if (this.subs.get(key)) {
this.subs.get(key).forEach(sub => {
sub.update();
});
}
}
}
我们在订阅器 Dep 中实现了一个notify方法来通知相应的订阅这们,然而notify方法到底什么时候被触发呢?
当然是当状态发生变化时,即 MVVM 中的 Modal 变化时触发通知,然而Dep 显然无法得知 Modal 是否发生了变化,因此我们需要创建一个监听者Observer来监听 Modal, 当 Modal 发生变化的时候我们就执行通知操作。
vue 基于Object.defineProperty来实现了监听者,我们用 Proxy 来实现监听者.
与Object.defineProperty监听属性不同, Proxy 可以监听(实际是代理)整个对象,因此就不需要遍历对象的属性依次监听了,但是如果对象的属性依然是个对象,那么 Proxy 也无法监听,所以我们实现了一个observify进行递归监听即可。
/**
* [Observer description] 监听器,监听对象,触发后通知订阅
* @param {[type]} obj [description] 需要被监听的对象
*/
const Observer = obj => {
const dep = new Dep();
return new Proxy(obj, {
get: function(target, key, receiver) {
// 如果订阅者存在,直接添加订阅
if (Dep.target) {
dep.addSub(key, Dep.target);
}
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver) {
// 如果对象值没有变,那么不触发下面的操作直接返回
if (Reflect.get(receiver, key) === value) {
return;
}
const res = Reflect.set(target, key, observify(value), receiver);
// 当值被触发更改的时候,触发 Dep 的通知方法
dep.notify(key);
return res;
},
});
};
/**
* 将对象转为监听对象
* @param {*} obj 要监听的对象
*/
export default function observify(obj) {
if (!isObject(obj)) {
return obj;
}
// 深度监听
Object.keys(obj).forEach(key => {
obj[key] = observify(obj[key]);
});
return Observer(obj);
}
我们目前已经解决了两个问题,一个是如何得知 Modal 发生了改变(利用监听者 Observer 监听 Modal 对象),一个是如何收集订阅者并通知其变化(利用订阅器收集订阅者,并用notify通知订阅者)。
我们目前还差一个订阅者(Watcher)
// 订阅者
export default class Watcher {
constructor(vm, exp, cb) {
this.vm = vm; // vm 是 vue 的实例
this.exp = exp; // 被订阅的数据
this.cb = cb; // 触发更新后的回调
this.value = this.get(); // 获取老数据
}
get() {
const exp = this.exp;
let value;
Dep.target = this;
if (typeof exp === 'function') {
value = exp.call(this.vm);
} else if (typeof exp === 'string') {
value = this.vm[exp];
}
Dep.target = null;
return value;
}
// 将订阅者放入待更新队列等待批量更新
update() {
pushQueue(this);
}
// 触发真正的更新操作
run() {
const val = this.get(); // 获取新数据
this.cb.call(this.vm, val, this.value);
this.value = val;
}
}
我们在上一节中实现了订阅者( Watcher),但是其中的update方法是将订阅者放入了一个待更新的队列中,而不是直接触发,原因如下:
因此这个队列需要做的是异步且去重,因此我们用 Set作为数据结构储存 Watcher 来去重,同时用Promise模拟异步更新。
// 创建异步更新队列
let queue = new Set()
// 用Promise模拟nextTick
function nextTick(cb) {
Promise.resolve().then(cb)
}
// 执行刷新队列
function flushQueue(args) {
queue.forEach(watcher => {
watcher.run()
})
// 清空
queue = new Set()
}
// 添加到队列
export default function pushQueue(watcher) {
queue.add(watcher)
// 下一个循环调用
nextTick(flushQueue)
}
我们梳理一下流程, 一个响应式系统是如何做到 UI(View)与状态(Modal)同步的?
我们首先需要监听 Modal, 本文中我们用 Proxy 来监听了 Modal 对象,因此在 Modal 对象被修改的时候我们的 Observer 就可以得知。
我们得知Modal发生变化后如何通知 View 呢?要知道,一个 Modal 的改变可能触发多个 UI 的更新,比如一个用户的用户名改变了,它的个人信息组件、通知组件等等组件中的用户名都需要改变,对于这种情况我们很容易想到利用发布订阅模式来解决,我们需要一个订阅器(Dep)来储存订阅者(Watcher),当监听到 Modal 改变时,我们只需要通知相关的订阅者进行更新即可。
那么订阅者来自哪里呢?其实每一个组件实例对应着一个订阅者(正因为一个组件实例对应一个订阅者,才能利用 Dep 通知到相应组件,不然乱套了,通知订阅者就相当于间接通知了组件)。
当订阅者得知了具体变化后它会进行相应的更新,将更新体现在 UI(View)上,至此UI 与 Modal 的同步完成了。
响应式系统虽然是 Vue 的核心概念,但是一个响应式系统并不够.
响应式系统虽然得知了数据值的变化,但是当值不能完整映射 UI 时,我们依然需要进行组件级别的 reRender,这种情况并不高效,因此 Vue 在2.0版本引入了虚拟 DOM, 虚拟 DOM进行进一步的 diff 操作可以进行细粒度更高的操作,可以保证 reReander 的下限(保证不那么慢)。
除此之外为了方便开发者,vue 内置了众多的指令,因此我们还需要一个 vue 模板解析器.
越来越多的人开始站队 Angular、Vue、React,仅仅围绕这些库或者框架进行前端技术讨论,这实在不是什么好的现象。其实我想基于我个人的经验聊下前端的演进和未来,希望可以贡献微薄的力量,消除一些我个人认为的前端社区不太好的风气。
近几年可谓是 JavaScript 的大爆炸纪元,各种框架类库层出不穷,它们给前端带来一个又一个的新思想。从以前我们用的 jQuery 直接操作 DOM,到 BackboneJS、Dojo 提供监听器的形式,在到 Ember.js、AngularJS 数据绑定的理念,再到现在的 React、Vue 虚拟 DOM 的思想。
新框架(新工具,语言),一、了解概念,把握思路,二、迅速实战,见招拆招,三、深入文档,求人不如求己,四、掌握原理,有恃无恐,五、源码分析,自立门户。如果你已经熟悉一门计算机语言,当再学习其他语言的时候,会发现他们几乎是大同小异,对比着学习,会令你事半功倍。
我曾见过很多很多人盲目地使用(前端)框架,如 React,Angular 或 Vue等等。这些框架提供了许多有意思的东西:它们支持组件化;它们有强大的社区支持;它们有很多(基于框架的)第三方库来解决问题;它们有很多(很好的)第三方组件;它们有浏览器扩展工具来帮助调试;它们适合做单页应用。
Web 技术变化得很快,而最佳技术实践也在不断发展。Uber 的 Web 平台团队开发了 Fusion.js,一个开源的 Web 框架,用于简化 Web 开发,并构建出高性能的轻量级 Web 应用程序。
要使用现代的前端框架,你需要下载开发环境和依赖,编译代码,然后在浏览器上运行。这个是好是坏?究竟是什么导致了这种不必要的复杂性?是因为我们构建的网站太复杂,还是因为框架本身就很复杂?
有一个流传较广的笑话,一个人在stackoverflow中提了一个问题,如何使用javascript实现一个数字与另外一个数字相加。最高票回答是你应该使用jQuery插件,jQuery插件可以做任何事情。 历史总是在重演,以前是jQuery,现在可能是react或vue。不同的框架有不同的应用场景,杀鸡不要用牛刀
Web框架(Web framework)是一种开发框架,用来支持动态网站、网络应用和网络服务的开发。这大多数的web框架提供了一套开发和部署网站的方式,也为web行为提供了一套通用的方法
Ionic 是一个高级的 HTML5 移动端应用框架,也是一个开发混合移动应用的前端框架,旨在让 Web 开发者更轻松地构建、测试、部署和监控跨平台应用。Ionic 基于 Angular 语法,之前一直不支持 Vue 和 React 。
最近想找一个简单的.Net下的轻量级Web框架,作为用户的本地的一个WebServer,实现同浏览器程序的一些简单交互,并调用本地服务,实现类似浏览器插件的功能。它有如下几点要求:
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!