>

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;
  }
});

去这里可以看到更多有代表性的示例。