热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

avalon的ViewModel设想

不是有了Object.defineProperty,Proxy或Reflect,放进一个对象就new出一个ViewModel出来。只能说,它们是必要条件。我们须要将要监听的属性变成

不是有了Object.defineProperty, Proxy或Reflect,放进一个对象就new出一个ViewModel出来。只能说,它们是必要条件。我们须要将要监听的属性变成接见器属性,一切接见器属性都是共用统一套setter, getter要领。getter内里做依靠网络(不是必需的),setter里做视图革新或触发该属性的$watch回调。在此之前,我们须要完成一套观察者形式,就是github中常见的EventEmitter库:

https://github.com/Olical/Eve…

https://github.com/asyncly/Ev…

https://github.com/primus/eve…

但这些库的定阅数组都是放函数。我们须要放绑定对象,须要革新一下,而且改成$watch, $fire接口。

var EventBus = {
$watch: function (type, callback) {
var binding = callback
if (typeof callback === "function") {
binding = {
expr: type,
update: callback
}
}
var bus = this.$events
var list = bus[type]
if (!list) {
list = bus[type] = []
}
function unwatch() {
avalon.Array.remove(list, binding)
if(!list.length){
delete bus[type]
}
}
list.push(binding)
return unwatch
},
$fire: function (type, value) {
var list = this.$events[type]
if (list && lsit.length) {
for (var i = 0, obj; obj = list[i++];) {
obj.update()
}
}
}
}

然后我们再为它增加一个$id,用于标记这个VM是作用于页面某个元素上的。

var vm = avalon.define({
$id: "test",
#: 1,
bbb: 2
})

{{@#}}

我们看avalon.define的一个简朴完成:

avalon.define = function(obj) {
var vm = {}
var other = {}
for (var name in obj) {
if (typeof obj[name] !== 'function' && name.charAt(0) !== '$') {
(function (key, value) {
function get(){
//在avalon1.4,1.5中这里会举行动态依靠网络,详见这里
//https://github.com/RubyLouvre/avalon/blob/1.5/src/10%20dependency.js
return get._value
}
get._value = value
Object.defineProperty(obj, key, {
set: function (newValue) {
if(newValue !== get._value){
get._value = newValue
if(vm.$hashcode)
vm.$fire(key, newValue)
}
return newValue
},
get: get
})
})(name, obj[name])
}else{
other[name] = obj[name]
}
}
for(var name in other){
vm[name] = other
}
vm.$events = {}
vm.$hashcode = new Date - Math.random()
vm.$fire = EventBus.$fire
vm.$watch = EventBus.$watch
return avalon.vmodels[vm.$id] = vm
}

另外,你能够增加更多以$开首的属性要领,来加强它的功用。在avalon, angular等库中,$开首的属性要领都是框架自用的。avalon2的一个简朴的vm是藏了很多不可遍历的$xxx属性要领:

《avalon的ViewModel设想》

那末如何将绑定属性放进vm.$events.#数组中呢。这就要靠扫描机制。从上到下扫描。

avalon.scan = function (el, vm) {
scanNodes([el], vm)
}
function scanNodes(array, vm) {
for (var i = 0, el; el = array[i++]; ) {
switch (el.nodeType) {
case 1:
scanTag(el, vm)
break
case 3:
scanText(el, vm)
break
}
}
}
function scanTag(el, vm){
var id = el.getAttribute('ms-controller')
if(id && avalon.vmodels[id]){
var vm2 = avalon.vmodels[id]
if(vm && vm2 && vm == vm2){
vm = mergeVM(vm,vm2)
}else{
vm = vm2
}
el.removeAttribute('ms-controller')
}
var bindings = scanAttrs(el,vm)
for(var i = 0, b; b = bindings[i++];){
vm.$watch(b.expr, b) //重点
}
if(el.children && el.children.length){
scanNodes(el.children, vm)
}
}
function scanText(){
// 用正则检测是不是有花括号
// 有则转换为绑定对象
// 并举行vm.$watch
}
function scanAttrs(){
//遍历el.attributes中一切对象,看name是不是以ms-开首
}

那末如何将绑定属性放进vm.$events.#数组中呢。这就要靠扫描机制。从上到下扫描。

avalon.scan = function (el, vm) {
scanNodes([el], vm)
}
function scanNodes(array, vm) {
for (var i = 0, el; el = array[i++]; ) {
switch (el.nodeType) {
case 1:
scanTag(el, vm)
break
case 3:
scanText(el, vm)
break
}
}
}
function scanTag(el, vm){
var id = el.getAttribute('ms-controller')
if(id && avalon.vmodels[id]){
var vm2 = avalon.vmodels[id]
if(vm && vm2 && vm == vm2){
vm = mergeVM(vm,vm2)
}else{
vm = vm2
}
el.removeAttribute('ms-controller')
}
var bindings = scanAttrs(el,vm)
for(var i = 0, b; b = bindings[i++];){
vm.$watch(b.expr, b) //重点
}
if(el.children && el.children.length){
scanNodes(el.children, vm)
}
}
function scanText(){
// 用正则检测是不是有花括号
// 有则转换为绑定对象
// 并举行vm.$watch
}
function scanAttrs(){
//遍历el.attributes中一切对象,看name是不是以ms-开首
}

《avalon的ViewModel设想》

内里用到一个mergeVM要领,实在也简朴,就是将两个VM合并成一个新的VM。运用Object.getOwnPropertyDescriptor或许更新的Object.getOwnPropertyDescriptors,就可以获得一切接见器属性的定义对象,然后合成。假如是陈旧浏览器,我们能够将接见器属性放到一个叫$accessors对象上。

如今我们这个VM是很简朴的,它只支撑一重属性,假如属性的属性也是对象呢。这个我们须要将这define要领递 归一下不就行了吗?!关于数组的监控,业界盛行的要领是重写数组的大部分要领,然后再加上一些移除数组的要领。

至此,avalon内部种种观点的关联图以下:

《avalon的ViewModel设想》

from 《Javascript框架设想》第三版,敬请期待


推荐阅读
author-avatar
重羽玉婷018
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有