>

损害了复用性,HTML也可以静态编译

- 编辑:至尊游戏网站 -

损害了复用性,HTML也可以静态编译

HTML也得以静态编译?

2016/11/30 · HTML5 · 1 评论 · binding.scala, React, 前端

本文小编: 伯乐在线 - ThoughtWorks 。未经小编许可,禁绝转发!
应接出席伯乐在线 专辑撰稿人。

More than React类别文章:

《More than React(豆蔻年华)为何ReactJS不符合复杂的前端项目?》

《More than React(二)React.Component损害了复用性?》

《More than React(三)虚拟DOM已死?》

《More than React(四)HTML也足以静态编写翻译?》


《More than React》体系的上大器晚成篇小说《虚拟DOM已死?》比较了Binding.scala和此外框架的渲染机制。本篇文章中校介绍Binding.scala中的XHTML语法。

React.Component 损害了复用性?

2016/09/07 · 基础技艺 · binding.scala, data-binding, React, scala.js

本文笔者: 伯乐在线 - ThoughtWorks 。未经小编许可,防止转发!
迎接加入伯乐在线 专辑作者。

本连串的上风姿罗曼蒂克篇小说《为何ReactJS不相符复杂的前端项目》列举了前端开采中的各类痛点。本篇作品大校详细探求此中“复用性”痛点。大家将用原生 DHTML API 、 ReactJS 和 Binding.scala 完结同五个索要复用的价签编辑器,然后相比较八个标签编辑器哪个达成难度更低,哪个更加好用。

别的前端框架的标题

标签编辑器的功能供给

在InfoQ的多数文章皆有标签。比如本文的价签是“binding.scala”、“data-binding”、“scala.js”。

要是你要费用多个博客系统,你也可望博客小编能够增加标签。所以您大概会提供标签编辑器供博客小编运用。

如图所示,标签编辑器在视觉上分为两行。

图片 1

首先行体现已经拉长的富有标签,每一个标签旁边有个“x”开关能够去除标签。第二行是二个文本框和贰个“Add”按键能够把文本框的剧情丰盛为新标签。每一遍点击“Add”开关时,标签编辑器应该检查标签是不是曾经加多过,防止再度增添标签。而在名利双收增多标签后,还应清空文本框,以便客户输入新的竹签。

除了这一个之外客商界面以外,标签编辑器还相应提供 API 。标签编辑器所在的页面能够用 API 填入最初标签,也得以调用 API 随即增加和删除查改标签。假使客户增删了标签,应该有某种机制布告页面包车型地铁别样一些。

对HTML的残缺援助

原先大家运用其余前端框架,举个例子Cycle.js 、Widok、ScalaTags时,由于框架不支持HTML语法,前端程序猿被迫浪费大批量年华,手动把HTML改写成代码,然后渐渐调节和测验。

哪怕是永葆HTML语法的框架,例如ReactJS,扶助境况也很片纸只字。

譬喻,在ReactJS中,你不能够那样写:

JavaScript

class BrokenReactComponent extends React.Component { render() { return ( <ol> <li class="unsupported-class">不支持 class 属性</li> <li style="background-color: red">不支持 style 属性</li> <li> <input type="checkbox" id="unsupported-for"/> <label for="unsupported-for">不支持 for 属性</label> </li> </ol> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BrokenReactComponent extends React.Component {
  render() {
    return (
      <ol>
        <li class="unsupported-class">不支持 class 属性</li>
        <li style="background-color: red">不支持 style 属性</li>
        <li>
          <input type="checkbox" id="unsupported-for"/>
          <label for="unsupported-for">不支持 for 属性</label>
        </li>
      </ol>
    );
  }
}

后边二个程序猿必须手动把 classfor 属性替换到 classNamehtmlFor,还要把内联的 style 样式从CSS语法改成JSON语法,代码才具运营:

JavaScript

class WorkaroundReactComponent extends React.Component { render() { return ( <ol> <li className="workaround-class">被迫把 class 改成 className</li> <li style={{ backgroundColor: "red" }}>被迫把体制表改成 JSON</li> <li> <input type="checkbox" id="workaround-for"/> <label htmlFor="workaround-for">被迫把 for 改成 htmlFor</label> </li> </ol> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class WorkaroundReactComponent extends React.Component {
  render() {
    return (
      <ol>
        <li className="workaround-class">被迫把 class 改成 className</li>
        <li style={{ backgroundColor: "red" }}>被迫把样式表改成 JSON</li>
        <li>
          <input type="checkbox" id="workaround-for"/>
          <label htmlFor="workaround-for">被迫把 for 改成 htmlFor</label>
        </li>
      </ol>
    );
  }
}

这种开采格局下,前端工程师即使能够把HTML原型复制粘贴到代码中,但还索要大量改变本事实际运行。比Cycle.js、Widok大概ScalaTags省相连太多事。

原生 DHTML 版

首先,小编试着不用别样前端框架,直接调用原生的 DHTML API 来促成标签编辑器,代码如下:

JavaScript

<!DOCTYPE html> <html> <head> <script> var tags = []; function hasTag(tag) { for (var i = 0; i < tags.length; i++) { if (tags[i].tag == tag) { return true; } } return false; } function removeTag(tag) { for (var i = 0; i < tags.length; i++) { if (tags[i].tag == tag) { document.getElementById("tags-parent").removeChild(tags[i].element); tags.splice(i, 1); return; } } } function addTag(tag) { var element = document.createElement("q"); element.textContent = tag; var removeButton = document.createElement("button"); removeButton.textContent = "x"; removeButton.onclick = function (event) { removeTag(tag); } element.appendChild(removeButton); document.getElementById("tags-parent").appendChild(element); tags.push({ tag: tag, element: element }); } function addHandler() { var tagInput = document.getElementById("tag-input"); var tag = tagInput.value; if (tag && !hasTag(tag)) { addTag(tag); tagInput.value = ""; } } </script> </head> <body> <div id="tags-parent"></div> <div> <input id="tag-input" type="text"/> <button onclick="addHandler()">Add</button> </div> <script> addTag("initial-tag-1"); addTag("initial-tag-2"); </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;script&gt;
    var tags = [];
 
    function hasTag(tag) {
      for (var i = 0; i &lt; tags.length; i++) {
        if (tags[i].tag == tag) {
          return true;
        }
      }
      return false;
    }
 
    function removeTag(tag) {
      for (var i = 0; i &lt; tags.length; i++) {
        if (tags[i].tag == tag) {
          document.getElementById("tags-parent").removeChild(tags[i].element);
          tags.splice(i, 1);
          return;
        }
      }
    }
 
    function addTag(tag) {
      var element = document.createElement("q");
      element.textContent = tag;
      var removeButton = document.createElement("button");
      removeButton.textContent = "x";
      removeButton.onclick = function (event) {
        removeTag(tag);
      }
      element.appendChild(removeButton);
      document.getElementById("tags-parent").appendChild(element);
      tags.push({
        tag: tag,
        element: element
      });
    }
 
    function addHandler() {
      var tagInput = document.getElementById("tag-input");
      var tag = tagInput.value;
      if (tag &amp;&amp; !hasTag(tag)) {
        addTag(tag);
        tagInput.value = "";
      }
    }
  &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div id="tags-parent"&gt;&lt;/div&gt;
  &lt;div&gt;
    &lt;input id="tag-input" type="text"/&gt;
    &lt;button onclick="addHandler()"&gt;Add&lt;/button&gt;
  &lt;/div&gt;
  &lt;script&gt;
    addTag("initial-tag-1");
    addTag("initial-tag-2");
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
 

为了落到实处标签编辑器的法力,小编用了 45 行 JavaScript 代码来编排 UI 逻辑,外加若干的 HTML <div> 外加两行 JavaScript 代码填入带头化数据。

HTML 文件中硬编码了多少个 <div>。这些<div> 本人并不是动态成立的,但能够当作容器,放置任何动态创建的成分。

代码中的函数来会把网页内容动态更新到这个 <div> 中。所以,固然要在同两个页面呈现多少个标签编辑器,id 就能冲突。因而,以上代码未有复用性。

就算用 jQuery 替代 DHTML API,代码复用如故很难。为了复用 UI ,jQuery 开辟者平日必需附加扩大代码,在 onload 时扫描整个网页,寻找装有一定 class 属性的成分,然后对那么些成分实行修改。对于复杂的网页,那么些 onload 时运转的函数非常轻易就能够冲突,比方四个函数修改了三个 HTML 成分,日常导致另风流倜傥处代码受影响而里边景色错乱。

不相称原生DOM操作

别的,ReactJS等部分前端框架,会生成虚拟DOM。虚构DOM不只怕协作浏览器原生的DOM API ,导致和jQuery、D3等另外库合作时寸步难行。比方ReactJS更新DOM对象时平常会破坏掉jQuery控件。

Reddit重重人评论了这几个主题素材。他们未有主意,只可以弃用jQuery。作者司的某顾客在用了ReactJS后也被迫用ReactJS重写了汪洋jQeury控件。

ReactJS 实现的竹签编辑器组件

ReactJS 提供了足以复用的机件,即 React.Component 。假若用 ReactJS 完结标签编辑器,大约能够如此写:

JavaScript

class TagPicker extends React.Component { static defaultProps = { changeHandler: tags => {} } static propTypes = { tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, changeHandler: React.PropTypes.func } state = { tags: this.props.tags } addHandler = event => { const tag = this.refs.input.value; if (tag && this.state.tags.indexOf(tag) == -1) { this.refs.input.value = ""; const newTags = this.state.tags.concat(tag); this.setState({ tags: newTags }); this.props.changeHandler(newTags); } } render() { return ( <section> <div>{ this.state.tags.map(tag => <q key={ tag }> { tag } <button onClick={ event => { const newTags = this.state.tags.filter(t => t != tag); this.setState({ tags: newTags }); this.props.changeHandler(newTags); }}>x</button> </q> ) }</div> <div> <input type="text" ref="input"/> <button onClick={ this.addHandler }>Add</button> </div> </section> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class TagPicker extends React.Component {
 
  static defaultProps = {
    changeHandler: tags =&gt; {}
  }
 
  static propTypes = {
    tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
    changeHandler: React.PropTypes.func
  }
 
  state = {
    tags: this.props.tags
  }
 
  addHandler = event =&gt; {
    const tag = this.refs.input.value;
    if (tag &amp;&amp; this.state.tags.indexOf(tag) == -1) {
      this.refs.input.value = "";
      const newTags = this.state.tags.concat(tag);
      this.setState({
        tags: newTags
      });
      this.props.changeHandler(newTags);
    }
  }
 
  render() {
    return (
      &lt;section&gt;
        &lt;div&gt;{
          this.state.tags.map(tag =&gt;
            &lt;q key={ tag }&gt;
              { tag }
              &lt;button onClick={ event =&gt; {
                const newTags = this.state.tags.filter(t =&gt; t != tag);
                this.setState({ tags: newTags });
                this.props.changeHandler(newTags);
              }}&gt;x&lt;/button&gt;
            &lt;/q&gt;
          )
        }&lt;/div&gt;
        &lt;div&gt;
          &lt;input type="text" ref="input"/&gt;
          &lt;button onClick={ this.addHandler }&gt;Add&lt;/button&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    );
  }
 
}
 

上述 51 行 ECMAScript 二〇一四代码完成了二个标签编辑器组件,即TagPicker。尽管代码量比 DHTML 版长了一丝丝,但复用性大大进步了。

倘若你绝不 ECMAScript 2016 的话,那么代码还组织首领一些,况兼亟需管理部分 JavaScript 的坑,比方在回调函数中用持续 this

ReactJS 开垦者能够每一日用 ReactDOM.render 函数把 TagPicker 渲染到别的层空间白成分内。另外,ReactJS 框架能够在 stateprops 改动时触发 render ,进而制止了手动修改现有的 DOM。

假诺不思量冗余的 key 属性,单个组件内的并行 ReactJS 还算壮志未酬。可是,复杂的网页结构往往要求五个零部件层层嵌套,这种父亲和儿子组件之间的相互,ReactJS 就很伤脑筋了。

譬喻说,若是供给在 TagPicker 之外突显全部的标签,每当客商增加和删除标签,这几个标签也要自动更新。要促成这么些职能,须求给 TagPicker 传入 changeHandler 回调函数,代码如下:

JavaScript

class Page extends React.Component { state = { tags: [ "initial-tag-1", "initial-tag-2" ] }; changeHandler = tags => { this.setState({ tags }); }; render() { return ( <div> <TagPicker tags={ this.state.tags } changeHandler={ this.changeHandler }/> <h3>全体标签:</h3> <ol>{ this.state.tags.map(tag => <li>{ tag }</li> ) }</ol> </div> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Page extends React.Component {
 
  state = {
    tags: [ "initial-tag-1", "initial-tag-2" ]
  };
 
  changeHandler = tags =&gt; {
    this.setState({ tags });
  };
 
  render() {
    return (
      &lt;div&gt;
        &lt;TagPicker tags={ this.state.tags } changeHandler={ this.changeHandler }/&gt;
        &lt;h3&gt;全部标签:&lt;/h3&gt;
        &lt;ol&gt;{ this.state.tags.map(tag =&gt; &lt;li&gt;{ tag }&lt;/li&gt; ) }&lt;/ol&gt;
      &lt;/div&gt;
    );
  }
 
}
 

为了能接触页面其他一些更新,笔者被迫增添了三个 21 行代码的 Page 组件。

Page 组件必需实现 changeHandler 回调函数。每当回调函数触发,调用 Page 自己的 setState 来触发 Page 重绘。

从那个例子,大家得以看见, ReactJS 能够简简单单的消除容易的标题,但碰上档案的次序复杂、交互频仍的网页,达成起来就很麻烦。使用 ReactJS 的前端项目充满了各类 xxxHandler 用来在组件中传递音信。我加入的某国外顾客项目,平均每种组件大概必要传入四个回调函数。倘若档期的顺序嵌套深,创制网页时,经常需求把回调函数从最顶层的零部件如日方升偶发传入最底部的机件,而当事件触发时,又必要一千载难逢把事件消息往外传。整个前端项目有当先二分之一代码都在此样绕圈子。

Binding.scala中的XHTML

近年来有了Binding.scala ,可以在@dom艺术中,间接编写XHTML。比方:

JavaScript

@dom def introductionDiv = { <div style="font-size:0.8em"> <h3>Binding.scala的优点</h3> <ul> <li>简单</li> <li>概念少<br/>功能多</li> </ul> </div> }

1
2
3
4
5
6
7
8
9
@dom def introductionDiv = {
  <div style="font-size:0.8em">
    <h3>Binding.scala的优点</h3>
    <ul>
      <li>简单</li>
      <li>概念少<br/>功能多</li>
    </ul>
  </div>
}

如上代码会被编写翻译,直接开立真实的DOM对象,而从未设想DOM。

Binding.scala对浏览器原生DOM的扶持很好,你可以在这里些DOM对象上调用DOM API,与 D3、jQuery等其他库交互也完全没不日常。

ReactJS对XHTML语法的欠缺不全。比较之下,Binding.scala帮忙完整的XHTML语法,前端程序猿可以直接把设计好的HTML原型复制粘贴到代码中,整个网址就能够运维了。

Binding.scala 的主导用法

在解说 Binding.scala 怎么样贯彻标签编辑器在此以前,小编先介绍部分 Binding.scala 的基础知识:

Binding.scala 中的最小复用单位是数码绑定表达式,即 @dom 方法。每个 @dom 方法是意气风发段 HTML 模板。比方:

JavaScript

// 两个 HTML 换行符 @dom def twoBr = <br/><br/>

1
2
3
// 两个 HTML 换行符
@dom def twoBr = &lt;br/&gt;&lt;br/&gt;
 

JavaScript

// 一个 HTML 标题 @dom def myHeading(content: String) = <h1>{content}</h1>

1
2
3
// 一个 HTML 标题
@dom def myHeading(content: String) = &lt;h1&gt;{content}&lt;/h1&gt;
 

每一个模板还足以使用bind语法富含其余子模板,比方:

JavaScript

@dom def render = { <div> { myHeading("Binding.scala的特点").bind } <p> 代码短 { twoBr.bind } 概念少 { twoBr.bind } 功能多 </p> </div> }

1
2
3
4
5
6
7
8
9
10
11
12
13
@dom def render = {
  &lt;div&gt;
    { myHeading("Binding.scala的特点").bind }
    &lt;p&gt;
      代码短
      { twoBr.bind }
      概念少
      { twoBr.bind }
      功能多
    &lt;/p&gt;
  &lt;/div&gt;
}
 

您能够敬仰附录:Binding.scala火速上手指南,学习上手Binding.scala开荒的具体步骤。

别的,本种类第四篇小说《HTML也得以编写翻译》还将列出Binding.scala所协助的总体HTML模板特性。

Binding.scala中XHTML的类型

@dom格局中XHTML对象的品类是Node的派生类。

比如,<div></div> 的品种就是HTMLDivElement,而 <button></button> 的等级次序正是 HTMLButtonElement。

此外, @dom 注明会修改总体艺术的重回值,包装成二个Binding。

JavaScript

@dom def typedButton: Binding[HTMLButtonElement] = { <button>按钮</button> }

1
2
3
@dom def typedButton: Binding[HTMLButtonElement] = {
  <button>按钮</button>
}

注意typedButton是个原生的HTMLButtonElement,所以能够平昔对它调用 DOM API。举例:

JavaScript

@dom val autoPrintln: Binding[Unit] = { println(typedButton.bind.innerHTML) // 在调整新竹打字与印刷按钮内部的 HTML } autoPrintln.watch()

1
2
3
4
@dom val autoPrintln: Binding[Unit] = {
  println(typedButton.bind.innerHTML) // 在控制台中打印按钮内部的 HTML
}
autoPrintln.watch()

这段代码中,typedButton.bind.innerHTML 调用了 DOM API HTMLButtonElement.innerHTML。通过autoPrintln.watch(),每当开关发生更新,autoPrintln中的代码就能够试行二回。

Binding.scala达成的价签编辑器模板

末尾,下文将展现怎么着用Binding.scala完结标签编辑器。

标签编辑器要比刚刚牵线的HTML模板复杂,因为它不可是静态模板,还隐含交互。

JavaScript

@dom def tagPicker(tags: Vars[String]) = { val input: Input = <input type="text"/> val addHandler = { event: Event => if (input.value != "" && !tags.get.contains(input.value)) { tags.get += input.value input.value = "" } } <section> <div>{ for (tag <- tags) yield <q> { tag } <button onclick={ event: Event => tags.get -= tag }>x</button> </q> }</div> <div>{ input } <button onclick={ addHandler }>Add</button></div> </section> }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@dom def tagPicker(tags: Vars[String]) = {
  val input: Input = &lt;input type="text"/&gt;
  val addHandler = { event: Event =&gt;
    if (input.value != "" &amp;&amp; !tags.get.contains(input.value)) {
      tags.get += input.value
      input.value = ""
    }
  }
  &lt;section&gt;
    &lt;div&gt;{
      for (tag &lt;- tags) yield &lt;q&gt;
        { tag }
        &lt;button onclick={ event: Event =&gt; tags.get -= tag }&gt;x&lt;/button&gt;
      &lt;/q&gt;
    }&lt;/div&gt;
    &lt;div&gt;{ input } &lt;button onclick={ addHandler }&gt;Add&lt;/button&gt;&lt;/div&gt;
  &lt;/section&gt;
}
 

本条标签编辑器的 HTML 模板黄金年代共用了 18 行代码就实现好了。

标签编辑器中须求出示当前有着标签,所以这里用tags: Vars[String]保存全数的标签数据,再用for/yield循环把tags中的每一个标签渲染成UI成分。

Vars 是永葆数据绑定的列表容器,每当容器中的数据发生改动,UI就能够活动改动。所以,在x按键中的onclick事件中剔除tags中的数据时,页面上的竹签就能自行随之消失。同样,在Add按钮的onclick中向tags中增加数据时,页面上也会自行发出相应的标签。

Binding.scala不但完结标签编辑器比 ReactJS 轻易,而且用起来也比 ReactJS 轻易:

JavaScript

@dom def render() = { val tags = Vars("initial-tag-1", "initial-tag-2") <div> { tagPicker(tags).bind } <h3>全体标签:</h3> <ol>{ for (tag <- tags) yield <li>{ tag }</li> }</ol> </div> }

1
2
3
4
5
6
7
8
9
@dom def render() = {
  val tags = Vars("initial-tag-1", "initial-tag-2")
  &lt;div&gt;
    { tagPicker(tags).bind }
    &lt;h3&gt;全部标签:&lt;/h3&gt;
    &lt;ol&gt;{ for (tag &lt;- tags) yield &lt;li&gt;{ tag }&lt;/li&gt; }&lt;/ol&gt;
  &lt;/div&gt;
}
 

若是用 9 行代码另写三个 HTML 模板,在模板中调用刚才实现好的 tagPicker 就行了。

完整的 DEMO 请访问 。

在 Binding.scala 无需像 ReactJS 那样编写 changeHandler 之类的回调函数。每当客商在 tagPicker 输入新的竹签时,tags 就能够变动,网页也就能够自行随之变动。

对照 ReactJS 和 Binding.scala 的代码,能够开掘以下分别:

  • Binding.scala 的开拓者能够用类似 tagPicker 这样的 @dom 方法表示 HTML 模板,而没有必要组件概念。
  • Binding.scala 的开垦者能够在艺术之间传递 tags 那样的参数,而不供给 props 概念。
  • Binding.scala 的开采者能够在方式钦定义局地变量表示情形,而不须要 state 概念。

因而看来 Binding.scala 要比 ReactJS 精简不少。

倘若您用过 ASP 、 PHP 、 JSP 之类的服务端网页模板语言, 你会发觉和 Binding.scala 的 HTML 模板很像。

动用 Binding.scala 一点也没有必要函数式编制程序知识,只要把规划工具中变化的 HTML 原型复制到代码中,然后把会变的某些用花括号取代、把重复的有的用 for / yield 取代,网页就做好了。

其他HTML节点

Binding.scala支持HTML注释:

JavaScript

@dom def comment = { <!-- 你看不见笔者 --> }

1
2
3
@dom def comment = {
  <!-- 你看不见我 -->
}

Binding.scala也支持CDATA块:

JavaScript

@dom def inlineStyle = { <section> <style><![CDATA[ .highlight { background-color:gold } ]]></style> <p class="highlight">Binding.scala真好用!</p> </section> }

1
2
3
4
5
6
7
8
9
10
@dom def inlineStyle = {
  <section>
    <style><![CDATA[
      .highlight {
        background-color:gold
      }
    ]]></style>
    <p class="highlight">Binding.scala真好用!</p>
  </section>
}

结论

本文相比较了分裂技艺栈中落成和选取可复用的竹签编辑器的难度。

原生 HTML ReactJS Binding.scala
实现标签编辑器需要代码行数 45行 51行 17行
实现标签编辑器的难点 在代码中动态更新HTML页面太繁琐 实现组件的语法很笨重
使用标签编辑器并显示标签列表需要代码行数 难以复用 21行 8行
阻碍复用的难点 静态HTML元素难以模块化 交互组件之间层层传递回调函数过于复杂

Binding.scala 不评释“组件”之类的玩笑,而以更轻易的“方法”为最小复用单位,让编制程序体验越来越顺风,得到了越来越好的代码复用性。

本种类下生机勃勃篇小说将相比 ReactJS 的杜撰 DOM 机制和 Binding.scala 的确切数据绑定机制,揭发 ReactJS 和 Binding.scala 相似用法背后掩盖的比不上算法。

内嵌Scala代码

除去能够把XHTML内嵌在Scala代码中的 @dom 方法中,Binding.scala 还扶植用 { ... } 语法把 Scala 代码内嵌到XHTML中。举个例子:

JavaScript

@dom def randomParagraph = { <p>生成二个即兴数: { math.random.toString }</p> }

1
2
3
@dom def randomParagraph = {
  <p>生成一个随机数: { math.random.toString }</p>
}

XHTML中内嵌的Scala代码能够用 .bind 绑定变量大概调用其余 @dom 方法,比如:

JavaScript

val now = Var(new Date) window.setInterval(1000) { now := new Date } @dom def render = { <div> 今后时间:{ now.bind.toString } { introductionDiv.bind } { inlineStyle.bind } { typedButton.bind } { comment.bind } { randomParagraph.bind } </div> }

1
2
3
4
5
6
7
8
9
10
11
12
13
val now = Var(new Date)
window.setInterval(1000) { now := new Date }
 
@dom def render = {
  <div>
    现在时间:{ now.bind.toString }
    { introductionDiv.bind }
    { inlineStyle.bind }
    { typedButton.bind }
    { comment.bind }
    { randomParagraph.bind }
  </div>
}

上述代码渲染出的网页中,时间会动态改动。

相关链接

  • Binding.scala 项目主页
  • Binding.scala • TodoMVC 项目主页
  • Binding.scala • TodoMVC DEMO
  • Binding.scala • TodoMVC 以外的其余DEMO
  • JavaScript 到 Scala.js 移植指南
  • Scala.js 项目主页
  • Scala API 参照他事他说加以考察文书档案
  • Scala.js API 参照他事他说加以考察文书档案
  • Scala.js DOM API 参谋文书档案
  • Binding.scala快速上手指南
  • Binding.scala API参照他事他说加以考察文书档案
  • Binding.scala 的 Gitter 聊天室

    1 赞 1 收藏 评论

强类型的 XHTML

Binding.scala中的XHTML 都援救静态类型检查。比方:

JavaScript

@dom def typo = { val myDiv = <div typoProperty="xx">content</div> myDiv.typoMethod() myDiv }

1
2
3
4
5
@dom def typo = {
  val myDiv = <div typoProperty="xx">content</div>
  myDiv.typoMethod()
  myDiv
}

鉴于上述代码有拼写错误,编写翻译器就能够报错:

JavaScript

typo.scala:23: value typoProperty is not a member of org.scalajs.dom.html.Div val myDiv = <div typoProperty="xx">content</div> ^ typo.scala:24: value typoMethod is not a member of org.scalajs.dom.html.Div myDiv.typoMethod() ^

1
2
3
4
5
6
typo.scala:23: value typoProperty is not a member of org.scalajs.dom.html.Div
        val myDiv = <div typoProperty="xx">content</div>
                     ^
typo.scala:24: value typoMethod is not a member of org.scalajs.dom.html.Div
        myDiv.typoMethod()
              ^

关于我:ThoughtWorks

图片 2

ThoughtWorks是一家中外IT咨询集团,追求特出软件质量,致力于科学技术驱动商业变革。专长构建定制化软件出品,扶助顾客高效将概念转变为价值。同一时间为客商提供顾客体验设计、技巧计谋咨询、组织转型等咨询服务。 个人主页 · 笔者的稿子 · 84 ·   

图片 3

内联CSS属性

style 属性设置内联样式时,style 的值是个字符串。举个例子:

JavaScript

@dom def invalidInlineStyle = { <div style="color: blue; typoStyleName: typoStyleValue"></div> }

1
2
3
@dom def invalidInlineStyle = {
  <div style="color: blue; typoStyleName: typoStyleValue"></div>
}

上述代码中设置的 typoStyleName 样式名写错了,但编写翻译器并从未报错。

要想让编写翻译器能检查内联样式,能够用 style: 前缀而不用 style 属性。比如:

JavaScript

@dom def invalidInlineStyle = { <div style:color="blue" style:typoStyleName="typoStyleValue"></div> }

1
2
3
@dom def invalidInlineStyle = {
  <div style:color="blue" style:typoStyleName="typoStyleValue"></div>
}

那便是说编写翻译器就能报错:

JavaScript

typo.scala:28: value typoStyleName is not a member of org.scalajs.dom.raw.CSSStyleDeclaration <div style:color="blue" style:typoStyleName="typoStyleValue"></div> ^

1
2
3
typo.scala:28: value typoStyleName is not a member of org.scalajs.dom.raw.CSSStyleDeclaration
        <div style:color="blue" style:typoStyleName="typoStyleValue"></div>
         ^

那样一来,能够在编写代码时就清楚属性有未有写对。不像原生JavaScript / HTML / CSS那样,蒙受bug也查不出来。

自定义属性

大器晚成旦您必要绕开对质量的门类检查,以便为HTML元素增多定制数据,你能够属性加上 data: 前缀,比如:

JavaScript

@dom def myCustomDiv = { <div data:customAttributeName="attributeValue"></div> }

1
2
3
@dom def myCustomDiv = {
  <div data:customAttributeName="attributeValue"></div>
}

那样一来Scala编写翻译器就不会报错了。

结论

本文的完整DEMO请访谈 ScalaFiddle。

从那么些示例能够看来,Binding.scala 风度翩翩方面匡助完全的XHTML ,能够从高保真HTML 原型无缝移植到动态网页中,开采进度颇为顺畅。另意气风发方面,Binding.scala 能够在编写翻译时静态检查XHTML中出现语法错误和语义错误,进而幸免bug 。

以下表格比较了ReactJS和Binding.scala对HTML语法的协理程度:

ReactJS Binding.scala
是否支持HTML语法? 残缺支持
是否支持标准的style属性? 不支持,必须改用 JSON 语法
是否支持标准的class属性? 不支持,必须改用className
是否支持标准的for属性? 不支持,必须改用htmlFor
是否支持HTML注释? 不支持
是否兼容原生DOM操作? 不兼容
是否兼容jQuery? 不兼容
能否在编译时检查出错误? 不能

小编将在下大器晚成篇小说中介绍 Binding.scala 怎么着兑现服务器发送央求并在页面显示结果的流水线。

相关链接

  • Binding.scala 项目主页
  • Binding.scala • TodoMVC 项目主页
  • Binding.scala • TodoMVC DEMO
  • Binding.scala • TodoMVC 以外的别的DEMO
  • JavaScript 到 Scala.js 移植指南
  • Scala.js 项目主页
  • Scala API 参谋文书档案
  • Scala.js API 参谋文书档案
  • Scala.js DOM API 参照他事他说加以考察文书档案
  • Binding.scala飞速上手指南
  • Binding.scala API参照他事他说加以考察文书档案
  • Binding.scala 的 Gitter 聊天室

    1 赞 1 收藏 1 评论

关于我:ThoughtWorks

图片 4

ThoughtWorks是一家中外IT咨询公司,追求非凡软件质量,致力于科学技术驱动商业变革。擅长创设定制化软件出品,扶植客商连忙将定义转变为价值。同一时间为顾客提供客户体验设计、手艺攻略咨询、组织转型等咨询服务。 个人主页 · 作者的小说 · 84 ·   

图片 5

本文由硬件数码发布,转载请注明来源:损害了复用性,HTML也可以静态编译