Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
wileam committed May 3, 2017
0 parents commit 2cb810e
Show file tree
Hide file tree
Showing 19 changed files with 588 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
26 changes: 26 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>2-way data binding demo</title>
<link rel="stylesheet" href="semantic.min.css">
<style>
.main {
margin-top: 40px;
}
</style>
</head>
<body>

<div class="ui main text container">
<h1 class="ui header">2-way data binding demo</h1>
<ul>
<li><a href="./simple.html">Simple input and div demo</a></li>
<li><a href="./todolist.html">A todo list demo</a></li>
</ul>
</div>

</body>
</html>
29 changes: 29 additions & 0 deletions js/el/Div.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
(() => {
"use strict";

const EL = Symbol('Div#EL');

class Div extends ElementBase {
constructor(el) {
super();
this[EL] = el;
}

get value() {
return this[EL].innerText
}

set value(d) {
this[EL].innerText = d.value;
this.emit('elementchange', this);
}

setValue(d) {
if (this[EL].innerText !== d.value) {
this[EL].innerText = d.value
}
}
}

window.Div = Div;
})()
39 changes: 39 additions & 0 deletions js/el/ElementBase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
(()=>{
'use strict';

const EL = Symbol('ElementBase#EL');
const DATA = Symbol('ElementBase#DATA');
const SELF_SETVALUE = Symbol('ElementBase#SELF_SETVALUE');

class ElementBase extends EventEmitter {
constructor(el) {
super();
this[EL] = el;
this[SELF_SETVALUE] = this.setValue.bind(this);
this.on('setValue', this.setValue.bind(this));
}

bind(d) {
if (this[DATA]) {
throw new Error('data has already been binded!');
}
this[DATA] = d;
d.on('datachange', this[SELF_SETVALUE]);
}

unbind(d) {
delete this[DATA];
d.off('datachange', this[SELF_SETVALUE]);
}

get value() {}

set value(d) {
this.emit('elementchange', this);
}

setValue(d) {}
}

window.ElementBase = ElementBase;
})()
30 changes: 30 additions & 0 deletions js/el/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
(() => {
"use strict";

const EL = Symbol('Input#EL');

class Input extends ElementBase {
constructor(el) {
super();
this[EL] = el;
this[EL].addEventListener('keyup', () => this.emit('elementchange', this));
}

get value() {
return this[EL].value
}

set value(d) {
this[EL].value = d;
this.emit('elementchange', this);
}

setValue(d) {
if (this[EL].value !== d.value) {
this[EL].value = d.value;
}
}
}

window.Input = Input;
})()
27 changes: 27 additions & 0 deletions js/el/Ul.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
(() => {
"use strict";

const EL = Symbol('Ul#EL');

class Ul extends ElementBase {
constructor(el) {
super();
this[EL] = el;
}
setValue(d) {
let list = '';
if( d && d.value && d.value instanceof Array ) {
for (var i = 0; i < d.value.length; i++) {
list += `<li>${d.value[i].text}</li>`
}
} else if( d && d.value && d.value instanceof Object ) {
for (var prop in d.value) {
list += `<li>${d.value[prop]}</li>`
}
}
this[EL].innerHTML = list;
}
}

window.Ul = Ul;
})()
52 changes: 52 additions & 0 deletions js/model/DataBase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
(() => {
'use strict';

const EL = Symbol('Data#EL');
const VALUE = Symbol('Data#VALUE');
const SELF_SETVALUE = Symbol('Data#SELF_SETVALUE');

class DataBase extends EventEmitter {
constructor(d) {
super();
this[VALUE] = d;
this[EL] = [];
this[SELF_SETVALUE] = this.setValue.bind(this);
}

get value() {
return this[VALUE]
}

set value(d) {
this[VALUE] = d;
this.emit('datachange', this);
}

bind(el) {
if(this[EL].indexOf(el) !== -1) {
throw new Error('this element is already binded!')
}
this[EL].push(el);
// 监听 & 赋值
el.on('elementchange', this[SELF_SETVALUE]);
}

unbind(el) {
// 解除监听
let index = this[EL].indexOf(el);
this[EL].splice(index, 1);
el.off('elementchange', this[SELF_SETVALUE]);
}

setValue(el) {
this[VALUE] = el.value;
for (var i = 0; i < this[EL].length; i++) {
if (this[EL][i] !== el) {
this[EL][i].emit('setValue', this);
}
}
}
}

window.DataBase = DataBase;
})()
11 changes: 11 additions & 0 deletions js/model/TodoList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(() => {
'use strict';

class TodoList extends DataBase {
constructor() {
super();
}
}

window.TodoList = TodoList;
})()
32 changes: 32 additions & 0 deletions js/myArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
(()=>{
'use strict';

let arrayProto = Array.prototype;
class MyArray extends Array {
constructor(...args) {
super(...args);
EventEmitter.call(this);
}
};

let methods = Object.getOwnPropertyNames(arrayProto);
methods.forEach(m => {
MyArray.prototype[m] = function (){
var _a = JSON.stringify(this);
var res = arrayProto[m].apply(this, arguments);

if(_a !== JSON.stringify(this)){
this.emit('datachange', this);
}
return res;
};
});

Object.assign(MyArray.prototype, {
on: EventEmitter.prototype.on,
off: EventEmitter.prototype.off,
emit: EventEmitter.prototype.emit
});

window.MyArray = MyArray;
})()
58 changes: 58 additions & 0 deletions js/myEventEmitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
(()=>{
'use strict';

class EventEmitter {
constructor() {
this.events = [];
}

on(event, fn) {
// registers the specified listener on the EventTarget it's called on.
if(!this.events[event]){
this.events[event] = [fn];
}else{
if(this.events[event].indexOf(fn) !== -1) {
throw new Error('binded')
}
this.events[event].push(fn);
}
}

off(event, fn) {
if( this.events[event].indexOf(fn) !== -1 ) {
let index = this.events[event].indexOf(fn);
this.events[event].splice(index, 1);
}
}

emit(event, args) {
// broadcast an event, call fn(args)
if( !this.events[event] || this.events[event].length == 0) {
return
}
for (let i = 0; i <= this.events[event].length; i++) {
if(typeof this.events[event][i] == 'function') {
this.events[event][i](args)
}
}
}
}

// TODO:

// on:
// 1. 接受外界传入的 event 和 fn
// 2. 放在中转区域,以供emit可以触发到,同一个 event 可以有多个 fn
// 3. 一个 event 是一个 array,存对应的 fn

// off:
// 1. 接受外界传入的 event 和 fn
// 2. 把 event 和 fn 的关联从中转区域删除

// emit:
// 1. 接受外界的 event 和 argvs
// 2. 从中转区域拿到已经存在的事件列表,匹配当前当前接收到的 event,拿到 对应的 fn 数组
// 3. 将自己拿到的 argvs 作为 fn 的参数,依次执行数组里的 fn

window.EventEmitter = EventEmitter;
})()
38 changes: 38 additions & 0 deletions js/myEventEmitter_es5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
(()=>{
function EventEmitter(){
this.events = [];
}

EventEmitter.prototype.on = function on(event, fn){
// registers the specified listener on the EventTarget it's called on.
if(!this.events[event]){
this.events[event] = [fn];
}else{
if(this.events[event].indexOf(fn) !== -1) {
throw new Error('binded')
}
this.events[event].push(fn);
}
}

EventEmitter.prototype.off = function off(event, fn) {
if( this.events[event].indexOf(fn) !== -1 ) {
let index = this.events[event].indexOf(fn);
this.events[event].splice(index, 1);
}
}

EventEmitter.prototype.emit = function emit(event, args) {
// broadcast an event, call fn(args)
if( !this.events[event] || this.events[event].length == 0) {
return
}
for (let i = 0; i <= this.events[event].length; i++) {
if(typeof this.events[event][i] == 'function') {
this.events[event][i](args)
}
}
}

window.EventEmitter = EventEmitter;
})()
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"scripts": {
"start": "./node_modules/.bin/hss"
},
"devDependencies": {
"http-static-server": "^0.2.3"
}
}
Loading

0 comments on commit 2cb810e

Please sign in to comment.