博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
More than React(二)组件对复用性有害?
阅读量:5900 次
发布时间:2019-06-19

本文共 4994 字,大约阅读时间需要 16 分钟。

本系列的上一篇文章《》列举了前端开发中的种种痛点。本篇文章中将详细探讨其中“复用性”痛点。我们将用原生 DHTML API 、 ReactJS 和 Binding.scala 实现同一个需要复用的标签编辑器,然后比较三个标签编辑器哪个实现难度更低,哪个更好用。

\\

标签编辑器的功能需求

\\

在InfoQ的许多文章都有标签。比如本文的标签是“binding.scala”、“data-binding”、“scala.js”。

\\

假如你要开发一个博客系统,你也希望博客作者可以添加标签。所以你可能会提供标签编辑器供博客作者使用。

\\

如图所示,标签编辑器在视觉上分为两行。

\\

ddd5b9e43dd071a7739cf8e3cabc5e8a.png

\\

第一行展示已经添加的所有标签,每个标签旁边有个“x”按钮可以删除标签。第二行是一个文本框和一个“Add”按钮可以把文本框的内容添加为新标签。每次点击“Add”按钮时,标签编辑器应该检查标签是否已经添加过,以免重复添加标签。而在成功添加标签后,还应清空文本框,以便用户输入新的标签。

\\

除了用户界面以外,标签编辑器还应该提供 API 。标签编辑器所在的页面可以用 API 填入初始标签,也可以调用 API 随时增删查改标签。如果用户增删了标签,应该有某种机制通知页面的其他部分。

\\

原生 DHTML 版

\\

首先,我试着不用任何前端框架,直接调用原生的 DHTML API 来实现标签编辑器,代码如下:

\\
\\u0026lt;!DOCTYPE html\u0026gt;\\u0026lt;html\u0026gt;\\u0026lt;head\u0026gt;\  \u0026lt;script\u0026gt;\    var tags = [];\\    function hasTag(tag) {\      for (var i = 0; i \u0026lt; tags.length; i++) {\        if (tags[i].tag == tag) {\          return true;\        }\      }\      return false;\    }\\    function removeTag(tag) {\      for (var i = 0; i \u0026lt; 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 \u0026amp;\u0026amp; !hasTag(tag)) {\        addTag(tag);\        tagInput.value = \"\";\      }\    }\  \u0026lt;/script\u0026gt;\\u0026lt;/head\u0026gt;\\u0026lt;body\u0026gt;\  \u0026lt;div id=\"tags-parent\"\u0026gt;\u0026lt;/div\u0026gt;\  \u0026lt;div\u0026gt;\    \u0026lt;input id=\"tag-input\" type=\"text\"/\u0026gt;\    \u0026lt;button onclick=\"addHandler()\"\u0026gt;Add\u0026lt;/button\u0026gt;\  \u0026lt;/div\u0026gt;\  \u0026lt;script\u0026gt;\    addTag(\"initial-tag-1\");\    addTag(\"initial-tag-2\");\  \u0026lt;/script\u0026gt;\\u0026lt;/body\u0026gt;\\u0026lt;/html\u0026gt;
\\

为了实现标签编辑器的功能,我用了 45 行 JavaScript 代码来编写 UI 逻辑,外加若干的 HTML \u0026lt;div\u0026gt; 外加两行 JavaScript 代码填入初始化数据。

\\

HTML 文件中硬编码了几个 \u0026lt;div\u0026gt;。这些\u0026lt;div\u0026gt; 本身并不是动态创建的,但可以作为容器,放置其他动态创建的元素。

\\

代码中的函数来会把网页内容动态更新到这些 \u0026lt;div\u0026gt; 中。所以,如果要在同一个页面显示两个标签编辑器,id 就会冲突。因此,以上代码没有复用性。

\\

就算用 代替 DHTML API,代码复用仍然很难。为了复用 UI ,jQuery 开发者通常必须额外增加代码,在onload 时扫描整个网页,找出具有特定 class 属性的元素,然后对这些元素进行修改。对于复杂的网页,这些onload 时运行的函数很容易就会冲突,比如一个函数修改了一个 HTML 元素,常常导致另一处代码受影响而内部状态错乱。

\\

ReactJS 实现的标签编辑器组件

\\

ReactJS 提供了可以复用的组件,即 React.Component 。如果用 ReactJS 实现标签编辑器,大概可以这样写:

\\
\class TagPicker extends React.Component {\\  static defaultProps = {\    changeHandler: tags =\u0026gt; {}\  }\\  static propTypes = {\    tags: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,\    changeHandler: React.PropTypes.func\  }\\  state = {\    tags: this.props.tags\  }\\  addHandler = event =\u0026gt; {\    const tag = this.refs.input.value;\    if (tag \u0026amp;\u0026amp; 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 (\      \u0026lt;section\u0026gt;\        \u0026lt;div\u0026gt;{\          this.state.tags.map(tag =\u0026gt;\            \u0026lt;q key={ tag }\u0026gt;\              { tag }\              \u0026lt;button onClick={ event =\u0026gt; {\                const newTags = this.state.tags.filter(t =\u0026gt; t != tag);\                this.setState({ tags: newTags });\                this.props.changeHandler(newTags);\              }}\u0026gt;x\u0026lt;/button\u0026gt;\            \u0026lt;/q\u0026gt;\          )\        }\u0026lt;/div\u0026gt;\        \u0026lt;div\u0026gt;\          \u0026lt;input type=\"text\" ref=\"input\"/\u0026gt;\          \u0026lt;button onClick={ this.addHandler }\u0026gt;Add\u0026lt;/button\u0026gt;\        \u0026lt;/div\u0026gt;\      \u0026lt;/section\u0026gt;\    );\  }\\}\
\\

以上 51 行 ECMAScript 2015 代码实现了一个标签编辑器组件,即TagPicker。虽然代码量比 DHTML 版长了一点点,但复用性大大提升了。

\\

如果你不用 ECMAScript 2015 的话,那么代码还会长一些,而且需要处理一些 JavaScript 的坑,比如在回调函数中用不了 this。

\\

ReactJS 开发者可以随时用 ReactDOM.render 函数把 TagPicker 渲染到任何空白元素内。此外,ReactJS 框架可以在state 和 props 改变时触发 render ,从而避免了手动修改现存的 DOM。

\\

如果不考虑冗余的 key 属性,单个组件内的交互 ReactJS 还算差强人意。但是,复杂的网页结构往往需要多个组件层层嵌套,这种父子组件之间的交互,ReactJS 就很费劲了。

\\

比如,假如需要在 TagPicker 之外显示所有的标签,每当用户增删标签,这些标签也要自动更新。要实现这个功能,需要给 TagPicker 传入 changeHandler 回调函数,代码如下:

\\
\class Page extends React.Component {\\  state = {\    tags: [ \"initial-tag-1\

转载地址:http://ppesx.baihongyu.com/

你可能感兴趣的文章
__set魔术方法可不可以加private属性
查看>>
MySQL 4种事务的隔离级别
查看>>
跟我一起学docker(13)--docker Machine的使用
查看>>
有关Java字符编码的一些问题
查看>>
二:Unit 4
查看>>
影响英语单词拼写的6大因素
查看>>
计算机硬件基础知识
查看>>
SQLServer删除/重建/禁用/启用外键约束
查看>>
Unity3D播放视频
查看>>
[hadoop实战3]Hbase安装
查看>>
CNN卷积核反传分析
查看>>
python刷取CSDN博文访问量之三
查看>>
shell if
查看>>
利用PDO导入导出数据库
查看>>
CentOS 6.5 部署redmine 2.42
查看>>
DDR3
查看>>
分支 统计字数
查看>>
艾级计算机的发展与挑战
查看>>
我的友情链接
查看>>
java.lang.ArrayIndexOutOfBoundsException: 100
查看>>