本系列博文从ShadowWidget作者的角度讲解框架的设计要点。本文讲解escape标签、json-x、projection定义,与“如何分离接口设计”相关。1、寻找JSX的替代品上一篇文章《Unseriousness入门(上)》中提到,ShadowWidget需要寻找JSX的替代品来克服“JSX贴”带来的不利影响。例如,下面的JSX表达式:return

本系列博文从ShadowWidget作者的角度讲解框架的设计要点。本文讲解escape标签、json-x、projection定义,与“如何分离接口设计”相关。1、寻找JSX的替代品上一篇文章《Unseriousness入门(上)》中提到,ShadowWidget需要寻找JSX的替代品来克服“JSX贴”带来的不利影响。例如,下面的JSX表达式:return转义标签无非就是把所有的HTML标签都分成内联tags和blocktags,前者用表示,后者用Referece:example.com表示,每个标签用$=XXX属性定义表示实际使用的是哪个ReactClass,比如$=Panel表示T.Panel,$=P表示T.P。ShadowWidget扩展的所有组件模板类(也叫WTC,WidgetTemplateClass)都应该注册到T下,这样在刚打开网页的时候,就可以在escape标签中找到$=XXX表示的对应的React类,实现正常安装。escape标签中定义的属性,如上面的src='http://example.com',挂载前先整理props表(如{src:"http://example.com"}),escape标签的上下节点,以及同级节点之间的上下文关系,表明了json-x数据中children的定义。所以ReactClass、props、children有3项信息,escape标签可以转成json-x,所以也相当于JSX。转义标签是可读的,所以可以直接写在*.html文件中。此外,这种格式对搜索引擎也很友好。如果依赖JSX定义接口,搜索引擎无法分析到html文件中定义了哪些信息。3、一看就是恶,而且很可能是恶。React支持服务端渲染。这个特性似乎在鼓励其生态链上的几个工具扩展服务端功能。比如react-router中Router组件的history属性可以是browserHistory也可以是hashHistory。对于前者,客户端路由(即URL路径)决定了服务端如何实现,绑定了双方的设计。后面的hashHistory(即#/some/path)完全由客户端决定,与服务端无关。很明显,后一种方法优于前者,前者违背了软件设计的“关注点分离”(Separationofconcerns,SOC)原则,而在实践中,只需要webpack-dev-server(add--history-api-fallbackparameter)玩的好,不仅用JS语言进行绑架,还有具体的绑架工具。可怕的是,react-router官方推荐browserHistory作为首选。这个浏览器历史是一个充满怪物的特征。表面上好像有用,但经不起推敲。React的propTypes也很魔性。官方保存了这么久,终于在v15.5之后决定弃用。甚至不推荐上下文。Context是React为减轻跨节点数据共享的不便而创建的一个不起眼的东西。事物。在某种程度上,React的服务端渲染有些“滔天”。有些人只是用它来解决SEO优化。仔细想想,倒是有点颠倒了。它最初的需求源于google等搜索引擎不认可JSX,因为JSX是为编程服务的,编程脚本不应该被搜索引擎关注,而只是一些静态文本。处理静态文本不必涉及React系列,不是吗?但事实是,我们不得不套用客户端编程风格,使用JS开发的服务端渲染工具。你觉得它是怪物吗?4.分离界面设计在分离界面之前,我们需要建立一个路径索引机制。ShadowWidget通过一棵树(Widgettree,R树)来管理它定义的接口。每个节点都由一个键值标识,可以通过显示键值指定,也可以默认。默认情况下,键值由系统自动生成。数来表示。这棵果树的根节点是“.body”。如果根节点下有键值为“toolbar”的Panel节点,则其绝对路径为“.body.toolbar”。通过路径索引机制,我们可以将接口描述与其行为定义分开。例如,这样定义界面:
像这样定义测试按钮的行为:main['.body.toolbar.p.btn1']={$onClick:function(事件){警报('点击');},};界面的转义标签写在*.html文件中,界面元素的行为定义在*.js文件中进行。这样,界面设计就分离了,界面描述和相关元素的行为定义都是通过这个元素的绝对路径来实现关联的。如上例,一个元素的行为定义是用javascript写的,也称为“投影定义”。5.表达复杂的props数据json-x数据和escape标签相当于JSX,但是传递props数据有一些限制,比如escape标签不支持传递函数对象,json-x可以传递函数对象,但是两者都不支持鼓励(主要是不规范)。函数定义应该定义在投影类中,就像上面例子中的$onClick函数一样,不通过escape标签的属性传递,只有在挂载escape标签的时候,在main下找到对应的投影定义,然后捆绑相应的函数定义。除了功能之外,在描述复杂的props数据时,json-x的表达能力是完整的,因为是javascript数据,但是escape标签受html标签格式的影响,应该用json字符串表示,例如:属性值用'{'和'}'括起来,表示是JSON字符串,之前必须删除使用JSON.parse去掉第一个和最后两个花括号,比如上面的width值为JSON.parse('400')。另外,对于string类型的属性值,可以直接传递(避免字符串首尾的花括号),而不是按照json字符串的方式,比如上面的title属性。6、idSetter函数实现接口与底层分离。除了投影定义之外,还有一种方式是指定idSetter函数。简单理解的话,这个方法就是投影定义的一种变体,同样实现了对具体界面元素的行为定义的动态绑定。例如界面描述如下:TestJavascript是这样定义的:idSetter['btn1']=function(value,oldValue){if(value<=2){if(value==1){//初始化流程this.setEvent({$onClick:function(event){alert('clicked');},});//...}elseif(value==2){//挂载//...}elseif(value==0){//将卸载//...}return;}//渲染过程...};这种写法等价于上面定义的projection,projection类中应该写在getInitialState()的代码应该移到idSetter函数的if(value==1)分支,而应该写的代码写在componentDidMount()应该移动到if(value==2)分支。componentWillUnmount()中编写的代码被移动到if(value==0)分支。使用idSetter函数的好处是不需要完全定义对应接口节点的绝对路径,即路径上的每一段不需要显式给出key值,系统自动查找来自$id__='xxx'属性值的idSetter函数。另一个优点是编程风格更实用。7、随时建立节点定位的W树。Flux框架要求对节点间的数据流进行严格的约束。React不惜牺牲编程的便利性,刻意隐藏了内置的虚拟DOM树,这使得编程中跨节点调用变得非常不便。每个节点都被一层黑墙包围着,无法检测其周围存在哪些节点。好在React为这面黑墙开了一扇单向玻璃窗:refs,这样父节点可以引用子节点,子节点不能引用父节点。节点。克服引用不便的良方是引入redux这样的框架,将两个或多个有交叉影响的节点中的数据提升到一个公共区域进行编程。由于ShadowWidget引入了MVVM框架,在Component的API层面限制节点间的通信已经不合时宜,应该在更高层面上保证数据的单向流动。因此ShadowWidget引入了“W树”的概念,即所有符合规范的Component节点(即WTC类创建的节点)串联在一棵树上。树中的每个节点都有唯一的“路径”标记,节点也可以通过“相对路径”或“绝对路径”来引用,例如:this.componentOf('//')//获取父组件this.componentOf('//brother')//兄弟节点this.componentOf('sub.child')//子节点this.componentOf('./seg.child')//通过相对路径this.componentOf('.body.top.toolbar')//通过绝对路径有了W树的设计,路由规划会变得简单明了。例如,在下面的界面中,两个可切换的页面Article和Talk被安装在一个导航面板(NavPanel)中。如果要切换到文章页面,请按“/article”导航,切换到另一个页面并使用“/talk”导航。(本文完)本专栏历史文章:介绍一种让React与Vue竞争的技术React可视化开发工具ShadowWidget非正式介绍(一:React三原罪)
Test