首页 > 网站 > WEB开发 > 正文

关于Nuclear相关回应及思考

2024-04-27 14:08:30
字体:
来源:转载
供稿:网友

关于Nuclear相关回应及思考

2015-06-06 17:39 by 【当耐特】, ... 阅读, ... 评论, 收藏, 编辑

起因

在一个风轻云淡周末晚上,宝宝已经睡着。我轻手轻脚地爬起来,打开电脑,把心里构思的Nuclear实现了一遍。我是那种无法带着idea入睡的人,这种人活着比较累。因为有现成的observejs、mustachejs和classjs可以用,所以比较顺利,很快就完成了。为什么取名叫Nuclear,因为Nuclear是核的意思,它爆炸起来比较凶猛。

为什么要写这样一个东西?因为学了一个星期的react,做游戏的人,对class base的编程有特别的好感,但是又无法适应jsx和vd无法快速搭建复杂的PC后台的困惑,对vd甚至要颠覆前端工作流程感到困惑。当时,看的相关文章挺多。对声明式,可嵌套,快速的vd的diff相关的东西,读了官网的代码和大量的相关文章以及各大分享的PPT,也体会到了一点。但是那些都不是我去写Nuclear的原因,当时写的原因很简单class base和ui=fn(state)。然后:

class base嘛,先来个classjs

ui=fn(state)嘛,在Nuclear是 通过this.option访问用户传入的配置

数据变化通知视图:observejs (赋值胜于method call)

模板?找个star最多的 = =! mustachejs就它了

Canvas组件? render里直接写逻辑,而不是返回模板,用户只需要传canvas容器、canvas宽高和组件配置。

困境

不动手不知道,一动手吓一跳。

问题零

问题零:事件绑定,react的事件绑定都是写在标签上的。可通过this访问状态和组件方法。Nuclear只能通过这样子去解决了。this.node可以得到当前组件的根节点。当时安慰自己说:这种方式还可以在js解除,触发,貌似更加灵活= =!

    onRefresh: function () {        this.form = this.node.querySelector("form");        this.textBox = this.node.querySelector("input");        this.form.addEventListener("submit", function (evt) {            evt.PReventDefault();            this.option.items.push(this.textBox.value);        }.bind(this), false);    }

问题一

问题一是嵌套的TodoList,非常地整齐优雅:

  render: function() {    return (      <div>        <h3>TODO</h3>        <TodoList items={this.state.items} />        <form onSubmit={this.handleSubmit}>          <input onChange={this.onChange} value={this.state.text} />          <button>{'Add #' + (this.state.items.length + 1)}</button>        </form>      </div>    );  }

上面是官网Todo的代码,这怎么搞?mustachejs虽然支持{{>partials}},但是也无法实现上面这种嵌套的自定义标签。所以最后Nuclear实现的时候混在一起了:

        return '<div>/                    <h3>TODO</h3>/                    <ul> {{#items}} <li>{{.}}</li> {{/items}}</ul>/                    <form >/                    <input type="text"  />/                    <button>Add #{{items.length}}</button>/                    </form>/                </div>';

为此我纠结了许久,怎么实现自定义标签的嵌套?纠结没有结果之后,我去创建了一个asp.net的项目,看看里面的控件有多少可以嵌套。发现能嵌套进其他控件的基本就是容器类的,然后我就一直怀疑是否有必要嵌套,直到现在,嵌套到底有没有必要,我现在心里还是个问号。

如果真的有必要,那么实现起来不简单,因为要管理组件间的状态、事件、更新等。据说组件之间的状态共享通过爬树!?Tree是非常有用的数据结构。

问题二

在写markdown编辑器的时候,遇到了第二个问题:失去焦点。

因为最开始的时候根本没有考虑dom diff和局部刷新,只是碰一个问题解决一个。只要数据变化,dom全部刷新。导致的结构就是:光标本来在textare里,然后每次输入们字就失去焦点了,因为重新刷新了dom。这里才想到了dom diff。但最后决定通过标记 nc-refresh 去定义需要局部刷新的地方,实现成本最低:

        return '<div>/                    <h3>Input</h3>/                    <textarea rows="15" cols="35">{{value}}</textarea>/                    <h3>Output</h3>/                    <div class="content" nc-refresh >/                        {{{html}}}/                    </div>/                </div>';

提供onRefresh方法出发刷新之后的回调。所以局部刷新区域内的事件绑定必须全部卸载onRefresh里面。不刷新的区域里面的dom元素事件绑定在installed里面。installed代表dom树已经ready里。

就这样,通过 nc-refresh和onRefesh和insalled 把第二个问题给fix了。脑子里一团浆糊,也想不到什么更好的方案(晚上写代码都是机械性的,走一步是一步)。

再谈嵌套

nuclear理念和react确实不相同,只是形似。比如Todo的例子。

var TodoList = Nuclear.create({    render: function () {        return '<ul> {{#items}} <li>{{.}}</li> {{/items}}</ul>';    }});var TodoApp = TodoList.create({    onRefresh: function () {        this.form = this.node.querySelector("form");        this.textBox = this.node.querySelector("input");        this.form.addEventListener("submit", function (evt) {            evt.preventDefault();            this.option.items.push(this.textBox.value);        }.bind(this), false);    },    render: function () {        return '<div>/                  <h3>TODO</h3>'                  + this._super() +                  '<form >/                      <input type="text"  />/                      <button>Add #{{items.length}}</button>/                   </form>/                </div>';    }});new TodoApp("#todoContainer", { items: [] });

nuclear是继承+组合,react是嵌套+组合。然而这样的话,就会有个问题,如果TodoApp里用了多个组件,不仅仅是TodoList。那么nuclear就需要使用多重继承或依赖注入,这个需要nuclear后续做一些处理。

问题小结

通过自己的动手,终于弄明白一些React的how/what/why。但是虽然知道归知道,进一步的提升Nuclear、把优秀的思想转成代码合并进Nuclear,我觉得连angularjs都没用过的我暂时也想不到好的方案。

后来我就发给了朋友看。朋友看到之后的反馈很逗B:文案太没霸气了= =!。

当时的文案是:一款类似React的超轻量级框架, 但是移除了JSX、Virtual Dom和RequestAnimationFrame

后来我改成了:一款类似React的超轻量级框架, 废除了JSX、Virtual Dom和RequestAnimationFrame

英文其实挺中立的: a react-like library without jsx , virtual dom and requestAnimationFrame

现在已经改过来了: http://alloyteam.github.io/Nuclear/

说实话,这一字之差确实拉了许多仇恨,现在也是追悔莫及。确实是炒作和标题党和博眼球的行为。

其实自私一点说,我确实希望项目能够得到更多的关注,比如oberserjs被貘馍和2位教主等大大们转发之后,收到了工业聚等朋友的大量宝贵建议和意见,最后都merge到代码里去了。

而Nuclear确实没了灵感,也想不到什么取巧的实现方式。所以丢到了wb里,听听社区的声音。

有三个人令我印象深刻。

尤小右

尤: 实话实说吧,完全没有 get 到 react 的 point,把 react 最有价值的部分去掉了,还搞得更 OO...

我:嗯,把react我认为最讨厌的部分去掉了,OO不是槽点,是优点吧!?react也是oo啊,只是帮你new了,无继承,但可组合嵌套

尤小右:这说明你完全没理解 React... 组件不能嵌套要来何用?另外你这个任何数据变了都会重置组建的整个 DOM tree,万一组件很大呢?

我:你完全没有理解nuclear。nuclear可局部刷新,你看markdown那个demo的代码

尤小右:你所谓的局部更新依然是在 DOM 外进行了完整的渲染,虽然对 DOM 内的操作少了,但是成本依然比 virtual dom 高太多了

我: strToDom不是渲染啊

尤小右:嗯,不是渲染,但是是创建了大量无用节点,然后丢掉了。即使只有一个数据变了,你也会重新创建整个模板对应的 DOM 节点,这一点都不便宜的,你自己 benchmark 过没有

我:你吐槽了半天终于吐准了。哎,以后我还是专心写游戏吧,mv+的圈子要不来。

尤小右:性能倒是其次了,我一开始吐的另一点 - 组件不能嵌套,其实更致命

我:组件嵌套是我自己提的。亲,我一开始就说了,nuclear继承,组合,react嵌套组合

尤小右:继承和嵌套的意义完全不一样啊,有了嵌套才能用组件声明式地搭页面

我:各有利弊。目前nuclear支持命令式嵌套。我会考虑支持声明式嵌套

总结

不怪尤小右,文案惹得祸。容易让人不看代码,先吐槽。后来认真分析写了一篇文章:https://github.com/yyx990803/tucao/issues/1 点赞!

寸志

寸志:我就是要喷,因为之前他做模块加载器的时候我就想喷了!

寸志:因为我是小白呀,我不懂呀!现在懂你为啥要放个 onrefresh 函数了,就是让我在 DOM 被换了重新做事件绑定 [哈哈] 。我之前模板是这么写的,现在我稍微改下模板,我就要改 onrefresh 的逻辑。小白常常会忘记了吧,这是硬伤。你写出Nuclear,其实挺好的,但是一副好似比 React 牛逼的架势..

总结

究其原因:nuclear确实不够智能地判断哪些地方也重新绑定事件。而react声明式确没有这个问题。

由于以前kmdjs拉过他仇恨,加上文案惹祸。所以一上来就吐槽kmdjs和nuclear。后来平静下来发了好多让我思考的wb和地址。 点赞!

不怪寸志,文案和kmdjs惹得祸。容易让人不看代码,先吐槽。

寸志发的相关地址:https://github.com/et-studio/et 点赞

朴灵

朴灵:不评论与reactjs的比较,但是这种框架我能顺手写10个。

最后

2014年发生了很多事情甚至颠覆了我的价值观和人生观。每次坐飞机或者火车,我会把一些打磨了很久的代码定时发送给同事,如果安全到家,我就会取消定时,有时也会忘了取消。因为我觉得我的代码没有烂到看不下去,有些思想我想要分享出去。可是,能力有限,有些东西确实做不好,有些东西我还蛮满意。我是个爱分享爱炒作的家伙,以后不会了。

文案已改: http://alloyteam.github.io/Nuclear/


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表