插值

文本

我们可以在模板中输出StringNumber类型的数据。

  1. <div>Hello {self.get('name')}!</div>

上述例子会建立DOM元素到组件name属性的绑定,只要组件name属性变更触发了update, DOM就会更新。

纯HTML

模板输出的数据,都会做转义来防止XSS漏洞。如果你想输出非转义html代码片段,可以将数据 赋给innerHTML属性

  1. <div innerHTML={self.get('content')}></div>

属性

使用{}语法,可以动态绑定属性值,例如:

  1. <div id={self.get('id')}></div>
  2. // 对于取值为布尔类型的属性,会将值强制转为布尔类型
  3. <input type="checkbox" checked={self.get('checked')} />

class属性

class属性既可以使用字符串赋值,也可以使用对象赋值。使用对象时,所有值为true的键名 都会被当做class属性的值。

  1. <div class="a"></div>
  2. <div class={{a: 1, b: false, c: true}}></div> // <div class="a c"></div>

style属性

style属性可以既支持字符串,又可以支持对象赋值。用对象赋值时,需要使用属性名的驼峰命名方式。

  1. <div style="color: red; font-size: 14px;"></div>
  2. <div style={{color: 'red', fontSize: '14px'}}></div>

ref属性

ref属性提供了保存组件或元素引用的能力,它的取值可以是函数或者字符串。

  1. 如果是函数,组件或元素被挂载后,该函数会被执行。对于组件,会传入组件的实例作为参数;对于DOM元素, 会传入DOM作为参数。在组件或元素被销毁时,该函数会被再次调用,传入null作为参数;
  2. 如果是字符串,则实例或者元素会绑定到this.refs[refName]下面。

因为ref是在编译时判断字符串还是函数的,所以字符串必须是字符串字面量,即:ref="name",如果写成表达式ref={"name"}则会报错

  1. <div>
  2. // 将dom赋给组件的dom属性
  3. <div ref={function(dom) { self.dom = dom; }}></div>
  4. // 将实例赋给组件的instance属性
  5. <Component ref={function(i) { self.component = i; }}></Component>
  6. <Component ref="test"></Component>
  7. </div>

对于循环渲染的时候(下面会讲如何循环渲染),我们可以使用对象保存引用

  1. var Component = self.Component;
  2. <div>
  3. <Component
  4. v-for={self.get('list')}
  5. ref={function(i) {
  6. // 使用v-for循环的key作为键名
  7. self.components[key] = i;
  8. }}
  9. name={value}
  10. ev-delete={self.delete.bind(self, key)}
  11. ></Component>
  12. </div>
  1. var Component = Intact.extend({
  2. template: '<div>{self.get("name")}' +
  3. '<button ev-click={function() {self.trigger("delete")}}>X</button>' +
  4. '</div>'
  5. });
  6. var App = Intact.extend({
  7. template: template,
  8. defaults: function() {
  9. return {
  10. list: ['JavaScript', 'PHP', 'Java']
  11. };
  12. },
  13. _init: function() {
  14. this.Component = Component;
  15. this.components = {};
  16. },
  17. delete: function(index) {
  18. // 不要直接操作元数据
  19. var list = this.get('list').slice(0);
  20. list.splice(index, 1);
  21. this.set('list', list);
  22. // 如果直接操作原数据,组件不会自动更新,需要手动更新
  23. // this.get('list').splice(index, 1);
  24. // this.update();
  25. }
  26. });
  27. window.appRef = Intact.mount(App, document.getElementById('ref'));

打开浏览器输入appRef.compoents可以看到引用对象,当你删除一个组件后,再次输入 appRef.compoents可以看到相应的引用也被置为null

删除组件或元素时,只是将引用置为null,你也可以判断参数是否存在,采用delete 操作来删除键名。

key属性

key属性用于给元素提供一个唯一的标识,在兄弟元素改变时,能够快速确定元素的增删改和移动。 在渲染列表时,虽然没有强制需要提供key属性,但为列表提供key属性是个良好的习惯。 在某些情况下,可能必须提供key属性才能达到目的。例如进行表单操作时:

  1. <div>
  2. <input v-if={self.get('step') === 1} name="name"/>
  3. <input v-else name="email" />
  4. <button ev-click={self.toggle.bind(self)}>切换input</button>
  5. </div>
  1. var App = Intact.extend({
  2. template: template,
  3. defaults: function() {
  4. return {step: 1}
  5. },
  6. toggle: function() {
  7. this.set('step', this.get('step') === 1 ? '2' : 1);
  8. }
  9. });
  10. Intact.mount(App, document.getElementById('appkey'));

可以看到,当我们往input中输入一些内容后,点击“切换input”,内容并不会删除, 这是因为底层比较两个元素时,发现是同一类元素,只是改变了元素的name属性, value属性都不存在,所以没有差异,也就不会改变。这种情况也许不是我们想要的。 此时给input设置key,则可以解决问题,因为key不同,会删除input后重建一个 新input。

  1. <div>
  2. <input key="name" v-if={self.get('step') === 1} name="name"/>
  3. <input key="email" v-else name="email" />
  4. <button ev-click={self.toggle.bind(self)}>切换input</button>
  5. </div>
  1. var App = Intact.extend({
  2. template: template,
  3. defaults: function() {
  4. return {step: 1}
  5. },
  6. toggle: function() {
  7. this.set('step', this.get('step') === 1 ? '2' : 1);
  8. }
  9. });
  10. Intact.mount(App, document.getElementById('appkeyed'));

使用JavaScript表达式

前面提到过{}中可以书写任意合法的JS表达式。下面我们给出几个例子说明下

JS表达式就是可以作为右值的式子,简单地说:能够赋给另一个变量的式子

  1. <div>{self.get('i') + 1}</div>
  2. <div>{self.get('checked') ? 'checked' : 'unChecked'}</div>
  3. <div>{self.get('message').split('').reverse().join()}</div>
  4. <div class={self.get('className') + ' test'}></div>
  5. // 对于复杂的逻辑,我们还可以使用自执行函数
  6. <div>{(function() {
  7. var ret = [];
  8. var books = self.get('books');
  9. for (var i = 0; i < books.length; i++) {
  10. if (books[i].size < 100) {
  11. ret.push(books[i].name);
  12. }
  13. }
  14. // 最后返回字符串
  15. return ret.join(' ');
  16. })()}</div>

Vdt模板支持访问全局变量。这会使你在项目全局引入了lodash等工具函数库时, 可以直接在模板中方便地使用它们而无需注入模板。但灵活性是把双刃剑, 如果你在模板中过多地依赖全局变量,可能会影响到组件的复用性。