Overview
Exact是一个事件驱动的JavaScript框架,用于构建Web用户界面。它的核心模块提供了一个Shadow层,由Text、Element和Component共同组成,是与真实DOM层相对应的。 其中,Component支持模板、数据绑定、属性验证等高级功能,为快速构建可靠的Web用户界面提供了帮助。
每当Shadow层发生变化时,Exact都会通过ExactSkin以异步批量更新的模式将变化的内容渲染到DOM层。 ExactSkin提供了DOM操作的接口,模板的解析和渲染都依赖于ExactSkin。
Setup
在页面中先后引入ExactSkin和Exact:
<script src="./javascripts/exact-skin.js"></script>
<script src="./javascripts/exact.js"></script>
Exact探测到ExactSkin,即令Exact.Skin等于ExactSkin。
Hello World
一个简单的例子如下:
// Define a Componnet Subclass
var App = Exact.defineClass({
extend: Exact.Component,
statics: {
descriptors: ['what'], // or {what: null}, so `what` is bindable
template: '<div><h1 style="color: #0066dd;">Hello, @{ $.what }!</h1></div>'
}
});
// Create an instance
var app = Exact.Component.create(App, {what: 'World'});
// Attach to an element
app.attach(Exact.Skin.query('#app'));
我们定义了类App,它继承自Component,使用了一个简单的模板作为静态属性。模板中使用了文本模板和内嵌的单向绑定表达式(以@{ }包围)。 实例化App时,给属性`what`赋了初始值。最后,附着到页面元素上,出现"Hello, World!"的字样。
你可以打开开发者工具,在控制台中修改app.what的值,观察上面文字的变化。
上面的例子使用了声明式定义的模板,但我们也可以过程式地创建组件和元素,达到相同的效果。
var App = Exact.defineClass({
extend: Exact.Component,
statics: {
descriptors: ['what'],
template: '<div></div>'
}
});
var app = Exact.Component.create(App);
var h1 = Exact.Element.create('h1');
var text = Exact.Text.create('');
h1.style.set('color', '#0066dd');
h1.children.insert(text);
app.children.insert(h1);
app.on('changed.what', function() {
text.set('data', 'Hello, ' + app.what + '!');
});
app.save({what: 'World'}); // Or app.set('what', 'World'). It will dispatch event `changed.what`
app.attach(Exact.Skin.query('#app'));
显然,使用声明式定义的模板更为简单直观。但是,模板主要用来初始化一个组件,它的结构是相对稳定的。 如果一个组件的结构是易变的,则可以考虑在简单的初始化过后,过程式地调整组件的结构。
Composing
Exact支持组件化的设计与开发。你可以在一个父组件中方便地使用子组件,只要你在本地resources或全局Exact.RES对象上注册了子组件类, 然后在响应的标签上添加`x-type`特性来引用子组件类。下面的例子中,`x-type`之于h1相当于`type`之于input,起到了丰富内容和扩展功能的作用。
<h1 class="hello">Hello @{ $.fullName | capitalize }</h1>
<div class="app">
<h1 x-type="Hello" full-name@="$.what"></h1>
<input type="text" value="world" input+="$.onInput(event)">
</div>
var Hello = Exact.defineClass({
extend: Exact.Component,
statics: {
descriptors: ['fullName'],
resources: {
capitalize: function(value) {
if (!value) { return ''; }
return value.trim().replace(/\w+/g, function(str) {
return str[0].toUpperCase() + str.slice(1);
});
}
},
template: Exact.Skin.query('.hello')
}
});
var App = Exact.defineClass({
extend: Exact.Component,
statics: {
defaults: function() {
return {
what: 'world'
};
},
resources: {
Hello: Hello
},
template: Exact.Skin.query('.app')
},
onInput: function(event) {
this.what = event.target.value;
}
});
去这里可以看到更多有代表性的示例。