aoy的说明书
aooy opened this issue · 6 comments
作者:杨敬卓
转载请注明出处
目录
- 前言
- 动机
- 原理
- 使用
- 总结
前言
随着移动端的崛起,现代标准浏览器的推广,为解决浏览器兼容问题的jQuery渐渐没落。vue和react这些新的前端框架带来了完全不一样的开发体验,不再需要手动去处理dom节点,只需要关心数据层面的问题。
动机
流行的框架和库往往因为功能齐全导致体积巨大,有时我们只用到它们很少的功能,尝试去学习原理,自己实现特定功能有益于学习。
aoy深受Vue和react的影响,是使用Vue和react后,去实践写的一个简单框架。在Vue和react中,每个组件都可以有自己的数据存储容器,当父子组件或不同层级组件需要频繁大量的通信数据时,如果没有Vuex和redux这些状态管理框架,往往最后会变得一团糟。
把所有组件的数据存储在一个唯一的容器里,数据只在容器和组件之间流动。 这是aoy的设计理念。现在aoy只有最基本的功能。只有600行代码,想了解Virtual DOM和diff算法的同学可以试着去阅读源码。
原理
使用了Object.defineProperty绑定store的数据,当观察到数据改变,比较新旧数据产生的Virtual DOM,将差异应用到真实dom上。练练ps,给大家画张图。
使用
- 一个经典的列表排序例子。
//初始化aoy实例,取得store
var aoy = Aoy.init();
var store = aoy.store;
var el = aoy.el;
//数据
var userData = [
{name: 'c', age: 19, city: 'Beijin'},
{name: 'a', age: 20, city: 'Xian'},
{name: 'b', age: 12, city: 'Hangzhou'},
{name: 'd', age: 30, city: 'Wuhan'}
];
//将数据添加进store
store.add('table',{
userData: userData
});
//封装的节点函数,便于复用
function Table(childern){
return el('table',childern);
}
function Tr(childern){
return el('tr', childern);
}
function Th(txt){
return el('td', txt);
}
function Td(txt){
return el('td', txt);
}
//记录字段的排序
var sortStore = Object.create(null);
//创建组件
var mytable = aoy.createComponent({
el: document.body,
sortData: function(field,e){ //字段的排序函数
let i;
userData.sort(function(a, b){
if(i = (sortStore[field] === 'down')){
if(a[field] < b[field]) return 1;
}else{
if(a[field] > b[field]) return 1;
}
});
sortStore[field] = i?'up':'down';
this.table.userData = userData;
},
render: function(){
var trs = [
el('tr',[
el('th',{onclick: this.sortData.bind(this, 'name') },'name'),
el('th',{onclick: this.sortData.bind(this, 'age') },'age'),
el('th',{onclick: this.sortData.bind(this, 'city') },'city')
]
)
];
this.table.userData.forEach(function(v, i){
var tdName = Td(v.name);
var tdAge = Td(v.age);
var tdCity = Td(v.city);
var tr = Tr([tdName, tdAge, tdCity]);
trs.push(tr);
});
var table = Table(trs);
return table;
}
});
// 连接组件与数据,同时渲染进文档
aoy.connect(mytable,'table');
- 如果想最大化的利用dom节点,例如 ul > li *n 结构,可以给节点加上key属性。
var userData = [
{name: 'c', key: '3'},
{name: 'a', key: '1'},
{name: 'b', key: '2'},
{name: 'd', key: '4'}
];
function Li (v) {
return el('li',{ key : v.key}, v.name);
}
var list = [];
userData.forEach(function ( v ){
list.push( Li(v) );
})
function render () {
return el('ul',[ list ]);
}
Note
-
只在需要大量重绘的地方使用。
-
每个aoy实例都会初始化自己的store, 建议一个document下只实例化一个aoy。
-
在组件中使用this时,this均指向它的调用者。如果需要在调用时取得组件,可以使用bind绑定。
var myinput = aoy.createComponent({
el: document.body,
inputFn: function(){
console(this) //input
},
render: function(){
return el('Input', {oninput: this.inputFn,type: 'text' });
}
});
var myinputComponent= aoy.createComponent({
el: document.body,
inputFn: function(){
console(this) //myinputComponent
},
render: function(){
return el('Input', {oninput: this.inputFn.bind(this),type: 'text' });
}
});
- 依赖计算只绑定到最高层级, 也就是shore的key,当你修改shore的一个深层对象时,视图不会有反应。aoy并没有像vue那样为组件所调用的每一个数据做依赖计算,甚至覆盖数组的原生方法达到双向绑定的目的。这意味着优化的钥匙掌握在使用者手中,可以将深层次的数据结构拆分,也可以搭配immutable-js使用。
var aoy = Aoy.init()
var store = aoy.store
store.add('a' , {b: {text: 'this is p' }})
var myP = aoy.createComponent({
el: document.body,
render: function(){
return el('p',this.a.b.text);
}
});
aoy.connect(myP, 'a')
aoy.store.get('a').b.text = 'new' //视图不会改变
aoy.store.get('a').b ={text: 'new'} //视图更新
总结
aoy可以说是学习Vue和react原理再结合自己想法的产物,还有很多不足之处。
大神,膜拜一下,打算通读一下源码
带我一个,我也要通读一下源码
上个车
明天有时间看一下源码,我是实习生,哈哈加油
谢谢大神的项目!已通读源码,深有体会 =)
react和vue源码过于复杂,您的项目极大得帮助了像我这样想要了解web framework架构的学生
然后弱弱提一点,"shore"是个typo吧?
谢谢大神的项目!已通读源码,深有体会 =)
react和vue源码过于复杂,您的项目极大得帮助了像我这样想要了解web framework架构的学生
然后弱弱提一点,"shore"是个typo吧?
应该是笔误 store