澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

HTML也足以静态编写翻译,不符合复杂的前端项目

怎么 ReactJS 不合乎复杂的前端项目?

2016/08/17 · JavaScript · 15 评论 · React, ReactJS, 前端

本文作者: 伯乐在线 - ThoughtWorks 。未经作者许可,幸免转发!
应接参加伯乐在线 专辑小编。

《More than React》种类的文章会一同分成五篇。本文是率先篇,介绍用ReactJS开荒时相遇的种种问题。前面四篇小说的每大器晚成篇将会独家详细座谈当中三个难点,以至Binding.scala怎么样清除那一个标题。

《More than React》类别的稿子会一同分成五篇。本文是首先篇,介绍用ReactJS开采时遇见的种种问题。后边四篇文章的每生龙活虎篇将会分别详细座谈之中三个难题,以至Binding.scala怎样解决那一个题材。

文/杨博

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 完结同三个须求复用的价签编辑器,然后相比八个标签编辑器哪个完毕难度更低,哪个更加好用。

背景介绍

去年 4 月,笔者先是次在有个别客商的类型中接触到ReactJS 。

我发觉ReactJS要比作者原先用过的AngularJS轻易比超多,它提供了响应式的数额绑定成效,把数量映射到网页上,使自个儿得以轻巧实现互动轻便的网址。

可是,随着笔者愈来愈深切的利用ReactJS,笔者发掘用ReactJS编写交互复杂的网页很困难。 笔者盼望有豆蔻梢头种办法,能够像ReactJS同样简单化解简单难题。除此以外,还要能大约消除复杂难题。

于是自身把ReactJS用Scala重新写了三个。代码量从近三万行降低到了意气风发千多行。

用那些框架实现的TodoMVC应用,只用了154行代码。而用ReactJS达成均等效果的TodoMVC,需要488行代码。

下图是用Binding.scala落成的TodoMVC应用。

澳门新浦京娱乐场网站 1

这些框架正是Binding.scala。

背景介绍

2018年 4 月,笔者第贰次在有些顾客的项目中接触到ReactJS 。

自己意识ReactJS要比本身早前用过的AngularJS轻松超多,它提供了响应式的数量绑定成效,把数据映射到网页上,使本人可以轻便达成相互之间轻松的网址。

可是,随着我进一步浓郁的使用ReactJS,小编意识用ReactJS编写交互复杂的网页很辛苦。
本身期望有大器晚成种方法,能够像ReactJS同样轻巧杀绝轻便难点。除此以外,还要能轻巧化解复杂难点。

于是本身把ReactJS用Scala重新写了两个。代码量从近四万行降低到了后生可畏千多行。

用那么些框架完毕的TodoMVC应用,只用了154行代码。而用ReactJS达成均等成效的TodoMVC,需要488行代码。

下图是用Binding.scala完成的TodoMVC应用。

以此框架就是Binding.scala。

正文首发于InfoQ:http://www.infoq.com/cn/articles/more-than-react-part05

别的前端框架的难点

标签编辑器的功用须求

在InfoQ的大队人马篇章都有标签。比如本文的标签是“binding.scala”、“data-binding”、“scala.js”。

假诺你要开采贰个博客系统,你也盼望博客作者能够增加标签。所以你或许会提供标签编辑器供博客笔者运用。

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

澳门新浦京娱乐场网站 2

先是行体现已经增多的具有标签,每一个标签旁边有个“x”按键能够去除标签。第二行是一个文本框和四个“Add”按键能够把文本框的源委丰硕为新标签。每回点击“Add”按键时,标签编辑器应该检查标签是或不是已经增多过,以防再一次增加标签。而在名利双收增多标签后,还应清空文本框,以便客商输入新的标签。

澳门新浦京娱乐场网站,除去客户分界面以外,标签编辑器还相应提供 API 。标签编辑器所在的页面能够用 API 填入开首标签,也足以调用 API 随即增加和删除查改标签。就算客户增加和删除了标签,应该有某种机制通告页面的别样一些。

主题素材生龙活虎:ReactJS组件难以在百端待举交互页面中复用

ReactJS中的最小复用单位是组件。ReactJS的零件比AngularJS的Controller和View 要轻量些。 每种组件只必要前端开采者提供一个 render 函数,把 propsstate 映射成网页元素。

这么的轻量级组件在渲染轻松静态页面时很好用, 然而只要页面有相互,就亟须在组件间传递回调函数来处理事件。

自己将要《More than React(二)组件对复用性有毒?》中用原生DHTML API、ReactJS和Binding.scala达成同二个亟需复用的页面,介绍Binding.scala如何轻巧完成、简单复用复杂的互动逻辑。

主题素材风流倜傥:ReactJS组件难以在百端待举交互页面中复用

ReactJS中的最小复用单位是组件。ReactJS的组件比AngularJS的Controller和View 要轻量些。
各样组件只须求前端开荒者提供一个 render 函数,把 propsstate 映射成网页元素。

那般的轻量级组件在渲染轻易静态页面时很好用,
可是假诺页面有相互,就不得不在组件间传递回调函数来处总管件。

自身将要《More than React(二)组件对复用性有毒?》中用原生DHTML API、ReactJS和Binding.scala完成同三个亟待复用的页面,介绍Binding.scala怎么着轻巧完成、轻便复用复杂的互相逻辑。

《More than React》类别的上后生可畏篇小说《HTML也能够编写翻译?》介绍了 Binding.scala 如何在渲染 HTML 时静态检查语法错误和语义错误,进而幸免 bug ,写出更加结实健的代码。本篇小说将研商Binding.scala和其余前端框架怎么着向服务器发送央求并在页面展现。

对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 成分,平时变成另黄金时代处代码受影响而里边景色错乱。

主题材料二:ReactJS的杜撰DOM 算法又慢又不许

ReactJS的页面渲染算法是捏造DOM差量算法。

开辟者必要提供 render 函数,根据 propsstate 生成虚构 DOM。 然后 ReactJS 框架依据 render 再次回到的伪造 DOM 创制肖似结构的真正 DOM.

每当 state 改进时,ReacJS 框架重新调用 render 函数,获取新的设想 DOM 。 然后,框架会相比较上次生成的虚构 DOM 和新的杜撰 DOM 有何样差距,然后把差别应用到实在DOM上。

如此做有两大缺点:

  1. 每次 state 更改,render 函数都要生成完全的设想 DOM. 哪怕 state 改变十分的小,render函数也会整中华全国体育总会计三次。固然 render 函数很复杂,这么些进程就白白浪费了不菲乘除资源。
  2. ReactJS框架相比设想DOM差距的进度,既慢又易于出错。比方,借让你想要在有些 <ul>列表的顶上部分插入黄金时代项 <li> ,那么ReactJS框架会误认为你改改了 <ul> 的每风度翩翩项 <li>,然后在尾部插入了一个 <li>

那是因为 ReactJS收到的新旧四个虚构DOM之间交互独立,ReactJS并不知道数据源产生了怎么着操作,只好借助新旧四个设想DOM来猜测内需实行的操作。 自动的推断算法既不许又慢,一定要前端开拓者手动提供 key 属性、shouldComponentUpdate 方法、componentDidUpdate 方法也许 componentWillUpdate 等情势才干协助 ReactJS 框架猜对。

自家就要《More than React(三)设想DOM已死?》中比较ReactJS、AngularJS和Binding.scala渲染机制,介绍轻便质量高的Binding.scala准确数据绑定机制。

标题二:ReactJS的杜撰DOM 算法又慢又不许

ReactJS的页面渲染算法是虚构DOM差量算法。

开采者必要提供 render 函数,根据 propsstate 生成设想 DOM。
下一场 ReactJS 框架根据 render 再次来到的杜撰 DOM 成立相同结构的忠实 DOM.

每当 state 改善时,ReacJS 框架重新调用 render 函数,获取新的虚构 DOM 。
然后,框架会相比上次生成的捏造 DOM 和新的伪造 DOM 有怎样分化,然后把差别应用到真正DOM上。

这么做有两折桂笔:

  1. 每次 state 更改,render 函数都要生成完全的虚构 DOM. 哪怕 state 退换非常的小,render函数也会完全总计贰次。如若 render 函数很复杂,这一个进度就白白浪费了累累妄图能源。
  2. ReactJS框架比较设想DOM差距的进度,既慢又易于出错。比如,假若你想要在某些 <ul> 列表的顶端插入生龙活虎项 <li> ,那么ReactJS框架会误感觉你改改了 <ul> 的每后生可畏项 <li>,然后在尾巴部分插入了三个 <li>

这是因为 ReactJS收到的新旧五个设想DOM之间相互独立,ReactJS并不知道数据源爆发了哪些操作,只可以依赖新旧三个虚构DOM来猜测急需实行的操作。
自动的猜估测计算法既不许又慢,一定要前端开采者手动提供 key 属性、shouldComponentUpdate 方法、componentDidUpdate 方法照旧 componentWillUpdate 等方式手艺帮衬 ReactJS 框架猜对。

作者就要《More than React(三)设想DOM已死?》中相比较ReactJS、AngularJS和Binding.scala渲染机制,介绍简单质量高的Binding.scala准确数据绑定机制。

在过去的前端开拓中,向服务器央浼数据需求使用异步编制程序技巧。异步编制程序的定义很简单,指在进行I/O 操作时,不封堵当前试行流,而通过回调函数管理 I/O 的结果。不幸的是,那些概念就算简易,但用起来很麻烦,假若错用会导致 bug 丛生,尽管如履薄冰的拍卖各样异步事件,也会招致程序变得复杂、更难保险。

不相称原生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 二〇一五 的话,那么代码还组织带头人一些,何况亟需管理部分 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 用来在组件中传递消息。小编参预的某国外客商项目,平均各个组件差不离须要传入多少个回调函数。假设档案的次序嵌套深,创制网页时,通常须求把回调函数从最顶层的机件黄金年代稀少传入最尾部的零部件,而当事件触发时,又要求一才高八漠不关心把事件消息往外传。整个前端项目有超过一半代码都在这里么绕圈子。

主题材料三:ReactJS的HTML模板成效既不齐全、也不硬朗

ReactJS支持用JSX编写HTML模板。

商量上,前端技术员只要把静态HTML原型复制到JSX源文件中, 扩张一些变量替换代码, 就会改形成动态页面。 理论上这种做法要比Cycle.js、Widok、ScalaTags等框架更切合复用设计员提供的HTML原型。

不幸的是,ReactJS对HTML的扶植四分五裂。开荒者必需手动把classfor属性替换到classNamehtmlFor,还要把内联的style体制从CSS语法改成JSON语法,代码手艺运转。 这种开荒格局下,前端程序猿即便能够把HTML原型复制粘贴到代码中,但还必要多量改建能力实际运作。 比Cycle.js、Widok、只怕、ScalaTags省相连太多事。

除此而外,ReactJS还提供了propTypes体制校验设想DOM的合法性。 但是,这一编写制定也漏洞非常多。 尽管钦点了propTypes,ReactJS也无法在编写翻译前提前开采错误。独有测量检验覆盖率超高的门类时手艺在各类组件使用其余零件时进行校验。 即便测量检验覆盖率超高,propTypes仍旧无法检查评定出拼错的属性名,要是你把onClick写成了onclick, ReactJS就不会报错,往往产生开辟者额外开销大量时日排查七个很简单的bug。

本人将要《More than React(四)HTML也足以编写翻译?》中比较ReactJS和Binding.scala的HTML模板,介绍Binding.scala怎么着在全部支持XHTML语法的同有时间静态检查语法错误和语义错误。

主题素材三:ReactJS的HTML模板效能既不齐全、也不完善

ReactJS支持用JSX编写HTML模板。

批驳上,前端程序猿只要把静态HTML原型复制到JSX源文件中,
日增一些变量替换代码,
就会改形成动态页面。
理论上这种做法要比Cycle.js、Widok、ScalaTags等框架更切合复用设计员提供的HTML原型。

倒霉的是,ReactJS对HTML的扶助七零八落。开拓者必得手动把classfor性子替换来classNamehtmlFor,还要把内联的style体制从CSS语法改成JSON语法,代码手艺运作。
这种开拓情势下,前端技术员尽管能够把HTML原型复制粘贴到代码中,但还亟需大批量改变工夫实际运营。
比Cycle.js、Widok、只怕、ScalaTags省处处太多事。

除去,ReactJS还提供了propTypes体制校验虚构DOM的合法性。
可是,那大器晚成体制也破绽百出。
不畏钦点了propTypes,ReactJS也无法在编写翻译前提前开采错误。唯有测量检验覆盖率超级高的门类时手艺在各类组件使用别的零件时实行校验。
固然测量试验覆盖率极高,propTypes还是不可能检验出拼错的属性名,若是您把onClick写成了onclick
ReactJS就不会报错,往往形成开荒者额外开支大量年华逐个审查一个很简短的bug。

本人就要《More than React(四)HTML也足以编写翻译?》中比较ReactJS和Binding.scala的HTML模板,介绍Binding.scala怎么着在完全扶植XHTML语法的相同的时候静态检查语法错误和语义错误。

Binding.scala 能够用 I/O 状态的绑定替代异步编制程序,进而让程序又简约又好读,对业务职员也更友好。

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模板天性。

标题四:ReactJS与服务器通讯时索要复杂的异步编制程序

ReactJS从服务器加载数据时的架构能够看作MVVM(Model–View–ViewModel)格局。 前端程序员须求编写制定一个数据库访谈层作为Model,把ReactJS的state当做ViewModel,而render用作View。 Model负担访谈数据库并把数据设置到state(即View Model)上,可以用Promise和fetch API实现。 然后,renderHTML也足以静态编写翻译,不符合复杂的前端项目。,即View,担负把View Model渲染到页面上。

在此整个流程中,前端技士须要编写制定大量闭包组成的异步流程, 设置、访谈状态的代码五零四散, 一超级大心就能够bug丛生,就算谨言慎行的拍卖各种异步事件,也会促成程序变得复杂,既难调节和测量试验,又难保证。

自个儿将要《More than React(五)为啥别用异步编制程序?》中相比ReactJS和Binding.scala的数据同步模型,介绍Binding.scala怎样自动同步服务器数据,避免手动异步编程。

主题素材四:ReactJS与服务器通讯时须求复杂的异步编制程序

ReactJS从服务器加载数据时的架构能够看作MVVM(Model–View–ViewModel)情势。
前端程序员供给编写制定三个数据库访谈层作为Model,把ReactJS的state当做ViewModel,而render当做View。
Model负担访问数据库并把多少设置到state(即View Model)上,可以用Promise和fetch API实现。
然后,render,即View,担负把View Model渲染到页面上。

在此整个流程中,前端程序猿必要编写制定大批量闭包组成的异步流程,
安装、访谈状态的代码五零四散,
轻率就能够bug丛生,就算谨慎小心的管理种种异步事件,也会促成程序变得复杂,既难调节和测量检验,又难保险。

本人将要《More than React(五)为啥别用异步编制程序?》中相比较ReactJS和Binding.scala的数码同步模型,介绍Binding.scala怎样自动同步服务器数据,防止手动异步编制程序。

自己将以贰个从 Github 加载头像的 DEMO 页面为例,表达为啥异步编程会招致代码变复杂,以致 Binding.scala 怎么样消除这些主题素材。

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 取代,网页就搞好了。

结论

就算Binding.scala初看上去很像ReactJS, 但遮盖在Binding.scala背后的建制更轻松、更通用,与ReactJS和Widok楚河汉界。

为此,通过简化概念,Binding.scala灵活性更加强,能用通用的方法消灭ReactJS消除不了的头昏眼花难点。

例如,除了上述八个地点以外,ReactJS的状态管理也是吃力难点,借使引进Redux或然react-router那样的第三方库来管理状态,会导致架构变复杂,分层变多,代码绕来绕去。而Binding.scala能够用和页面渲染同样的数据绑定机制描述复杂的情形,不须求此外第三方库,就能够提供服务器通讯、状态处理和网站分发的机能。

以下表格中列出了上述Binding.scala和ReactJS的成效差别:

Binding.scala

ReactJS

复用性

微小复用单位

方法

组件

复用难度

不论交互内容还是静态内容都轻巧复用

轻松复用静态内容组件,但有口难言复用交互组件

页面渲染算法

算法

规范的数据绑定

虚拟 DOM

性能

正确性

电动保险科学

亟需开拓者手动设置 key 属性,不然复杂的页面会混杂。

HTML 模板

语法

Scala XML 字面量

JSX

是还是不是协理 HTML 或 XHTML 语法

完全援助 XHTML

残缺援助。平常的 XHTML 不可能编写翻译。开采者必得手动把 classfor 属性替换来 classNamehtmlFor,还要把内联的 style 样式从 CSS 语法改成 JSON 语法。

什么样校验模板语法

机动编写翻译时校验

运作时通过 propTypes 校验但不可能检查测验大约的拼写错误。

服务器通讯

机制

机动远程数据绑定

MVVM 异步编制程序

落到实处难度

简单

复杂

其他

何以分担网站只怕锚点链接

辅助把网站当成普通的绑定变量来用,没有必要第三方库。

不接济,须要第三方库 react-router

功效完善性

总体的前端开采解决方案

小编只含有视图部分功用。须要万分驾驭 react-router 、 Redux 品级三方库技能兑现完全的前端项目。

上学曲线

API 轻松,对没用过 Scala 的人来讲也很好懂

上心灵。但效果太弱导致中期学习第三方库时曲线陡峭。

Binding.scala

ReactJS

五个多月前,作者在Scala.js的论坛发布Binding.scala时,那个时候Scala.js社区最流行的响应式前端编制程序框架是Widok。提姆Nieradzik是Widok的笔者。他在拜访自己发表的框架后,赞美那个框架是Scala.js社区最有前途的 HTML 5渲染框架。

他是没有错,四个月后,以往Binding.scala已经济体改为Scala.js社区最风靡的响应式前端编制程序框架。

Awesome Scala网站对待了Scala的响应式前端编制程序框架,Binding.scala的龙腾虎跃程度和流行度都比Udash、Widok等别的框架要高。

澳门新浦京娱乐场网站 3

作者在新近的多少个类型中,也渐渐抛弃JavaScript和ReactJS,改用Scala.js和Binding.scala搭建新时期的前端本领栈。

结论

即便Binding.scala初看上去很像ReactJS,
但隐讳在Binding.scala背后的建制更轻便、更通用,与ReactJS和Widok楚河汉界。

因而,通过简化概念,Binding.scala灵活性更加强,能用通用的诀窍减轻ReactJS解决不了的复杂难题。

比如,除了上述三个地方以外,ReactJS的图景管理也是困难难点,假如引入Redux也许react-router那样的第三方库来处理意况,会形成架构变复杂,分层变多,代码绕来绕去。而Binding.scala能够用和页面渲染同样的数量绑定机制描述复杂的情形,无需别的第三方库,就能够提供服务器通讯、状态管理和网站分发的成效。

以下表格中列出了上述Binding.scala和ReactJS的职能差距:

3-sheet.png

八个多月前,小编在Scala.js的论坛发表Binding.scala时,此时Scala.js社区最风靡的响应式前端编制程序框架是Widok。TimNieradzik是Widok的审核人。他在寻访作者颁发的框架后,赞赏那几个框架是Scala.js社区最有前程的 HTML 5渲染框架。

她是对的,七个月后,今后Binding.scala已经变为Scala.js社区最风靡的响应式前端编程框架。

Awesome Scala网站相比较了Scala的响应式前端编制程序框架,Binding.scala的活跃程度和流行度都比Udash、Widok等别的框架要高。

本人在近日的多少个品种中,也逐渐甩掉JavaScript和ReactJS,改用Scala.js和Binding.scala搭建新时期的前端才干栈。

DEMO 功效须求

作为 DEMO 使用者,伸开页面后会看见一个文本框。

在文本框中输入猖狂 Github 顾客名,在文本框下方就能够显得顾客名对应的头像。

澳门新浦京娱乐场网站 4

从 Github 加载头像

要想达成那些需求,能够用 Github API 发送赢得客户音讯的 HTTPS 请求。

出殡央浼并渲染头像的全体流程的检验收下标准如下:

  • 假若顾客名称叫空,呈现“请输入客商名”的唤醒文字;
  • 假设顾客名非空,发起 Github API,并依据 API 结果展现分化的剧情:
    • 万风姿浪漫未有加载完,显示“正在加载”的提醒消息;
    • 如果成功加载,把回应深入解析成 JSON,从中提取头像 USportageL 并出示;
    • 只要加载时出错,呈现错误消息。

其他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 相像用法背后掩藏的比不上算法。

连带链接

  • 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 赞 5 收藏 15 评论

连带链接

  • 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 聊天室

异步编制程序和 MVVM

千古,我们在前端开采中,会用异步编制程序来发送哀告、获取数据。举个例子ECMAScript 2014 的 Promise 和 HTML 5 的 fetch API。

而要想把这一个数据渲染到网页上,我们过去的做法是用 MVVM 框架。在获取数据的进度中连连改正 View Model ,然后编写 View 把 View Model 渲染到页面上。这样一来,页面上就足以反映出加载进度的动态新闻了。比方,ReactJS 的 state 就是 View Model,而 render 则是 View ,担负把 View Model 渲染到页面上。

用 ReactJS 和 Promise 的完毕如下:

class Page extends React.Component {

  state = {
    githubUserName: null,
    isLoading: false,
    error: null,
    avatarUrl: null,
  };

  currentPromise = null;

  sendRequest(githubUserName) {
    const currentPromise = fetch(`https://api.github.com/users/${githubUserName}`);
    this.currentPromise = currentPromise;
    currentPromise.then(response => {
      if (this.currentPromise != currentPromise) {
        return;
      }
      if (response.status >= 200 && response.status < 300) {
        return response.json();
      } else {
        this.currentPromise = null;
        this.setState({
          isLoading: false,
          error: response.statusText
        });
      }
    }).then(json => {
      if (this.currentPromise != currentPromise) {
        return;
      }
      this.currentPromise = null;
      this.setState({
        isLoading: false,
        avatarUrl: json.avatar_url,
        error: null
      });
    }).catch(error => {
      if (this.currentPromise != currentPromise) {
        return;
      }
      this.currentPromise = null;
      this.setState({
        isLoading: false,
        error: error,
        avatarUrl: null
      });
    });
    this.setState({
      githubUserName: githubUserName,
      isLoading: true,
      error: null,
      avatarUrl: null
    });
  }

  changeHandler = event => {
    const githubUserName = event.currentTarget.value;
    if (githubUserName) {
      this.sendRequest(githubUserName);
    } else {
      this.setState({
        githubUserName: githubUserName,
        isLoading: false,
        error: null,
        avatarUrl: null
      });
    }
  };

  render() {
    return (
      <div>
        <input type="text" onChange={this.changeHandler}/>
        <hr/>
        <div>
          {
            (() => {
              if (this.state.githubUserName) {
                if (this.state.isLoading) {
                  return <div>{`Loading the avatar for ${this.state.githubUserName}`}</div>
                } else {
                  const error = this.state.error;
                  if (error) {
                    return <div>{error.toString()}</div>;
                  } else {
                    return <img src={this.state.avatarUrl}/>;
                  }
                }
              } else {
                return <div>Please input your Github user name</div>;
              }
            })()
          }
        </div>
      </div>
    );
  }

}

一齐用了 100 行代码。

出于整个流程由若干个闭包构成,设置、访问状态的代码五零四散,所以调节和测量试验起来很辛勤,笔者花了三个晚间才调通那100 行代码。

内嵌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 收藏 评论

有关小编:ThoughtWorks

澳门新浦京娱乐场网站 5

ThoughtWorks是一家中外IT咨询集团,追求卓越软件品质,致力于科学和技术驱动商业变革。长于塑造定制化软件出品,补助顾客火速将定义转变为价值。同期为顾客提供客商体验设计、才能战术咨询、协会转型等咨询服务。 个人主页 · 作者的稿子 · 84 ·   

澳门新浦京娱乐场网站 6

Binding.scala

未来大家有了 Binding.scala ,由于 Binding.scala 扶持活动远程数据绑定,能够这样写:

@dom def render = {
  val githubUserName = Var("")
  def inputHandler = { event: Event => githubUserName := event.currentTarget.asInstanceOf[Input].value }
  <div>
    <input type="text" oninput={ inputHandler }/>
    <hr/>
    {
      val name = githubUserName.bind
      if (name == "") {
        <div>Please input your Github user name</div>
      } else {
        val githubResult = FutureBinding(Ajax.get(s"https://api.github.com/users/${name}"))
        githubResult.bind match {
          case None =>
            <div>Loading the avatar for { name }</div>
          case Some(Success(response)) =>
            val json = JSON.parse(response.responseText)
            <img src={ json.avatar_url.toString }/>
          case Some(Failure(exception)) =>
            <div>{ exception.toString }</div>
        }
      }
    }
  </div>
}

一共 25 行代码。

完整的 DEMO 请访问 ScalaFiddle。

于是如此简单,是因为 Binding.scala 可以用 FutureBinding 把 API 须求当成普通的绑定表明式使用,表示 API 恳求的脚下气象。

每个 FutureBinding 的状态有三种恐怕,None意味着操作正在进展,Some(Success(...))表示操作成功,Some(Failure(...))意味着操作败北。

还记得绑定表达式的 .bind 吗?它表示“each time it changes”。
由于 FutureBinding 也是 Binding 的子类型,所以大家就足以接纳 .bind ,表明出“每当远端数据的意况退换”的语义。

结果正是,用 Binding.scala 时,大家编辑的每大器晚成行代码都得以对应检验收下标准中的一句话,描述着职业法规,而非“异步流程”那样的本事细节。

让大家回想一下检验收下标准,看看和源代码是怎么黄金时代风流罗曼蒂克对应的:

  • 如若顾客名称为空,显示“请输入客户名”的提示文字;

    if (name == "") {
      <div>Please input your Github user name</div>
    
  • 只要顾客名非空,发起 Github API,并基于 API 结果呈现分化的内容:

    } else {
      val githubResult = FutureBinding(Ajax.get(s"https://api.github.com/users/${name}"))
      githubResult.bind match {
    
    • 假如未有加载完,展现“正在加载”的提醒音讯;

      case None =>
        <div>Loading the avatar for { name }</div>
      
    • 万十分一功加载,把回应拆解深入分析成 JSON,从当中提取头像 UHavalL 并呈现;

      case Some(Success(response)) =>
        val json = JSON.parse(response.responseText)
        <img src={ json.avatar_url.toString }/>
      
    • 要是加载时出错,突显错误音信。

      case Some(Failure(exception)) => // 如果加载时出错,
        <div>{ exception.toString }</div> // 显示错误信息。
      
  • } }

强类型的 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

澳门新浦京娱乐场网站 7

ThoughtWorks是一家中外IT咨询公司,追求卓绝软件品质,致力于科技(science and technology)驱动商业变革。长于创设定制化软件出品,扶持客商高效将概念转变为价值。同不时候为客商提供客户体验设计、本领计谋咨询、协会转型等咨询服务。 个人主页 · 小编的小说 · 84 ·   

澳门新浦京娱乐场网站 8

结论

正文相比较了 ECMAScript 2016 的异步编制程序和 Binding.scala 的 FutureBinding 三种通讯本事。Binding.scala 概念更加少,成效更加强,对工作特别谐和。

表格.png

那五篇小说介绍了用 ReactJS 完毕复杂交互的前端项指标多少个困难,以及Binding.scala 如何减轻这么些难题,富含:

  • 复用性
  • 属性和准确性
  • HTML模板
  • 异步编制程序

除去上述八个方面以外,ReactJS 的情事处理也是难于难点,若是引进 Redux 只怕 react-router 那样的第三方库来管理状态,会招致架构变复杂,分层变多,代码绕来绕去。而Binding.scala 能够用和页面渲染相符的数量绑定机制描述复杂的情景,不供给其余第三方库,就会提供服务器通讯、状态处理和网站分发的效果。

若是您正参加复杂的前端项目,使用ReactJS或别的开销框架时,以为忧伤不堪,你可以用Binding.scala一举化解那个标题。Binding.scala火速上手指南中蕴含了从零早前成立Binding.scala项指标每一步骤。

内联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也查不出来。

后记

Everybody's Got to Learn How to Code
——奥巴马

编制程序语言是人和管理器对话的言语。对明白编程语言的人来讲,计算机就是他俩大脑的延长,也是她们肉体的少年老成都部队分。所以,不会编制程序的人就像失去双翅的Smart。

微型Computer程序是很奇妙的存在,它能够运营,会看、会听、会讲话,就好像生命相通。会编制程序的人就好像在开立生命相仿,干的是上帝的劳作。

自己有一个可望,梦想编程能够像说话、写字相像的底蕴技巧,被每一个人都调节。

比如网页设计员通晓Binding.scala,他们不再需求找程序猿达成他们的规划,而只要求在温馨的设计稿原型上加码法力符号.bind,就能够创造出会动的网页。

举个例子QA、BA或制品高管明白Binding.scala,他们写下检验收下标准后,不再必要检讨技师干的活对不对,而得以把检验收下标准机动成为可以运作的功效。

自个儿尽力在Binding.scala的统筹中扑灭不要求的技能细节,令人接收Binding.scala时,只需求关爱她想传递给计算机的音讯。

Binding.scala是本身朝着梦想迈进的小小产物。小编期望它不只是后边多少个技术员手中的利器,也能产生平凡人迈入编制程序圣堂的踏脚石。

自定义属性

假若您须求绕开对品质的等级次序检查,以便为HTML元素增添定制数据,你能够属性加上 data: 前缀,比如:

JavaScript

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

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

那样一来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 聊天室

More than React连串文章:

《More than React(生机勃勃)为什么ReactJS不符合复杂的前端项目?》

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

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

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

《More than React(五)异步编制程序真的好吧?》

结论

正文的总体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

澳门新浦京娱乐场网站 9

ThoughtWorks是一家中外IT咨询公司,追求优越软件品质,致力于科学技术驱动商业变革。擅长营造定制化软件出品,协助顾客高效将定义转变为价值。相同的时间为客户提供客商体验设计、技艺战略咨询、组织转型等咨询服务。 个人主页 · 作者的文章 · 84 ·   

澳门新浦京娱乐场网站 10

本文由澳门新浦京娱乐场网站发布于新浦京娱乐场官网,转载请注明出处:HTML也足以静态编写翻译,不符合复杂的前端项目