Merge pull request #49 from OuYancey/master

lint fix test and update some tutorial
This commit is contained in:
当耐特 2017-08-03 08:25:53 +08:00 committed by GitHub
commit 75dbccfde0
9 changed files with 408 additions and 466 deletions

View File

@ -1,68 +1,58 @@
import Omi from '../../src/index.js';
import Omi from '../../src/index.js'
class Hello extends Omi.Component {
constructor(data, renderTo) {
super(data, renderTo);
super(data, renderTo)
}
style () {
return `
h1{
color:red;
}
`;
style() {
return `
h1 {
color: red;
}
`
}
onClick(){
alert(1);
onClick() {
alert(1)
}
render() {
return `<h1 onclick="onClick(1)">Omi by {{name}}</h1>`;
return `<h1 onclick="onClick(1)">Omi by {{name}}</h1>`
}
}
var hello = Omi.render(new Hello({ name:'dntzhang'}),'body');
describe("A suite is just a function", function() {
var hello = Omi.render(new Hello({ name: 'dntzhang'}), 'body')
describe('A suite is just a function', function() {
var result = hello.node.outerHTML
it("hello omi", function() {
expect(result).toBe('<h1 omi_scoped_0="" onclick="Omi.instances[0].onClick(1)">Omi by dntzhang</h1>');
});
});
it('hello omi', function() {
expect(result).toBe('<h1 omi_scoped_0="" onclick="Omi.instances[0].onClick(1)">Omi by dntzhang</h1>')
})
})
describe("Omi.mixIndex ", function() {
describe('Omi.mixIndex ', function() {
var items = [1, 2]
Omi.mixIndex(items)
it('Omi.mixIndex', function() {
expect(JSON.stringify(items)).toBe('[{"value":1,"index":0},{"value":2,"index":1}]')
})
var items = [1,2]
Omi.mixIndex(items);
it("Omi.mixIndex", function() {
expect(JSON.stringify(items)).toBe('[{"value":1,"index":0},{"value":2,"index":1}]');
});
var items2 = [{a: 1}, {b: 2}]
Omi.mixIndex(items2)
it('Omi.mixIndex', function() {
expect(JSON.stringify(items2)).toBe('[{"a":1,"index":0},{"b":2,"index":1}]')
})
var items2 = [{a:1},{b:2}];
Omi.mixIndex(items2);
it("Omi.mixIndex", function() {
expect(JSON.stringify(items2)).toBe('[{"a":1,"index":0},{"b":2,"index":1}]');
});
var items3 = [{a: 1}, {b: 2}]
Omi.mixIndex(items3, 'myIndex')
it('Omi.mixIndex', function() {
expect(JSON.stringify(items3)).toBe('[{"a":1,"myIndex":0},{"b":2,"myIndex":1}]')
})
})
var items3 = [{a:1},{b:2}];
Omi.mixIndex(items3,"myIndex");
it("Omi.mixIndex", function() {
expect(JSON.stringify(items3)).toBe('[{"a":1,"myIndex":0},{"b":2,"myIndex":1}]');
});
});
describe('_getDataset ', function() {
hello._dataset = {}
hello._getDataset('<div data-a="a" data-b="b"></div>')
describe("_getDataset ", function() {
hello._dataset = {};
hello._getDataset('<div data-a="a" data-b="b"></div>');
it("_getDataset", function() {
expect(hello._dataset.a).toBe('a');
});
});
it('_getDataset', function() {
expect(hello._dataset.a).toBe('a')
})
})

View File

@ -1,55 +1,49 @@
import scopedEvent from '../../src/event.js';
import scopedEvent from '../../src/event.js'
describe("scopedEvent", function() {
var result2 = scopedEvent("<div onclick='adfd()' onblur='adfd()'>sfsdf </div>",1);
var result3 = scopedEvent("<div onblur='adfd'>sfsdf </div>",1);
var result = scopedEvent("<div onclick='adfd()'>sfsdf </div>",1);
it("and so is a spec", function() {
expect(result).toBe("<div onclick='Omi.instances[1].adfd()'>sfsdf </div>");
expect( scopedEvent(result)).toBe("<div onclick='Omi.instances[1].adfd()'>sfsdf </div>");
expect(result2).toBe("<div onclick='Omi.instances[1].adfd()' onblur='Omi.instances[1].adfd()'>sfsdf </div>");
expect(result3).toBe("<div onblur='Omi.instances[1].adfd(event)'>sfsdf </div>");
});
});
describe('scopedEvent', function() {
var result2 = scopedEvent("<div onclick='adfd()' onblur='adfd()'>sfsdf </div>", 1)
var result3 = scopedEvent("<div onblur='adfd'>sfsdf </div>", 1)
var result = scopedEvent("<div onclick='adfd()'>sfsdf </div>", 1)
it('and so is a spec', function() {
expect(result).toBe("<div onclick='Omi.instances[1].adfd()'>sfsdf </div>")
expect(scopedEvent(result)).toBe("<div onclick='Omi.instances[1].adfd()'>sfsdf </div>")
expect(result2).toBe("<div onclick='Omi.instances[1].adfd()' onblur='Omi.instances[1].adfd()'>sfsdf </div>")
expect(result3).toBe("<div onblur='Omi.instances[1].adfd(event)'>sfsdf </div>")
})
})
describe("scopedEvent2", function() {
describe('scopedEvent2', function() {
var result = scopedEvent("<div onclick='adfd'>sfsdf </div>", 1)
it('and so is a spec', function() {
expect(result).toBe("<div onclick='Omi.instances[1].adfd(event)'>sfsdf </div>")
})
})
var result = scopedEvent("<div onclick='adfd'>sfsdf </div>",1);
it("and so is a spec", function() {
expect(result).toBe("<div onclick='Omi.instances[1].adfd(event)'>sfsdf </div>");
describe('scopedEvent3', function() {
var result = scopedEvent("<div ontap='adfd'>sfsdf </div>", 1)
it('and so is a spec', function() {
expect(result).toBe("<div ontap='adfd'>sfsdf </div>")
})
})
});
});
describe("scopedEvent3", function() {
var result = scopedEvent("<div ontap='adfd'>sfsdf </div>",1);
it("and so is a spec", function() {
expect(result).toBe("<div ontap='adfd'>sfsdf </div>");
});
});
describe("scopedEvent4", function() {
var result = scopedEvent("<div ontap='adfd()'>sfsdf </div>",1);
it("and so is a spec", function() {
expect(result).toBe("<div ontap='adfd()'>sfsdf </div>");
});
});
//describe("jsx-like event binding", function() {
describe('scopedEvent4', function() {
var result = scopedEvent("<div ontap='adfd()'>sfsdf </div>", 1)
it('and so is a spec', function() {
expect(result).toBe("<div ontap='adfd()'>sfsdf </div>")
})
})
// describe("jsx-like event binding", function() {
//
// var result = scopedEvent("<div onclick={function(e){console.log(this)}}>sfsdf </div>",1);
// it("and so is a spec", function() {
// expect(result).toBe(`<div onclick="new Function('event', '(function(e){console.log(this)}).bind(Omi.instances[1])(event)')(event)";>sfsdf </div>`);
// });
//});
// });
//
//describe("jsx-like event binding with quote", function() {
// describe("jsx-like event binding with quote", function() {
//
// var result = scopedEvent('<div onclick={function(e){console.log("string with sigal quote \' and double quote \"")}}>sfsdf </div>',1);
// it("and so is a spec", function() {
// expect(result).toBe(`<div onclick="new Function('event', '(function(e){console.log(&quot;string with sigal quote \\&#039; and double quote &quot;&quot;)}).bind(Omi.instances[1])(event)')(event)";>sfsdf </div>`);
// });
//});
// });

View File

@ -1,12 +1,10 @@
describe('A suite is just a function', function() {
var a
describe("A suite is just a function", function() {
var a;
it('and so is a spec', function() {
a = true
it("and so is a spec", function() {
a = true;
expect(a).toBe(true);
});
});
expect(a).toBe(true)
})
})

View File

@ -1,77 +1,59 @@
import Omi from '../../src/index.js';
import Omi from '../../src/index.js'
class Hello extends Omi.Component {
render() {
return `<div><Test><div style="color:red;">abc</div></Test></div>`;
return `<div><Test><div style="color:red;">abc</div></Test></div>`
}
}
class Test extends Omi.Component {
render() {
return `<div><slot></slot>efg</div>`;
return `<div><slot></slot>efg</div>`
}
}
Omi.tag('Test',Test)
var hello = Omi.render(new Hello(),'body');
describe("slot1", function() {
Omi.tag('Test', Test)
var hello = Omi.render(new Hello(), 'body')
describe('slot1', function() {
var result = hello.node.outerHTML
it("hello omi", function() {
expect(result).toBe(`<div omi_scoped_1=""><div omi_scoped_2="" omi_scoped_test=""><div omi_scoped_2="" omi_scoped_test="" omi_scoped_1="" style="color:red;">abc</div>efg</div></div>`);
});
});
it('hello omi', function() {
expect(result).toBe(`<div omi_scoped_1=""><div omi_scoped_2="" omi_scoped_test=""><div omi_scoped_2="" omi_scoped_test="" omi_scoped_1="" style="color:red;">abc</div>efg</div></div>`)
})
})
class Hello2 extends Omi.Component {
render() {
return `<div>
return `<div>
<Test2>
<div slot-index="1" style="color:red;">abc</div>
<div slot-index="0" style="color:green;">efg</div>
</Test2>
</div>`;
</div>`
}
}
class Test2 extends Omi.Component {
render() {
return `<div>
return `<div>
<slot></slot>
<slot></slot>
</div>`;
</div>`
}
}
Omi.tag('Test2',Test2)
Omi.tag('Test2', Test2)
describe("slot2", function() {
var hello2 = Omi.render(new Hello2(),'body');
describe('slot2', function() {
var hello2 = Omi.render(new Hello2(), 'body')
var result2 = hello2.node.outerHTML
it("hello omi", function() {
it('hello omi', function() {
expect(result2).toBe(`<div omi_scoped_3="">
<div omi_scoped_4="" omi_scoped_test2="">
<div omi_scoped_4="" omi_scoped_test2="" omi_scoped_3="" slot-index="0" style="color:green;">efg</div>
<div omi_scoped_4="" omi_scoped_test2="" omi_scoped_3="" slot-index="1" style="color:red;">abc</div>
</div>
</div>`);
});
});
</div>`)
})
})

View File

@ -1,97 +1,97 @@
import assert from 'assert';
import style from '../../src/style.js';
import assert from 'assert'
import style from '../../src/style.js'
describe("scoper", function() {
describe("Attribute selector as prefix", function() {
var result = style.scoper(".active{ color:red};","[attribute]");
it("expect attribute selector prefix works well", function() {
expect(result).toBe(".active[attribute],[attribute] .active{ color:red};");
});
});
describe('scoper', function() {
describe('Attribute selector as prefix', function() {
var result = style.scoper('.active{ color:red};', '[attribute]')
it('expect attribute selector prefix works well', function() {
expect(result).toBe('.active[attribute],[attribute] .active{ color:red};')
})
})
describe("Id selector as prefix", function() {
var result = style.scoper(".active{ color:red};","#id");
it("expect id selector prefix works well", function() {
expect(result).toBe(".active#id,#id .active{ color:red};");
});
});
describe('Id selector as prefix', function() {
var result = style.scoper('.active{ color:red};', '#id')
it('expect id selector prefix works well', function() {
expect(result).toBe('.active#id,#id .active{ color:red};')
})
})
describe("Two classes", function() {
var result = style.scoper(".active,.xx{ color:red};","#id");
it("expect id selector prefix works well with two class selector", function() {
expect(result).toBe(".active#id,#id .active,.xx#id,#id .xx{ color:red};");
});
});
describe('Two classes', function() {
var result = style.scoper('.active,.xx{ color:red};', '#id')
it('expect id selector prefix works well with two class selector', function() {
expect(result).toBe('.active#id,#id .active,.xx#id,#id .xx{ color:red};')
})
})
describe("Pseudo class", function() {
var result = style.scoper(".active:hover{ color:red};","[attribute]");
it("expect pseudo class works well", function() {
expect(result).toBe(".active[attribute]:hover,[attribute] .active:hover{ color:red};");
});
});
describe('Pseudo class', function() {
var result = style.scoper('.active:hover{ color:red};', '[attribute]')
it('expect pseudo class works well', function() {
expect(result).toBe('.active[attribute]:hover,[attribute] .active:hover{ color:red};')
})
})
describe("Pseudo element", function() {
var result = style.scoper(".active::after{ color:red};","[attribute]");
it("expect pseudo element works well", function() {
expect(result).toBe(".active[attribute]::after,[attribute] .active::after{ color:red};");
});
});
describe('Pseudo element', function() {
var result = style.scoper('.active::after{ color:red};', '[attribute]')
it('expect pseudo element works well', function() {
expect(result).toBe('.active[attribute]::after,[attribute] .active::after{ color:red};')
})
})
describe("Quoted values", function() {
var result = style.scoper(".active { font-family: \"Helvetica Neue\"};","[attribute]");
it("expect quoted values works well", function() {
expect(result).toBe(".active[attribute],[attribute] .active{ font-family: \"Helvetica Neue\"};");
});
});
describe('Quoted values', function() {
var result = style.scoper('.active { font-family: "Helvetica Neue"};', '[attribute]')
it('expect quoted values works well', function() {
expect(result).toBe('.active[attribute],[attribute] .active{ font-family: "Helvetica Neue"};')
})
})
describe("Base64 values", function() {
var result = style.scoper(".watch i, .watchaa ,p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}.watch i, .watchaa ,p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}",'#xx');
it("expect quoted values works well", function() {
expect(result).toBe(".watch i#xx,#xx .watch i, .watchaa#xx,#xx .watchaa,p#xx:lang(it),#xx p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}.watch i#xx,#xx .watch i, .watchaa#xx,#xx .watchaa,p#xx:lang(it),#xx p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}");
});
});
describe('Base64 values', function() {
var result = style.scoper('.watch i, .watchaa ,p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}.watch i, .watchaa ,p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}', '#xx')
it('expect quoted values works well', function() {
expect(result).toBe('.watch i#xx,#xx .watch i, .watchaa#xx,#xx .watchaa,p#xx:lang(it),#xx p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}.watch i#xx,#xx .watch i, .watchaa#xx,#xx .watchaa,p#xx:lang(it),#xx p:lang(it){background-image: url(data:image/png;base64,iVBORw0C);}')
})
})
describe("Media queries", function() {
var rule = "@media (max-width: 600px) {\n" +
" h1 {\n" +
" font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n" +
" }" +
"}";
var expected = "@media (max-width: 600px) {\n" +
" h1#scoper-1,#scoper-1 h1{\n" +
" font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n" +
" }" +
"}";
var actual = style.scoper(rule, "#scoper-1");
it("expect media queries works well", function() {
expect(actual).toBe(expected);
});
});
describe('Media queries', function() {
var rule = '@media (max-width: 600px) {\n' +
' h1 {\n' +
' font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;\n' +
' }' +
'}'
var expected = '@media (max-width: 600px) {\n' +
' h1#scoper-1,#scoper-1 h1{\n' +
' font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;\n' +
' }' +
'}'
var actual = style.scoper(rule, '#scoper-1')
it('expect media queries works well', function() {
expect(actual).toBe(expected)
})
})
describe("Font faces", function() {
var rule = "@font-face {\n" +
describe('Font faces', function() {
var rule = '@font-face {\n' +
" font-family: 'MyWebFont';\n" +
" src: url('myfont.woff2') format('woff2');\n" +
" url('myfont.woff') format('woff');\n" +
"}";
var expected = rule;
var actual = style.scoper(rule, "#scoper-1");
it("expect font faces works well", function() {
expect(actual).toBe(expected);
});
});
'}'
var expected = rule
var actual = style.scoper(rule, '#scoper-1')
it('expect font faces works well', function() {
expect(actual).toBe(expected)
})
})
describe("Comment", function() {
var rule = "/* .item:nth-child(odd) {float: left;}*/";
var expected = '';
var actual = style.scoper(rule, "#scoper-1");
it("expect comment works well", function() {
expect(actual).toBe(expected);
});
});
describe('Comment', function() {
var rule = '/* .item:nth-child(odd) {float: left;}*/'
var expected = ''
var actual = style.scoper(rule, '#scoper-1')
it('expect comment works well', function() {
expect(actual).toBe(expected)
})
})
describe("complex test", function() {
var rule= `.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
describe('complex test', function() {
var rule = `.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
.clearfix:after{clear:both;}
.nick {
@ -140,11 +140,10 @@ font-family:proxima-nova,"Helvetica Neue",Helvetica,Roboto,PT Sans,DejaVu Sans,A
vertical-align: top;
-webkit-transform: scale(.5, .5);
transform: scale(.5, .5);
}`;
var actual = style.scoper(rule, "#cc");
it("expect complex test works well", function() {
expect(actual).toBe(expected);
});
});
});
}`
var actual = style.scoper(rule, '#cc')
it('expect complex test works well', function() {
expect(actual).toBe(expected)
})
})
})

View File

@ -1,82 +1,70 @@
// Karma configuration
// Generated on Tue Jan 03 2017 10:33:15 GMT+0800 (中国标准时间)
var webpackConfig = require('./webpack.test.config');
var webpackConfig = require('./webpack.test.config')
module.exports = function(config) {
config.set({
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'js/*.js'
],
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files to exclude
exclude: [
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'js/*.js': ['webpack']
},
// list of files / patterns to load in the browser
files: [
'js/*.js'
],
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// list of files to exclude
exclude: [
],
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'js/*.js':['webpack']
},
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity,
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity,
webpack: webpackConfig,
webpackMiddleware:{
noInfo:false
},
plugins: [
'karma-webpack',
'karma-jasmine',
'karma-chrome-launcher'
]
})
webpack: webpackConfig,
webpackMiddleware: {
noInfo: false
},
plugins: [
'karma-webpack',
'karma-jasmine',
'karma-chrome-launcher'
]
})
}

View File

@ -1,13 +1,11 @@
var path = require('path');
var webpack = require('webpack');
module.exports={
module:{
loaders:[{
test:/\.js$/,
loader:'babel',
query:{
presets:['es2015']
module.exports = {
module: {
loaders: [{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['es2015']
}
}]
}
};
}

View File

@ -1,10 +1,10 @@
## 写在前面
[Omi框架](https://github.com/AlloyTeam/omi)可以通过在组件上声明 data-* 把属性传递给子节点。
[Omi框架](https://github.com/AlloyTeam/omi)可以通过在组件上声明`data-*`把属性传递给子节点。
Omi从设计之初就是往标准的DOM标签的标准传递方式靠齐。比如
* 下划线自动转驼峰, data-page-index传到子组件就变成this.data.pageIndex
* data-xx 传递到子节点全都变成字符串如data-page-index="1"到子节点中this.data.pageIndex就是字符串"1"
* 下划线自动转驼峰,`data-page-index`传到子组件就变成 `this.data.pageIndex`
* `data-xx` 传递到子节点全都变成字符串,如`data-page-index="1"`到子节点中`this.data.pageIndex`就是字符串"1"
这样会有什么局限性和问题?如:
@ -14,7 +14,7 @@ Omi从设计之初就是往标准的DOM标签的标准传递方式靠齐。
那么支持传递javascript表达式就能解决这些痛点。
废话不多说,来看神的冒号。
废话不多说,来看神的冒号。
## 冒号标记
@ -23,73 +23,71 @@ Omi从设计之初就是往标准的DOM标签的标准传递方式靠齐。
```js
import Hello from 'hello.js'
Omi.tag('hello', Hello);
Omi.tag('hello', Hello)
class App extends Omi.Component {
render() {
return `
<div>
<hello :data-user="{ name : 'Dntzhang', favorite : 'Omi' }" ></hello>
</div>
return `
<div>
<hello :data-user="{ name : 'Dntzhang', favorite : 'Omi' }" ></hello>
</div>
`
}
}
Omi.render(new App(),"#container")
```
在data-user前面加上冒号即:data-user就代表传递的是js 表达式,够方便吧。
`data-user`前面加上冒号即`:data-user`就代表传递的是js表达式够方便吧。
然后在Hello组件内就可以直接使用。
```js
class Hello extends Omi.Component {
render() {
return `
<div>
<h1>{{user.name}} love {{user.favorite}}.</h1>
</div>
`
return `
<div>
<h1>{{user.name}} love {{user.favorite}}.</h1>
</div>
`
}
}
```
你也可以在hello组件内打印出 this.data.user 试试。
你也可以在hello组件内打印出`this.data.user`试试。
## 传递其他类型
上面的例子展示了传递JSON其他类型也支持。比如
```js
<hello :data-age="18" ></hello>
```html
<hello :data-age="18"></hello>
```
```js
<hello :data-xxx="1+1*2/3" ></hello>
```html
<hello :data-xxx="1+1*2/3"></hello>
```
```js
<hello :data-is-girl="false" ></hello>
```html
<hello :data-is-girl="false"></hello>
```
```js
<hello :data-array-test="[1,2,3]" ></hello>
```html
<hello :data-array-test="[1,2,3]"></hello>
```
当然也支持传递多个值:
```js
<hello :data-array-test="[1,2,3]" :data-is-girl="false" :data-age="18" ></hello>
```html
<hello :data-array-test="[1,2,3]" :data-is-girl="false" :data-age="18"></hello>
```
当然你也可以使用:data合并到一起
```js
<hello :data="{
arrayTest : [1,2,3],
isGirl : false,
age : 19
}"
```html
<hello
:data="{
arrayTest : [1,2,3],
isGirl : false,
age : 19
}"
/><hello>
```
@ -99,56 +97,51 @@ class Hello extends Omi.Component {
```js
class Hello extends Omi.Component {
handleClick(evt){
alert( this.data.arrayTest[0].name)
handleClick(evt) {
alert(this.data.arrayTest[0].name)
}
render() {
return `
<ul>
{{#arrayTest}}
<li onclick="handleClick">{{name}}</li>
{{/arrayTest}}
</ul>
`;
}
}
Omi.tag('hello', Hello);
class App extends Omi.Component {
render() {
return `
<div>
<hello :data-array-test="[{name:'dntzhang'},{name:'omi'},{name:'AlloyTeam'}]" ></hello>
</div>
`;
<ul>
{{#arrayTest}}
<li onclick="handleClick">{{name}}</li>
{{/arrayTest}}
</ul>
`
}
}
Omi.render(new App(),"#container");
Omi.tag('hello', Hello)
class App extends Omi.Component {
render() {
return `
<div>
<hello :data-array-test="[{name:'dntzhang'},{name:'omi'},{name:'AlloyTeam'}]" ></hello>
</div>
`
}
}
Omi.render(new App(), "#container")
```
当然,在子组件中,你也可以不使用 [mustache.js](https://github.com/janl/mustache.js)模板引擎的语法去遍历使用ES6+的姿势去遍历。
当然,在子组件中,你也可以不使用[mustache.js](https://github.com/janl/mustache.js)模板引擎的语法去遍历使用ES6+的姿势去遍历。
```js
class Hello extends Omi.Component {
render() {
return `
<ul>
${this.data.arrayTest.map(item =>
`<li>${item.name}</li>`
).join('')}
</ul>
`;
return `
<ul>
${this.data.arrayTest.map(item => `<li>${item.name}</li>`).join('')}
</ul>
`
}
}
```
这也是为什么omi提供了两个版本omi.js和omi.lite.js的原因。omi.lite.js不包含 [mustache.js](https://github.com/janl/mustache.js)模板引擎。
## 在线演示

View File

@ -4,56 +4,57 @@
当我们组件之间拥有共享的数据的时候经常需要进行组件通讯。在Omi框架里父组件传递数据给子组件非常方便
* 通过在组件上声明 data-* 或者 :data-* 传递给子节点
* 通过在组件上声明 data 或者 :data 传递给子节点 (支持复杂数据类型的映射)
* 声明 group-data 把数组里的data传给一堆组件传递支持复杂数据类型的映射
* 通过在组件上声明 `data-*` 或者 `:data-*` 传递给子节点
* 通过在组件上声明 `data` 或者 `:data` 传递给子节点(支持复杂数据类型的映射)
* 声明 `group-data` 把数组里的data传给一堆组件传递支持复杂数据类型的映射
注:上面带有冒号的是[传递javascript表达式](https://github.com/AlloyTeam/omi/blob/master/tutorial/js-expression.md)
注:上面带有冒号的是[传递javascript表达式](js-expression.md)
通过声明onXxx="xxxx"可以让子组件内执行父组件的方法。具体的如下图所示:
通过声明 `onXxx="xxxx"` 可以让子组件内执行父组件的方法。具体的如下图所示:
![](http://images2015.cnblogs.com/blog/105416/201705/105416-20170509130200394-716974903.jpg)
如果还不明白的话,那... 我就直接上代码了:
```js
class Main extends Omi.Component {
handlePageChange(index){
this.content.goto(index+1)
handlePageChange(index) {
this.content.goto(index + 1)
this.update()
}
render () {
return `<div>
<h1>Pagination Example</h1>
<content name="content"></content>
<pagination
name="pagination"
:data-total="100"
:data-page-size="10"
:data-num-edge="1"
:data-num-display="4"
on-page-change="handlePageChange"></pagination>
</div>`;
return `
<div>
<h1>Pagination Example</h1>
<content name="content"></content>
<pagination
name="pagination"
:data-total="100"
:data-page-size="10"
:data-num-edge="1"
:data-num-display="4"
on-page-change="handlePageChange">
</pagination>
</div>
`
}
}
```
上面的例子中
上面的例子中
* 父组件的render方法里通过 data-✽ 传递数据给子组件 Pagination
* 通过`on-page-change="handlePageChange"`实现子组件与父组件通讯
* 父组件的render方法里通过 `data-*` 传递数据给子组件 `Pagination`
* 通过 `on-page-change="handlePageChange"` 实现子组件与父组件通讯
详细代码可以点击: [分页例子地址](https://github.com/AlloyTeam/omi/tree/master/example/pagination)
详细代码可以点击:[分页例子地址](https://github.com/AlloyTeam/omi/tree/master/example/pagination)
当然你也可以使用event emitter / pubsub库在组件之间通讯比如这个只有 200b 的超小库[mitt](https://github.com/developit/mitt) 。但是需要注意mitt兼容到IE9+Omi兼容IE8。但是使用event emitter / pubsub库会对组件代码进行入侵所以非常不建议在基础非业务组件使用这类代码库。
虽然组件通讯非常方便,但是在真实的业务场景中,不仅仅是父子、爷孙、爷爷和堂兄、嫂子和堂弟...
onXxx="xxxx"就显得无能为力,力不从心了,各种数据传递、组件实例互操作、 emitter/pubsub或者循环依赖让代码非常难看且难以维护。所以
`onXxx="xxxx"`就显得无能为力,力不从心了,各种数据传递、组件实例互操作、 emitter/pubsub或者循环依赖让代码非常难看且难以维护。所以
Omi.Store是用来管理共享数据以及共享数据的逻辑
Omi.Store是用来管理共享数据以及共享数据的逻辑。
Omi Store使用足够简便对架构入侵性极极极小(3个极代表比极小还要小)。下面一步一步从todo的例子看下Store体系怎么使用。
@ -65,20 +66,17 @@ Omi.Store是基类我们可以继承Omi.Store来定义自己的Store比如
import Omi from 'omi'
class TodoStore extends Omi.Store {
constructor(data , isReady) {
constructor(data, isReady) {
super(isReady)
this.data = Object.assign({
items:[]
},data)
this.data = Object.assign({ items:[] }, data)
}
add(value){
add(value) {
this.data.items.push(value)
this.update()
}
clear(){
clear() {
this.data.items.length = 0
this.update()
}
@ -87,8 +85,8 @@ class TodoStore extends Omi.Store {
export default TodoStore
```
TodoStore定义了数据的基本格式和数据模型的逻辑。
比如 this.data 就是数据的基本格式:
`TodoStore` 定义了数据的基本格式和数据模型的逻辑。
比如 `this.data` 就是数据的基本格式:
```js
{
@ -105,42 +103,45 @@ add和clear就是共享数据相关的逻辑。
通过 new 关键字来使用TodoStore对象的实例。
```js
let store = new TodoStore({ /* 初始化数据 */ /* 数据是否准备好 */ })
let store = new TodoStore({ /* 初始化数据 */, /* 数据是否准备好 */ })
```
上面可以传入一些初始化配置信息store里面便包含了整个应用程序共享的状态数据以及贡献数据逻辑方法(add,clear)。
上面可以传入一些初始化配置信息store里面便包含了整个应用程序共享的状态数据以及贡献数据逻辑方法(add, clear)。
当然这些初始化配置信息可能是异步拉取的。所以有两种方法解决异步拉取store配置的问题
* 拉取数据然后new TodoStore()再Omi.render
* 先let store = new TodoStore(),再Omi.render,组件内部监听store.ready拉取数据更改store的data信息然后执行store.beReady()
* 拉取数据,然后`new TodoStore()`,再`Omi.render`
* 先`let store = new TodoStore()`,再`Omi.render`,组件内部监听`store.ready`拉取数据更改store的data信息然后执行`store.beReady()`
### 根组件注入 store
为了让组件树能够使用到 store可以通过Omi.render的第三个参数给根组件注入 store:
为了让组件树能够使用到 store可以通过`Omi.render`的第三个参数给根组件注入 store:
```js
Omi.render(new Todo(),'body',{
store: store
});
Omi.render(
new Todo(),
'body',
{ store: store }
;
```
当然ES2015已经允许你这样写了:
```js
Omi.render(new Todo(),'body',{
store
});
Omi.render(
new Todo(),
'body',
{ store }
)
```
两份代码同样的效果。
通过Omi.render注入之后在组件树的**所有组件**都可以通过 this.$store 访问到 store。
通过 `Omi.render` 注入之后,在组件树的**所有组件**都可以通过 `this.$store` 访问到 store。
### 利用 beforeRender
为什么要说beforeRender这个函数 因为通过beforeRender转换store的data到组件的data这样store的数据和组件的数据就解耦开了。
为什么要说beforeRender这个函数因为通过beforeRender转换store的data到组件的data这样store的数据和组件的数据就解耦开了。
beforeRender是生命周期的一部分。且看下面这张图:
@ -149,75 +150,76 @@ beforeRender是生命周期的一部分。且看下面这张图:
不管是实例化或者存在期间在render之前会去执行beforeRender方法。所以可以利用该方法写store的data到组件data的转换逻辑。比如
```js
import Omi from '../../src/index.js';
import List from './list.js';
import Omi from '../../src/index.js'
import List from './list.js'
Omi.tag('list', List);
Omi.tag('list', List)
class Todo extends Omi.Component {
constructor(data) {
super(data)
}
install(){
install() {
this.$store.addView(this)
}
beforeRender(){
beforeRender() {
this.data.length = this.$store.data.items.length
}
add (evt) {
add(evt) {
evt.preventDefault()
let value = this.data.text
this.data.text = ''
this.$store.add(value)
}
style () {
style() {
return `
h3 { color:red; }
button{ color:green;}
`;
h3 { color:red; }
button{ color:green;}
`
}
clear(){
clear() {
this.data.text = ''
this.$store.clear()
}
handleChange(evt){
handleChange(evt) {
this.data.text = evt.target.value
}
render () {
return `<div>
<h3>TODO</h3>
<button onclick="clear">Clear</button>
<list name="list" data="$store.data"></list>
<form onsubmit="add" >
<input type="text" onchange="handleChange" value="{{text}}" />
<button>Add #{{length}}</button>
</form>
</div>`;
render() {
return `
<div>
<h3>TODO</h3>
<button onclick="clear">Clear</button>
<list name="list" data="$store.data"></list>
<form onsubmit="add">
<input type="text" onchange="handleChange" value="{{text}}"/>
<button>Add #{{length}}</button>
</form>
</div>
`
}
}
export default Todo;
```
为什么要去写beforeRender方法因为render只会使用this.data去渲染页面而不会去使用this.$store.data所以需要把数据转移到组件的this.data下。这样组件既能使用自身的data也能使用全局放this.$store.data了不会耦合在一起。
为什么要去写`beforeRender`方法因为render只会使用`this.data`去渲染页面而不会去使用`this.$store.data`,所以需要把数据转移到组件的`this.data`下。这样组件既能使用自身的data也能使用全局放`this.$store.data`了,不会耦合在一起。
注意看上面的:
```js
install(){
install() {
this.$store.addView(this)
}
```
通过 addView 可以让 store 和 view也就是组件的实例 关联起来以后store执行update方法的时候关联的view都会自动更新
通过 `addView` 可以让 store 和 view也就是组件的实例关联起来以后store执行update方法的时候关联的view都会自动更新
再看上面的子组件声明:
@ -225,12 +227,12 @@ export default Todo;
<list name="list" data="$store.data"></list>
```
这样相当于把this.$store.data传递给了List组件。所以在List内部就不再需要写beforeRender方法转换了。
这样相当于把`this.$store.data`传递给了List组件。所以在List内部就不再需要写`beforeRender`方法转换了。
```js
class List extends Omi.Component {
render () {
return ` <ul> <li o-repeat="item in items">{{item}}</li></ul>`
render() {
return `<ul><li o-repeat="item in items">{{item}}</li></ul>`
}
}
```
@ -244,10 +246,10 @@ class List extends Omi.Component {
```js
let todoStore = new TodoStore()
setTimeout(()=>{
todoStore.data.items = ["omi","store"];
todoStore.beReady();
},2000)
setTimeout(() => {
todoStore.data.items = ["omi", "store"]
todoStore.beReady()
}, 2000)
```
上面的beReady就是代码已经准备就绪在组件内部可以监听ready方法
@ -258,28 +260,26 @@ class Todo extends Omi.Component {
super(data)
}
install(){
install() {
this.$store.addView(this)
}
installed(){
this.$store.ready(()=>this.$store.update())
installed() {
this.$store.ready(() => this.$store.update())
}
add (evt) {
add(evt) {
evt.preventDefault()
if(!this.$store.isReady){
return
}
if (!this.$store.isReady) return
let value = this.data.text
this.data.text = ''
this.$store.add(value)
}
```
可以看到上面的add方法可以通过this.$store.isReady获取组件store是否准备就绪。
可以看到上面的add方法可以通过`this.$store.isReady`获取组件store是否准备就绪。
你可以通过Omi.createStore快捷创建store。如:
你可以通过`Omi.createStore`快捷创建store。如:
```js
export default Omi.createStore({
@ -287,12 +287,12 @@ export default Omi.createStore({
items: ["omi", "store"]
},
methods: {
add: function (value) {
add: function(value) {
this.data.items.push(value)
this.update()
},
clear: function () {
clear: function() {
this.data.items.length = 0
this.update()
}
@ -300,7 +300,7 @@ export default Omi.createStore({
})
```
也支持省略Omi.createStore的形式创建store。如:
也支持省略`Omi.createStore`的形式创建store。如:
```js
export default {
@ -308,14 +308,14 @@ export default {
items: ["omi", "store"]
},
methods: {
install:function(){ },
install: function() {},
add: function (value) {
add: function(value) {
this.data.items.push(value)
this.update()
},
clear: function () {
clear: function() {
this.data.items.length = 0
this.update()
}