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语法。

背景介绍

二零一八年 4 月,作者先是次在某个顾客的品种中接触到ReactJS 。

自个儿发觉ReactJS要比小编原先用过的AngularJS简单超级多,它提供了响应式的数码绑定效能,把数量映射到网页上,使自身得以轻巧达成相互影响轻便的网址。

只是,随着我越来越深远的运用ReactJS,作者开掘用ReactJS编写人机联作复杂的网页非常不便。 作者愿意有大器晚成种方法,可以像ReactJS同样轻巧化解轻松难点。别的,还要能轻松消除复杂难题。

于是乎自个儿把ReactJS用Scala重新写了贰个。代码量从近四万行减低到了生机勃勃千多行。

用那一个框架完成的TodoMVC应用,只用了154行代码。而用ReactJS完结平等功效的TodoMVC,需要488行代码。

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

星彩彩票app下载 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

别的前端框架的题材

标题大器晚成: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省随处太多事。

标题二: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来猜测亟待实践的操作。
星彩彩票app下载,自行的猜测算法既不允许又慢,应当要前端开采者手动提供 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的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原型复制粘贴到代码中,整个网址就足以运作了。

题目四: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怎样自动同步服务器数据,制止手动异步编制程序。

标题四: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卡塔尔(英语:State of Qatar) // 在调整桃园打字与印刷按钮内部的 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初看上去很像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。TimNieradzik是Widok的编辑者。他在观察作者宣布的框架后,称扬那个框架是Scala.js社区最有前程的 HTML 5渲染框架。

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

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

星彩彩票app下载 2

自个儿在这里段日子的多少个连串中,也慢慢遗弃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 客户名,在文本框下方就能来得顾客名对应的头像。

星彩彩票app下载 3

从 Github 加载头像

要想完毕那一个须要,能够用 Github API 发送得到顾客音讯的 HTTPS 请求。

出殡哀告并渲染头像的完整流程的检验收下规范如下:

  • 假诺客户名称叫空,显示“请输入客商名”的唤醒文字;
  • 要是客商名非空,发起 Github API,并依附 API 结果显示差异的开始和结果:
    • 若是未有加载完,展现“正在加载”的提醒消息;
    • 生机勃勃旦成功加载,把回应深入深入分析成 JSON,从当中提取头像 U宝马7系L 并呈现;
    • 要是加载时出错,展现错误音信。

其他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>
}

相关链接

  • 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 二〇一四 的 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>
}

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

有关笔者:ThoughtWorks

星彩彩票app下载 4

ThoughtWorks是一家中外IT咨询集团,追求非凡软件品质,致力于科技(science and technology卡塔尔(قطر‎驱动商业变革。擅长营造定制化软件出品,扶植客商快捷将定义转化为价值。同临时候为顾客提供客商体验设计、能力战略咨询、组织转型等咨询服务。 个人主页 · 小编的篇章 · 84 ·   

星彩彩票app下载 5

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,从当中提取头像 UENCOREL 并体现;

      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()
              ^

结论

本文相比较了 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
——奥巴马

编制程序语言是人和微型机对话的语言。对调改编制程序语言的人的话,计算机正是她们大脑的延伸,也是他俩肉体的风流洒脱局部。所以,不会编制程序的人就好像失去双翅的精灵。

微管理机程序是很奇妙的留存,它能够运作,会看、会听、会讲话,好似生命相符。会编制程序的人就好像在成立生命相像,干的是苍天的职业。

自个儿有叁个盼望,梦想编制程序能够像说话、写字相近的底蕴本事,被每一种人都调整。

只要网页设计员了解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

星彩彩票app下载 6

ThoughtWorks是一家中外IT咨询集团,追求优良软件品质,致力于科技(science and technology卡塔尔(英语:State of Qatar)驱动商业变革。长于创设定制化软件出品,帮忙客户高效将概念转变为价值。同时为客商提供顾客体验设计、本领战略咨询、组织转型等咨询服务。 个人主页 · 小编的稿子 · 84 ·   

星彩彩票app下载 7

本文由星彩网app下载发布于前端技术,转载请注明出处:HTML也得以静态编译,异步编制程序真的好啊

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。