热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

React可视化开辟工具shadowwidget的非可视开辟要领

ShadowWidget首倡在可视设想器中开辟用户界面,输出转义标签,而非JSX。许多童鞋能够不知道SW一样支撑用JSX设想界面,开辟体验比原生React编程好出许多,本文就引见这

Shadow Widget 首倡在可视设想器中开辟用户界面,输出转义标签,而非 JSX。许多童鞋能够不知道 SW 一样支撑用 JSX 设想界面,开辟体验比原生 React 编程好出许多,本文就引见这方面学问。

 

1. 被官方无视的开辟要领

Shadow Widget 区分于别的前端框架的症结特征是可视化设想,因为 JSX 与 Javascript 混写,不能直接支撑可视化设想。所以,SW 用 “转义标签” 表达可视设想的输出,因为 SW 强调可视化,所以怎样应用 JSX 的内容,在官方文档中被弱化了,有一些零碎引见,疏散在手册各个章节,本文将它们串接起来说。

在 Shadow Widget 下做开辟,既可所以主流的 “正交框架” 情势(也就是遵照 MVVM 思绪设想可视界面,再用 Flux 框架组织横向数据流的开辟体式格局),也能够完整依从 React 原生情势,只把 SW 看做更好的 lib 库来运用。**下面我们连系代码实例,解说后一开辟体式格局。

因为 JSX 界面设想与用鼠标拖沓设置界面的设想是等价的,我们以 React 原生情势做开辟,相对 SW 主流体式格局,重要丧失可视化的直观特征,别的并不丧失。固然,如今运用 JSX 还得借助 Babel 转译环境,搭建 “Babel + Browserify” 或 “Babel + Webpack” 开辟环境是不得已的挑选。

怎样建立新工程及怎样搭建 Browerify 或 Webpack 环境,请参考《Shadow Widget 用户手册》的 “3.1 搭建工程环境” 一章。

2. 几个等价观点

1) json-x

json-x 是 “转义标签” 的数据化情势,用 Javascript 的 Array 数据表达各层嵌套节点。json-x 与转义标签的关联,就像 xml 与 HTML DOM 的关联。json-xJSX 是对应的,是统一类东西,不过 json-x 不如 JSX 易读。

 

2) WTC(Widget Template Class,构件模板类)

WTC 对应于 React 中各 Component 的 class 类定义。React 请求这么定义:

class MyButton extends React.Component {
constructor(props) {
// ...
}
componentDidMount() {
// ...
}
render() {
// ...
}
}

WTC 请求这么定义(必需从已有的 WTC 类继续,而且只能用 ES6+ 语法才做获得):

class MyButton_ extends T.Button_ {
constructor(name,desc) {
super(name,desc);
}
getDefaultProps() {
var props = super.getDefaultProps();
// props.attr = value;
return props;
}
getInitialState() {
var state = super.getInitialState();
// ...
return state;
}
componentDidMount() {
// ...
}
$onClick: function(event) {
alert('clicked');
}
}

WTC 不是 React class,不能在 JSX 中直接运用,应先转成 React class。

 

3) render 函数

假如想把 React 递次写得更严谨,削减 Side Effects,应该在 render() 函数集合处置惩罚种种掌握逻辑,对别的函数的功用,诸如 getInitialState, componentDidMount, componentWillUnmount 等,无妨简朴这么明白:为 render() 供应设置效劳。当设置缩简到能够疏忽时,Component 定义便退化为单个函数(即 Functional Component),该函数等效供应 render 功用。

Shadow Widget 按这个思绪,把掌握逻辑集合在 render() 函数中处置惩罚,包括:duals 双源属性的侦听、触发、联动,$if, $for 等掌握指令与可计算属性自动更新等。因为庞杂性在此封装,render 不轻易公开给用户定制,别的,Shadow Widget 为了支撑可视化设想,只管将 render() 中的逻辑掌握剖析,星散出属性项供设置,所以,Shadow Widget 不再勉励用户自定义 render() 函数,虽然人人能够 hack 各 WTC 的 render 完成历程,然后仿照着本身写一个,但这不是发起的做法。

借助以下门路,在 Shadow Widget 可完成 render 历程的逻辑掌握:

  1. props.attr, duals.attr, state.attr 取值掌握当前节点的界面表现
    个中,props.attr 反应了 Component 生计周期内的稳定量,duals.attr 是可变量,state.attr 也是可变量,偏向用作节点内私有掌握(不供别的节点挪用)。
  2. 在 render 衬着以外,挪用 comp.setChild() 来增、删、修正子节点
    即:不在 render() 挪用的历程当中挪用 comp.setChild()
  3. idSetter 函数中,挪用 utils.setChildren() 来增、删、修正子节点

上面 3 点,第一点比较好明白,第二点是 Shadow Widget 增添的,原生 React 不供应这类操纵,比方说,在一个页面提交一条反应看法,用户能够点一下 “删除” 按钮可删掉刚提交的看法。若用原始 Javascript 完成,也许用这么一条语句:

commentNode.parentNode.removeChild(commentNode);

原生 React 处置惩罚这类需求要轻微绕一下,给 commentNode 的父节点发个 “删除指令”,然后由它代为实行 “删除操纵”。Shadow Widget 供应 comp.setChild() 相当于补回 Javascript 本可直接完成的操纵。

上面第三点,在传入的 props.id__ 函数中,能够经由过程修正 duals.attrstate.attr 转变本节点的显现效果,还能经由过程挪用 utils.setChildren() 来转变子节点怎样显现。其完成道理与在 render() 函数中写代码是等价的,将在后文细述。

3. 将 WTC 转化为 React class

同为定义 component 类,WTC 继续链与 React class 继续链是不相干的两条链,前者起始于 T.Widget_,后者起始于 React.Component。当前者 WTC 类实例挪用 _createClass() 获得值,才与后者等效。

比方:

var AbstractButton = new MyButton_(); // MyButton_ is WTC
var MyButton = AbstractButton._createClass(); // MyButton is React class
var jsx = test;
var MyButton2 = AbstractButton._createClass( {
$onClick: function(event) {
alert('another onClick');
}
});
var jsx2 = test2;
var MyButton3 = T.Button._createClass( {
$onClick: function(event) {
alert('yet another onClick');
}
});
var jsx3 = test3;

简朴明白 WTC,可把它看做 React class 的 class 定义,即,它是一种用于天生 React class 的模板,所以 WTC 是 “构件模板” 的类(Widget Template Class)。

我们之所以要插进去 “模板” 一级的抽像物,重要为了顺应可视化编程,Widget Template 不只用来天生 React class,也为可视设想器供应支撑。别的,一个 Component 的行动在 WTC 中定义,照样在 _createClass(defs) 的传入参数(即投影类)定义是可选的,比方上例中 $onClick 事宜函数,在哪一个处所都可定义。这么设想的长处是:习习用 ES6 编码的童鞋,在 WTC 编程,习习用 ES5 的,用投影类编程,没必要搭建 Babel 转译环境。

Shadow Widget 供应 utils.getWTC() 接口用来批量从 T 模块获得 React class,比方:

var t = utils.getWTC('*'); // or, utils.getWTC(['Panel','P'])
var jsx = ( class HelloComponent extends React.Component {
constructor(props) {
super(props);
this.shouldCompOnentUpdate= PureRender.shouldComponentUpdate.bind(this);
}
render() {
return

Hello {this.props.name}
;
}
}

SFC 好像简朴,易读易保护,也轻易 “Lifting State Up”(后文有叙述),但 SFC 比 PRC 缺罕用 shouldComponentUpdate() 防止反复革新,机能会受影响,别的,JSX 中把 SFC 的函数用作 tag,动词用作名词,闪着一丝诡异的光。

Shadow Widget 开创性的设想 idSetter 机制,将 SFC 与 PRC 的长处连系起来了。一方面,你不须要非得用 class 类定义一个 Component,在层层嵌套的函数式作风中,不宜随意找个处所就定义 class,别的,idSetter 是函数,在一个函数中定义 Component 一切行动。

比方:

function btn__(value,oldValue) {
if (value <= 2) {
if (value == 1) { // init process
}
else if (value == 2) { // mount
}
else if (value == 0) { // unmount
}
return;
}
// rendering for evey render()
// ...
}
var jsx = test

若用 SFC 体式格局编程,先定义的一个 MakeButton 函数,然后用 test 形貌 UI 界面。MakeButton() 终究返回的 tag 是 button,照样 span,或是别的是动态变化的。但这里 test 倒是明白指定 tag 是 MyButton,很直接。

设想界面时,手头的 tag 标签相当于食材(比方 “米饭”),给各 tag 指定种种属性来掌握它的表面,这是最直接的设想体式格局。Stateless Functional Component 是 “紫菜包饭”,用函数情势包裹食材,idSetter 体式格局则相当于 “饭包紫菜包饭”,表面表现还是 “米饭”,内层用紫菜包裹过。

《React 可视化开辟工具 shadow-widget 的非可视开辟要领》

4.2 idSetter 长处

通报给 $id__ 的函数是 idSetter,这是万能的,因为体系在基类的 componentWillMount, componentDidMount, componentWillUnmount, render 这 4 个函数中增添了对 idSetter 函数自动挪用。个中,value <= 2 下的 3 个前提分支,离别等效于在 componentWillMount, componentDidMount, componentWillUnmount 中编码,别的前提(即 value > 2)相当于在 render 函数中编码。

这么处置惩罚有几个长处:

  1. 增强了功用,又符合函数式编程作风
    Functional Component 功用受限,因为不能插进去 componentDidMount, componentWillUnmount 时的处置惩罚,若用 React class 定义一个 Component 的行动,你具有 componentDidMount, componentWillUnmount 等专项处置惩罚函数,但 React class 定义是静态声明,非单项函数,把 class 定义在层层嵌套的任一函数中,比较别扭。idSetter 同时战胜了这两种缺点。
  2. 便于 lifting state up
    当我们采纳 JSX 形貌界面时,行动定义(属性与行动函数)与假造 DOM 形貌混在一同,这时候仅依靠 props.attr 逐层通报的数据同享体式格局,用起来不轻易。React 官方为此供应一种 “上举 state” 的解决方案,拜见 Lifting state up。

我们取 React 官方 Lifting State Up 一文引见的,推断温度是不是到达沸点的场景,举个例子:

var React = require('react');
var ReactDOM = require('react-dom');
var W = require('shadow-widget');
var main = W.$main, utils = W.$utils, ex = W.$ex;
var idSetter = W.$idSetter, t = utils.getWTC('*');
function calculatorUI() {
var selfComp = null, verdictComp = null;
var scaleNames = { c:'Celsius', f:'Fahrenheit' };
function onInputChange(value,oldValue) {
var scale = this.parentOf().props.scale || 'c'; // 'c' or 'f'
var degree = parseFloat(value) || 0; // take NaN as 0
selfComp.duals.temperature = [scale,degree];
}
function calculator__(value,oldValue) {
if (value <= 2) {
if (value == 1) { // init
selfComp = this;
this.defineDual('temperature', function(value,oldValue) {
if (Array.isArray(value) && verdictComp) {
var scale = value[0], degree = value[1];
var isBoil = degree >= (scale == 'c'?100:212);
verdictComp.duals['html.'] = isBoil?
'The water would boil.':
'The water would not boil.';
}
});
}
else if (value == 2) { // mount
verdictComp = this.componentOf('verdict');

var field = this.componentOf('field');
var inputComp = field.componentOf('input');
var legend = field.componentOf('legend');
var sScale = field.props.scale || 'c';
legend.duals['html.'] = 'Temperature in ' + scaleNames[sScale];

inputComp.listen('value',onInputChange.bind(inputComp));
selfComp.duals.temperature = [ sScale,
parseFloat(inputComp.duals.value) || 0
];
}
else if (value == 0) { // unmount
selfComp = verdictComp = null;
}
return;
}
}
return (



Shadow Widget 的 &#8220;Lift State Up&#8221; 比 React 原生体式格局更好用。

1) 起首,Shadow Widget 有双源属性,更多历程处置惩罚转为对 duals 属性的读写,更简朴,更直接,比方上面 legend 节点,用 legend.duals['html.'] = sDesc 直接转变界面文本,是外挂的,若在 render 函数中 return {sDesc} 则是历程处置惩罚,是内嵌的,不利于将子节点营业逻辑提升到父节点。

2) 其次,双源属性的 listen 机制,也有助于 &#8220;Lift State Up&#8221;,比方上面 inputComp.listen('value',onInputChange),在 输入框输入文本将驱动 onInputChange 挪用,有关相应函数能轻松 &#8220;Lift Up&#8221;。

3) 另有,idSetter 是函数,函数套函数很轻易,很天然,假以基层节点须要处置惩罚庞杂逻辑,里层嵌套定义另一个 idSetter 函数便可。我们能够把存在关联的高低多层节点的逻辑掌握代码,都归入外层节点的 idSetter 函数中。

4.3 在 idSetter 编程的等效性

在 idSetter 函数中编写代码,等效于在 React class 的 render 函数中编码。挪用 render 函数,末了返回 “本节点定义”,idSetter 函数现实在 render() 挪用中被调起的,相当于在 render() 进口位置,先挪用 idSetter 函数。等效代码以下所示:

function id__(comp) { // will call idSetter()
// comp.state.xxx = xxx;
// comp.$gui.comps = xxx;
}
class NewWTC extends T.BaseWTC_ {
// ...
render() {
id__(this);
var tagName = xxx, props = xxx, children = comp.$gui.comps;
return React.createElement(tagName,props,children);
}
}

本处代码仅为提要示例,以伪码体式格局诠释事情道理,xxx 示意省略历程的处置惩罚效果。个中嵌入的 id__ 函数会挪用前面引见的 idSetter 函数,只要在 idSetter 函数中本节点属性变动,及针对子节点的变动被保留,render() 依据修正过的信息天生 React Element,就到达让 idSetter 中编码与 render 中编码等效的目的。

与在 render 中编码等效的 idSetter 函数举例:

var fieldWidth = 0.9999;
var sTitle = 'Temperature in Celsius';
function fieldset__(value,oldValue) {
if (value <= 2) {
// ...
return;
}
this.duals.width = fieldWidth;
utils.setChildren(this, [
{sTitle} ,

]);
}

函数 utils.setChildren() 用来设置或更新子节点定义,需注意,各级子节点应指定 key 值,假如不指定,体系会以为你要建立新节点,而不是更新已存在节点。

只管在 idSetter 的 value > 2 前提段编码,等效于在 render 中编程,大部分情况下我们没必要这么做(也只管防止这么做)。因为 Shadow Widget 的双源属性功用很壮大,逻辑掌握总能剖析的,把掌握剖析到双源属性的 setter 函数,或侦听数据源变化来驱动特定行动,都能完成等效功用。这么细化剖析,代码更容易明白,更好保护。

5. 高层设想过于 &#8220;函数式&#8221; 的圈套

即使摒弃 Shadow Widget 的可视化开辟特征,只把它看成一个通例的 lib 库运用也是很有代价的,重要表如今两方面:

  1. Shadow Widget 在假造 DOM 之上对四种构件关联(即:递次、包括、导航、层叠)做了封装,像面板、导航、选项构件、弹窗等经常使用构件已现成可用,组织 GUI 越发方便。
  2. JSX 与 idSetter 连系运用,既保持函数式编程作风,也战胜原有 React 开辟过于 &#8220;函数式&#8221; 的缺点。

过于 “函数式” 关于界面类开辟一定不好,比方 UI 设想时,我们想摆一个文本框,再摆一个按钮,剖析设想的思绪是,文本输入变化了(onChange)该做什么,文本框输入完成(键入了回车键)该做什么,按钮被点击后该怎样相应。细化设想的思索历程,是从界面一个个可视的 Component 动身的,是按对象化体式格局做剖析的。不论你的代码写成啥样,设想历程仍离不开一个个对象(如文本框、按钮等),越是高层设想越是云云。

因为 React 偏幸函数式编程,加上 Flux 强化了数据流设想,轻易指导人人一开始就从数据设想入手,着眼于数据怎样剖析、怎样通报、怎样驱动相应函数等。采纳 Shadow Widget 后,产物开辟会往面向对象设想拉回一些,把握这一点就轻易明白 Shadow Widget 的设想精华了。

本专栏历史文章:

  1. 引见一项让 React 能够与 Vue 对抗的手艺
  2. React 可视化开辟工具 Shadow Widget 非正派入门(之一:React 三宗罪)
  3. React 可视化开辟工具 Shadow Widget 非正派入门(之二:星散界面设想)
  4. React 可视化开辟工具 Shadow Widget 非正派入门(之三:双源属性与数据驱动)
  5. React 可视化开辟工具 Shadow Widget 非正派入门(之四:flux、mvc、mvvm)
  6. React 可视化开辟工具 Shadow Widget 非正派入门(之五:指令式界面设想)
  7. React 可视化开辟工具 Shadow Widget 非正派入门(之六:markdown)

推荐阅读
author-avatar
嘉心面包-1908
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有