澳门在线威尼斯官方 > 威尼斯澳门在线 > HTML也能够静态编写翻译,损害了复用性

原标题:HTML也能够静态编写翻译,损害了复用性

浏览次数:112 时间:2019-10-31

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 2016代码达成了三个标签编辑器组件,即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 用来在组件中传递新闻。小编参与的某国外客商项目,平均种种组件大概必要传入多少个回调函数。借使等级次序嵌套深,创造网页时,日常需求把回调函数从最顶层的组件生龙活虎罕有传入最尾巴部分的零部件,而当事件触发时,又需求生机勃勃稀有把事件新闻往外传。整个前端项目有当先五成代码都在此样绕圈子。

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 相像用法背后隐蔽的不如算法。

本文由澳门在线威尼斯官方发布于威尼斯澳门在线,转载请注明出处:HTML也能够静态编写翻译,损害了复用性

关键词:

上一篇:特殊对象

下一篇:没有了