Vue 一个 MVVM 框架、一个响应式的组件系统,通过把页面抽象成一个个组件来增加复用性、降低复杂性

主要特色就是数据操纵视图变化,一旦数据变化自动更新所有关联组件~

所以它的一大特性就是一个数据响应系统,当然有了数据还需要一个模板解析系统

即 HTMLParse 帮我们把数据模板生成最终的页面,但每次数据变动都重新生成 HTML 片段挂载到 DOM 性能肯定慢的没法说

所以还需要 Virtual DOM 把最少的变动应用到 DOM 上,以提升性能

基本上述三项组装到一起也就出来了我们自己的 Vue 框架 Evo

下面先介绍下 Virtual DOM

所谓的 Virtual DOM 就是用 JS 来模拟 DOM 树(因为 JS 操作比 DOM 快很多)

每次数据变动用新生成的树与之前的树做比对,计算出最终的差异补丁到真正的 DOM 树上

Vue 2.0 底层基于 Snabbdom 这个 Virtual DOM 做了优化与整合

具体可以到这里查看更多 https://github.com/snabbdom/snabbdom

这个库的主要特色是简单、模块化方便扩展与出色的性能

一个简单例子

```js
var snabbdom = require('snabbdom');
var patch = snabbdom.init([ // Init patch function with chosen modules
require('snabbdom/modules/class').default, // makes it easy to toggle classes
require('snabbdom/modules/props').default, // for setting properties on DOM elements
require('snabbdom/modules/style').default, // handles styling on elements with support for animations
require('snabbdom/modules/eventlisteners').default, // attaches event listeners
]);
var h = require('snabbdom/h').default; // helper function for creating vnodes

var container = document.getElementById('container');

var vnode = h('div#container.two.classes', {on: {click: someFn}}, [
h('span', {style: {fontWeight: 'bold'}}, 'This is bold'),
' and this is just normal text',
h('a', {props: {href: '/foo'}}, 'I\'ll take you places!')
]);
// Patch into empty DOM element – this modifies the DOM as a side effect
patch(container, vnode);

var newVnode = h('div#container.two.classes', {on: {click: anotherEventHandler}}, [
h('span', {style: {fontWeight: 'normal', fontStyle: 'italic'}}, 'This is now italic type'),
' and this is still just normal text',
h('a', {props: {href: '/bar'}}, 'I\'ll take you places!')
]);
// Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state

```

不难看出 patch 就是一个模块化的功能聚合,你也可以根据核心的 Hook 机制来提供自己的功能模块

然后通过 snabbdom/h 来创建 vnodes,最后用 patch 做更新处理

这个库的代码量不大,实现的非常灵活,有兴趣的可以读读源码,另外也建议读读这篇文章 https://github.com/livoras/blog/issues/13 以更好的了解内部原理

不过从上面的语法可以看出使用起来相当麻烦,所以我们需要一种简单的书写方式来帮我们解析成对应的语法规则

也就是要说的 HTMLParse

Vue 2.0 的 Parse 原型基于 John Resig 的 HTML Parser,这个 Parser 写的很小巧,可以到这里了解 http://ejohn.org/blog/pure-javascript-html-parser/

基本的 HTML 解析用法

```js
var results = "";

HTMLParser(html, {
start: function( tag, attrs, unary ) {
results += "<" + tag;

for ( var i = 0; i < attrs.length; i++ )
results += " " + attrs[i].name + '="' + attrs[i].escaped + '"';

results += (unary ? "/" : "") + ">";
},
end: function( tag ) {
results += "</" + tag + ">";
},
chars: function( text ) {
results += text;
},
comment: function( text ) {
results += "<!--" + text + "-->";
}
});

return results;

```

可以看出它把 HTML 解析后对应的节点数据都传入了处理函数,Vue 在它的基础上做了升级与优化处理,在拿到对应的节点数据后做一些自己的解析处理,如 分析 v-if、v-for、v-on 等属性做指令处理,也就出来了 Vue 的模板系统~

下面在说下响应系统

数据响应主要是依据 ES5 的 getter 与 setter 来做数据变化的钩子处理,比如下面

```js
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: ()=>{
// some handle
return val
},
set: newVal => {
if(newVal === val)
return
val = newVal
//some handle
}
})

```

这样取值与赋值的过程中都可以做一些我们自己的处理,比如 set 的时候我们可以判断值是否真的发生了变化,变化了可以触发我们的重新渲染函数,做虚拟 DOM 比对处理更新界面

不过说明下并不是一旦有数据变动我们就要做重新渲染,看这个例子

```js
new Vue({
template: `
<div>
<section>
<span>name:</span> {{name}}
</section>
<section>
<span>age:</span> {{age}}
</section>
<div>`,
data: {
name: 'js',
age: 24,
height: 180
}
})

setTimeout(function(){
demo.height = 181
}, 3000)
```

可以看到 height 的变动与我们的模板完全无关,如果做重渲染会造成浪费,所以 Vue 做了一个收集依赖

Vue 在第一次渲染的时候会读取需要的数据,所以它在 get 的时候做了手脚(依赖收集),后面只有依赖的数据变动才会触发重渲染

想更详细的了解数据响应的可以看看这个 https://segmentfault.com/a/1190000007334535

不过 ES5 的 setter、getter,使用与处理起来还是有些麻烦与不便

所以数据方面我选择了这个 https://github.com/nx-js/observer-util 使用 Proxy 的库做响应处理(毕竟现在不考虑兼容性~)

实现原理与上面的差不多,只不过更简单,功能更强一些~

上面就是我们主要参考的技能点,让我们加些代码把它们连起来,这样自己的框架就出来了~

最终的实现代码在这里 https://github.com/ygm125/evo

evo = easy + vue + o,快来帮我 star 吧~

下面来个例子,跑起来

```html
<div id="app">
<div :message="message">{{ message }}</div>

<a v-for="(item,index) in list" @click="popMsg(item.text)">{{index}}、{{item.text}}</a>

<my-component :message="message"></my-component>

<div v-if="first">first</div>
<div v-else>not</div>
</div>
<script src="../dist/evo.js"></script>
<script>

var Child = {
data: {
text: 'component'
},
template: '<div>A custom {{text}} {{message}}!</div>'
}

var app = new Evo({
components: {
'my-component': Child
},
el: "#app",
data: {
first: true,
message: "Hello Evo!",
list: [{
text: "Im one"
}, {
text: "Im two"
}]
},
methods: {
popMsg(msg) {
alert(msg)
}
}
})

setTimeout(function(){
app.message = 'HI'
},1000)

</script>
```

当然实现一个完整的东西还是有很多路要走的,希望大家都能越走越远,也能越走越近~

实现一个类 Vue 的 MVVM 框架的更多相关文章

  1. 对类Vue的MVVM前端库的实现

    关于实现MVVM,网上实在是太多了,本文为个人总结,结合源码以及一些别人的实现 关于双向绑定 vue 数据劫持 + 订阅 - 发布 ng 脏值检查 backbone.js 订阅-发布(这个没有使用过, ...

  2. 手写一个类SpringBoot的HTTP框架:几十行代码基于Netty搭建一个 HTTP Server

    本文已经收录进 : https://github.com/Snailclimb/netty-practical-tutorial (Netty 从入门到实战:手写 HTTP Server+RPC 框架 ...

  3. VUE的MVVM框架解析

    这篇文章主要介绍了MVVM模式中ViewModel和View.Model有什么区别?本文分别解释了它们的功能和作用,然后总结了它之间的区别,需要的朋友可以参考下 Model:很简单,就是业务逻辑相关的 ...

  4. 高并发架构系列:如何从0到1设计一个类Dubbo的RPC框架

    在过去持续分享的几十期阿里Java面试题中,几乎每次都会问到Dubbo相关问题,比如:“如何从0到1设计一个Dubbo的RPC框架”,这个问题主要考察以下几个方面: 你对RPC框架的底层原理掌握程度. ...

  5. 如何从0到1设计一个类Dubbo的RPC框架

    之前分享了如何从0到1设计一个MQ消息队列,今天谈谈"如何从0到1设计一个Dubbo的RPC框架",重点考验: 你对RPC框架的底层原理掌握程度. 以及考验你的整体RPC框架系统设 ...

  6. Vue的MVVM框架理解

    图示 只上图,请不要怪楼主懒. 这是楼主梳理后画的,因为毕竟自己画的印象深刻,更觉得香啊. 黄线: 表示View->Model, 红线: 表示Model->View 具体代码,请查看Vue ...

  7. MVVM 框架解析之双向绑定

    更好的阅读体验,点击 原文地址 MVVM 框架 近年来前端一个明显的开发趋势就是架构从传统的 MVC 模式向 MVVM 模式迁移.在传统的 MVC 下,当前前端和后端发生数据交互后会刷新整个页面,从而 ...

  8. 浅谈WPF中的MVVM框架--MVVMFoundation

    先科普一下:什么是WPF,请看下图 微软对于WPF技术的构想是很宏大的,可惜普及率不高,不过如果你要做Windows客户端开发的话WPF技术还是值得一学的. 什么是MVVM模式 简单来说它是一种高级的 ...

  9. 剖析手写Vue,你也可以手写一个MVVM框架

    剖析手写Vue,你也可以手写一个MVVM框架# 邮箱:563995050@qq.com github: https://github.com/xiaoqiuxiong 作者:肖秋雄(eddy) 温馨提 ...

随机推荐

  1. ural1019 Line Painting

    Line Painting Time limit: 2.0 secondMemory limit: 64 MB The segment of numerical axis from 0 to 109  ...

  2. PAT (Advanced Level) 1082. Read Number in Chinese (25)

    模拟题. #include<cstdio> #include<cstring> #include<cmath> #include<vector> #in ...

  3. (中等) CF 585C Alice, Bob, Oranges and Apples,矩阵+辗转相除。

    Alice and Bob decided to eat some fruit. In the kitchen they found a large bag of oranges and apples ...

  4. linux undelete

    http://www.tldp.org/HOWTO/archived/Ext2fs-Undeletion-Dir-Struct/index.html http://www.giis.co.in/deb ...

  5. Unity3d之协程自实现测试

    using UnityEngine; using System.Collections; public class TestStartCoroutine : MonoBehaviour { IEnum ...

  6. linux命令学习-2-dmesg

    DMESG NAME dmesg - print or control the kernel ring buffer(打印或者控制内核环缓冲) Usage: dmesg [options] Optio ...

  7. RabbitMQ消息队列(三):任务分发机制

    在上篇文章中,我们解决了从发送端(Producer)向接收端(Consumer)发送“Hello World”的问题.在实际的应用场景中,这是远远不够的.从本篇文章开始,我们将结合更加实际的应用场景来 ...

  8. redhat在线安装chrome浏览器

    开始的时候是参考吹尽黄沙始到金的文章http://www.cnblogs.com/effective/archive/2012/03/18/2405189.html 1.创建一个文件/etc/yum. ...

  9. 【Xilinx-Petalinux学习】-00-开始

    基于自己的ZYNQ板子,在上面运行petalinux,已经搞得稳定了,之后详细记录. 现在功能:QSPI启动u-boot和kernel,vdma.tpg.osd.vtc等IP模块在Linux下的驱动, ...

  10. java_web学习(8)会话与状态管

    HTTP简介       WEB浏览器与WEB服务器之间的一问一答的交互过程必须遵循一定的规则,这个规则就是HTTP协议.HTTP是hypertext transfer protocol(超文本传输协 ...