探讨前端组件化

2019-11-16 19:44:42 +08:00
 hfcc8685

一. 现状

现在我接手一个项目”好货网”, 该项目已经上线两年, 我的 title 是前端技术负责人, 团队现有三名前端工程师, 其中一人刚入职.
项目用原生 JS+CSS 编写, 没有使用任何框架, 整个网站共有 10 个一级页面, 20 个子页面, 页面风格一致.
当有新需求时, 开发人员会新建一个页面, 如果新页面的部分模块和已有页面雷同, 会拷贝代码到新页面中, 基本不考虑复用和抽取.

二. 问题

  1. 新页面开发周期长, 产品经理痛苦不堪
  2. 页面难以维护, 比如有一个模块是商品模块, 当商品结构调整时,所有的商品信息展示都要更改, 开发和测试要对 15 个页面进行调整和测试
  3. 页面可读性差, 因为已经换了很多工程师, 每个人的风格可能都不一样, 导致代码风格千奇百怪
  4. 重复代码非常多, 而且同一种业务逻辑会有多种实现方式, 但是效果是一样的
  5. 不敢重构, 动一发牵全身

三. 目标

为了解决上述五个问题, 我决定开展一个技术项目, 即实现项目组件化

四. 方案

4.1 框架的选择 有两种方案可以选择, 一种是原生 JS 组件化, 另一种是引入 react,vue 等框架. 考虑到团队成员的水平, react 和 vue 基本没用过, 这样会有学习成本, 而且这些框架入门容易,用好难, 考虑到团队成员的 js 基础还不错, 保险起见, 决定采用 js 实现组件化.

4.2 制定方案 分析所有页面后发现, 30 个页面的风格一致, 按钮,下拉框,弹出层等都一致,商品展示模块 ui 一致, 用户信息模块 ui 一致, 所以打算分为基础组件和业务组件两部分进行封装, 为了保证线上功能稳定性和迭代的正常开发, 按如下步骤完成最终的上线:

  1. 跟 UI 和产品沟通, 确认网站风格, UI 设计基础组件和业务组件
  2. 封装基础组件
  3. 替换线上页面的基础组件, 一个个上线, 保证稳定性
  4. 封装业务组件
  5. 替换页面的业务组件, 一个个页面上线, 保证稳定性
  6. 重构页面, 一个个页面上线

4.3 组件的实现过程 组件分为两大类, 一类是基础组件, 一类是业务组件, 业务组件使用基础组件+业务逻辑进行封装, 除了一些简单的基础组件,比如 button 等, 其他组件都继承一个组件基类 Component

4.3.1 基类 Component 的实现 1. Component 有三个最重要的生命周期: init: 组件实例被创建, 我们在这里去创建一个 div mounted: 在 div 挂在到 dom 树上, 该方法会触发, 供子类去重写 unmounted: 把 div 移除 dom 树 2. 提供一个 attributes 数组, 用于存放组件的属性值, 比如 style 属性,data 属性, 由使用者传递进来 3. 组件之间需要互相挂载, 所以提供两个方法 appendTo 和 appendChild. 考虑到大多数组件都是被挂载到 Component 上, 提供一个 render 方法供重写 4. 很多时候, 组件的逻辑很复杂, 不同状态下展示不同的 div,这时候需要有状态去标识, 所以我们可以封装一个 states 数组到 components 中 5. Component 要暴露出去 div 的事件供子类设置, 封装 addEventListener, removeEventListener, triggerEvent 方法, 子类可重写

4.3.2 基础组件的实现 基础组件包括 TabContainer, ScrollContainer 组件等, 带有业务特性, 需继承 Component 并按组件要求重写某些方法, 举例 1. TabContainer 组件会重写 render 实现 tab 头的切换效果. 2. ScrollContainer 组件的最外层 div 要设置为可滚动, 一种方法是每次使用 ScrollContainer 时传入 style 属性, 但对 ScrollContainer 来说这种属性是固定的, 应该封装到 ScrollContainer 更合适, 所以我采用重写 init 方法,里边(先调用super.init())

4.3.3 业务组件的实现 业务组件继承 Component, 可以使用基础组件, 一般是用于通用业务模块的抽取, 比如商品模块,ui 和交互都一样,就抽取出来, 商品信息作为属性传递进来, 根据需求去展示商品信息, 内部交互自己处理,有的交互需要通知父组件时通过事件向外传递

4.3.4 页面 页面由各个业务组件+基础组件+业务逻辑封装, 页面一方面负责取服务端数据, 并把部分数据传递到业务组件中, 另一方面需要处理子组件之间的交互

4.3.5 过程中的点 1. 应该会有不少人在子类中直接调用 component 创建的 div, 这种是否合理呢? 我的想法是不太合理, div 应该由 component 自己维护, 但是开发的过程中发现有的子类真的需要调用,比如 scrollContainer 需要知道 div 的高度, 所以在 Component 中提供了一个 get 方法供子类调用, 纠结… 其实也可以考虑不能被子类调用, scrollContainer 自己定义一个最大的 div, 挂载到 component 的 div 上,然后 scrollContainer 取自己的 div 高度 2. 如果有埋点的需求, 比如大部分组件的 mounted 后都需要发送后端埋点, 可以考虑封装到 component 的 mounted 中, 提供一个 attribute 作为是否发送埋点的开关, 控制 mounted 里要不要加载 3. 子类组件封装自己能提供的事件, 对于使用者来说只需要知道事件的名称, 然后把事件函数传入. 比如 scrollContainer 在滚动条触底时要对外抛出一个事件, 不具备通用性, 需封装到 scrollContainer 中, 所以它需要提供一个 scrollEnd 事件. 一开始我直接调用this.container.addEventListener(‘scroll’)去做的, 但是思考了一下觉得应该通过重写 addEventListener 方法去实现比较合理

4.4 组件化的工具 组件化的过程中, 会发现很多问题, 比如:

  1. css 样式都写在 js 中, css 维护起来非常不方便, 而且代码可读性变差. 解决方式有很多种, 比如 npm 去引入 css-loader, 让 css 文件可以 import 到 js 中
  2. 用 js 代码去生成 dom 树比较繁琐, 不够清晰和直观, 可以引入 JSX 的写法, npm 上找现成儿的, 或者可以自己去实现解析 jsx

4.5 保证项目可维护性的其他措施

  1. 项目大了, 无论新老员工都需要知道项目中目前有哪些组件, 省的去找代码看, 开源的 storyBook 非常好, 可以很方便安装到项目中, 项目启动后, 在浏览器中就能看到目前项目的所有组件了.
  2. 确定一种好的代码风格, 通过 codeReview 的方式让团队的代码风格趋于一致,大家也能互相学习各自的好的编程风格, 提高个人的编程能力
  3. 我觉得不停的重构是保证团队质量的唯一方式, 而如何保证重构又能完成迭代任务呢, 搭建自动化测试是一种好的方式

五. 结果

这是个计划, 我还没做完 4.3.2, 没有结果, 中间肯定还有很多坑…. , 这是个漫长的过程, 但是会有完成的那天的, 毕竟时间如白驹过隙, 岁月又曾绕过谁呢

5877 次点击
所在节点    JavaScript
36 条回复
weixiangzhe
2019-11-16 19:59:44 +08:00
这样整 不如用 react vue 啊,几轮人员流动下来谁还能维护
crs0910
2019-11-16 20:14:38 +08:00
钓鱼?
crs0910
2019-11-16 20:16:37 +08:00
4.1 真是张口就来
ironMan1995
2019-11-16 20:19:33 +08:00
不让开发加班,怎么都成
TangMonk
2019-11-16 20:20:47 +08:00
现在的潮流动不动就是 react,vue,不是 spa 感觉没必要。后端模板引擎搞定。
Mutoo
2019-11-16 20:25:42 +08:00
如果 js 基础不错,会连 vue 和 react 都用不好吗? React 的开发团队一路踩了多少年的坑过来的,优化到极致。哪怕不去用,至少学习和参考一下吧。毕竟连 vue 都懂得抄 react。
shintendo
2019-11-16 20:42:45 +08:00
有一说一,vue 有个鸡儿学习成本
mara1
2019-11-16 20:46:27 +08:00
你高估了 react/vue 的难度,写前端的上手这些框架很快的。
用 react/vue 的好处显而易见,代码量少下来,开发快,后期人员离职,再找个立刻上手,你整这一套少有人愿意接手维护。
建议挑个好手,找个成熟的 react 或 vue 方案,搞个模版出来,其他人照着抄即可。
hfcc8685
2019-11-16 20:58:29 +08:00
这文章也不能编辑啊....我想删掉 4.2 之前的, 莫问 vue 和 react, 我也非常喜欢也会用, 这个现状其实是我的一种假设, 主要是老师带着我们去做的论文, 研究组件原理, 应该文章里声明一下的, sorry! 求对组件化理解深的大佬交流, 我 4.2 以后部分的有啥毛病
wangyzj
2019-11-16 21:04:19 +08:00
新的轮子要诞生了
murmur
2019-11-16 21:05:12 +08:00
我以前做过 jquery+easyui+bootstrap 大杂烩(没办法,企业开发要求表格的功能特别强)的组件封装,后来我用了 vue 和 react,发现以前做的都是 shit
hoyixi
2019-11-16 21:09:03 +08:00
首先,你们项目是前后端分离吗?如果是,方法多了去了,自己搞一套可以; 早期 handlebars/mustache 模板可以用起来;或者 handlebars/mustache 搭配 backbone.js 也可以; 或者上 React/Vue~

如果不是前后端分离,那就有点麻烦,不仅前端麻烦,还得说服后端一起重构
tanszhe
2019-11-16 21:09:32 +08:00
如果是 app 内嵌的,单页应用感觉体验不如传统的好
传统的已经显示完了,你的框架还么有加载完 后面还有页面 体检比较差
crs0910
2019-11-16 21:20:03 +08:00
组件化是有标准的,可以参考 https://github.com/Polymer
Torpedo
2019-11-16 23:00:01 +08:00
这种纯 js 的组件化,找个库吧。库从某个意义上来说,就是标准。大家跟着库的最佳实践走,一般没错。同时,库的封装也都比较好。
cmingxu
2019-11-16 23:05:42 +08:00
是多么怀念 SPA 之前的例子, 前端大神们别折腾了。
duan602728596
2019-11-16 23:16:33 +08:00
看完这一篇长篇大论后,我选择 react、vue,省下的时间学习、打游戏、旅游、睡觉不好吗?
hyy1995
2019-11-16 23:18:46 +08:00
原生 JS+CSS 来怼出来的项目?贵司真的牛批。。。



你洋洋洒洒写了一大堆,其实没必要,如果前后端分离,那么好说,前端直接用 vue/react 等这些流行框架重构就行,做好组件化。如果前后端不分离,那就麻烦了,后端也得重构。总之这种项目我说难听点就是屎山,唯一解决方式就是大换血,你要说开发人员不会用框架、学习成本高耗不起时间,那就是死局。
OSF2E
2019-11-17 01:20:05 +08:00
说点题外话。
React 的 Hook 没出现之前,我做前端项目的时候跟你基本是一个思路,而且从 IE6 时代开始就推崇原生和手撸。
React 的 Hook 没出现之后,我自认为我对前端架构的认识已经提升到了第三层。简单说下我自己的分层方案,第一层是使用原生 html/css/js 纯意识流手糊代码;第二层,是采用业内主流技术栈(三大框架,ES6、Typescript、webpack 等),配合 NPM 第三方包,用最能 [被同行认可标的姿势] 去糊 [代码质量完全无法自主控制] 的项目;第三层,悟出了产品、视觉、交互、前端、后端 [单向数据流风格] 的协作流程。
tsui
2019-11-17 02:44:49 +08:00
想学 Github 不用 framework,也得看自己有没有那两把刷子呀,自己有还得看队友有没有,不然真的是闲的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/620247

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX