首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
Coding
V2EX  ›  JavaScript

探讨前端组件化

  •  
  •   hfcc8685 · 26 天前 · 2110 次点击

    一. 现状

    现在我接手一个项目”好货网”, 该项目已经上线两年, 我的 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, 没有结果, 中间肯定还有很多坑…. , 这是个漫长的过程, 但是会有完成的那天的, 毕竟时间如白驹过隙, 岁月又曾绕过谁呢

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

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



    你洋洋洒洒写了一大堆,其实没必要,如果前后端分离,那么好说,前端直接用 vue/react 等这些流行框架重构就行,做好组件化。如果前后端不分离,那就麻烦了,后端也得重构。总之这种项目我说难听点就是屎山,唯一解决方式就是大换血,你要说开发人员不会用框架、学习成本高耗不起时间,那就是死局。
        19
    OSF2E   26 天前
    说点题外话。
    React 的 Hook 没出现之前,我做前端项目的时候跟你基本是一个思路,而且从 IE6 时代开始就推崇原生和手撸。
    React 的 Hook 没出现之后,我自认为我对前端架构的认识已经提升到了第三层。简单说下我自己的分层方案,第一层是使用原生 html/css/js 纯意识流手糊代码;第二层,是采用业内主流技术栈(三大框架,ES6、Typescript、webpack 等),配合 NPM 第三方包,用最能 [被同行认可标的姿势] 去糊 [代码质量完全无法自主控制] 的项目;第三层,悟出了产品、视觉、交互、前端、后端 [单向数据流风格] 的协作流程。
        20
    tsui   26 天前
    想学 Github 不用 framework,也得看自己有没有那两把刷子呀,自己有还得看队友有没有,不然真的是闲的
        21
    learningman   26 天前 via Android
    纯手写。。。我初中那会儿可能会这么写吧
        22
    seki   26 天前   ♥ 1
    我觉得 9102 年的前端负责人如果还感觉不到 mvvm 框架相对于原生 js 在工程方面的优势的话,那还是挺可怕的
        23
    wunonglin   26 天前 via iPhone
    楼主牛逼,楼主万岁
        24
    yesvods   25 天前
    上百人团队都不敢这么干,太闲了吧,开头一股劲,维护火葬场,后面又是一堆坑。
        25
    a852695   25 天前
    讲真 还好我没在这种坑爹公司。。。什么年代了还在用原生 js 搞,用 Vue React 组件库哪里不爽了呢,前后端分离节约的事件去约妹哪里不好了
        26
    g0thic   25 天前
    jQuery 也没用么 赖是真的牛逼
        27
    connection   25 天前
    业务代码原本是 shit。你怎么可能期望换个框架就不是 shit 了。。

    比较正常的方法,是基于你现有的 沉淀出可用组件。将现有的可复用抽离。
    shit 就让它 shit 吧。

    并不是很推荐基类。
    记得以前接过一个老的 react 项目,也是基于基类+mixin 的方法,后面维护起来 根本没人敢动基类内容。维护性并不高。
        28
    angel001ma   25 天前
    支持#1
        29
    Solael   25 天前
    对团队水平没信心还要重新造轮子,自求多福
        30
    cuzfinal   24 天前 via Android
    重新招点会 vue 的人比较容易。
        31
    MikeFeng   24 天前
    花个几天学 Vue 比你花十几天写自己的原生 js 框架效率不是更高?你自己写的框架有 Vue 的三分之二稳?
        32
    Chenamy2017   24 天前
    4.1 你再考虑一下。本人 C 程序员一个,很快就能上手 vue,何况你们是前端出生,这是要给前端抹黑吗?
        33
    cocolate   24 天前
    纯 js 写成这样就别折腾了吧
    你的需求已经算半个框架了,不用现成的框架是何苦呢
        34
    gaigechunfeng   24 天前
    我一个 android 底层开发,写 C 的,都学会 vue 了。你们 js 基础那么好,一周的时间也掌握了 vue 了吧。
    react 也行。
    感觉这么写造轮子,又是一个坑
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2043 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 30ms · UTC 00:24 · PVG 08:24 · LAX 16:24 · JFK 19:24
    ♥ Do have faith in what you're doing.