原文地点:https://gmiam.com/post/evo.html
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/s…
这个库的重要特征是简朴、模块化轻易扩大与精彩的机能
一个简朴例子
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/bl… 以更好的相识内部道理
不过从上面的语法能够看出运用起来相称贫苦,所以我们须要一种简朴的誊写体式格局来帮我们剖析成对应的语法划定规矩
也就是要说的 HTMLParse
Vue 2.0 的 Parse 原型基于 John Resig 的 HTML Parser,这个 Parser 写的很玲珑,能够到这里相识 http://ejohn.org/blog/pure-ja…
基础的 HTML 剖析用法
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 来做数据变化的钩子处置惩罚,比方下面
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 比对处置惩罚更新界面
不过申明下并非一旦有数据更改我们就要做从新衬着,看这个例子
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/11…
不过 ES5 的 setter、getter,运用与处置惩罚起来照样有些贫苦与不方便
所以数据方面我挑选了这个 https://github.com/nx-js/obse… 运用 Proxy 的库做相应处置惩罚(毕竟如今不斟酌兼容性~)
完成道理与上面的差不多,只不过更简朴,功用更强一些~
上面就是我们重要参考的妙技点,让我们加些代码把它们连起来,如许本身的框架就出来了~
终究的完成代码在这里 https://github.com/ygm125/evo
evo = easy + vue + o,快来帮我 star 吧~
下面来个例子,跑起来
<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>
固然完成一个完全的东西照样有许多路要走的,愿望人人都能越走越远,也能越走越近~