IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Web-IM 系统的前端设计与实现

    BelinChung发表于 2015-01-23 11:34:15
    love 0

    写在前面

    从14年3月份入职之后,就一直在跟公司的一个即时 IM 的 Web APP 。15年已经来了,博客还没有一篇更新,就来聊聊在做这个 APP 的时候遇到的一些坑和一些总结吧。由于刚开始经验有限,所以在系统设计方面有很多的缺陷和不足,随着知识的积累,通过不断调整项目目录和一些规范,最终变成了下面的前端模型。

    设计理念

    期间重构时受到 UC前端工程实践.pdf 模块化开发 开发思想的影响,我们也在 APP 中引入了 模块化 的概念。正如里面所说:我们希望能像搭积木一样开发和维护系统,最终通过组装模块得到一个完整的应用。

    • 模块是可组合、可分解和更换的单元
    • 模块具有一定的独立性
    • 将模块所需的js、css、图片、模板维护在一起 ( 我们未采用 )
    • 组件生态,同团队不同项目之间能有可复用的模块

    技术选型

    前端构建工具:F.I.S

    我们在 FIS 和 Grunt 之间选择了后者 - 国产的 FIS ,基于如下的考虑:Grunt 是一个基于 task 的构建工具,依赖众多的插件进行配置组织,可以解决基本的前端自动化问题。FIS 是基于工具、开发框架、本地开发环境为一体的前端解决方案,不但拥有各类工具插件,同时还针对 PC、Mobile、I18n 等业务、场景总结了很多最佳实践。简单来说就是 FIS 更适合大型工程化的项目。

    模块加载器:RequireJS

    通过 fis-postprocessor-amd 的支持,FIS 能很好的支持 amd ,完全满足 amdjs 规范。至于选择哪个模块加载器,似乎也不是特别重要。

    动态样式语言:Less

    没啥好说的,你喜欢 less 就用 less ,喜欢 Sass ,就用 Sass 。

    MV* 框架:Vue.js

    我们觉得 MV* 框架的选择非常重要,这关系着项目开发进度和后期维护。前端的轮子很多,我们不是大厂,没有实力也没有必要自己去造一个。一开始的提议是选用 Angular ,但是考虑到 Angular 的入门门槛,后期维护难度会加大,我们最终选择了 Vue.js (未考虑 IE 8- 的兼容)。

    主要原因大概是:Vue.js 更灵活,允许你按照自己的方式来架构你的程序,而不是所有事情都必须按照 Angular 的方式运行;Vue.js 比 Angular 简单的多,所以你可以在很快的时间内学到它所有的东西然后变得更有效率。
    由于 Vue.js 关注点在 MVVM 模式的 ViewModel 层,所有还需要额外的第三方库进行支持。

    vue-router: flatiron/director
    vue-resource: jQuery Ajax

    开发目录

    并不是所有的项目都适合下面的开发目录。不同的开发模式、协作、打包策略都会影响都会影响开发目录的结构,其实没必要纠结哪种开发目录更美观、更合理。还是根据实际的需求不断的调整,直至它更适合你们团队、项目。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    Project
    |-- i18n
    |-- index.js
    |-- index-zh_CN.js
    |-- script
    |-- util
    |-- module
    |-- home
    |-- index.js
    |-- service.js
    |-- main.js
    |-- style
    |-- common
    |-- widget
    |-- dialog
    |-- index.less
    |-- index-red.less
    |-- module
    |-- home
    |-- index.less
    |-- index-red.less
    |-- index.less
    |-- index-red.less
    |-- template
    |-- widget
    |-- dialog.tpl.html
    |-- module
    |-- home.tpl.html
    |-- index.tpl.html
    |-- vendors
    |-- jquery
    |-- jquery.js
    |-- index.html
    |-- fis-conf.js

    子目录基本上是按照结构、样式和脚本来划分。细化到各个子目录,基本上是按照模块来划分,关于结构,也就是模板,可能很多时候一个模块的模板可以将其融合在一个文件中,所以就没有单独建立一个目录,如果一个模块的结构比较复杂,可以像脚本和样式那样来建立相应的模块目录。各个模块会有相关的主题外观。

    开发一个组件

    Vue.js 允许你把扩展的 Vue 子类当曾一个可重用的组件,概念上和 web 组件一样,但是不需要任何填充。为了创建一个组件,只需要使用 Vue.extend() 来创建一个子类的构造函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    //script/main.js
    new Vue({
    el: 'body',
    data: {
    currentView: 'home'
    },
    components: {
    login-component: require('login/index'),
    home-component: require('home/index'),
    archive-component: require('archive/index')
    }
    })
    ```
    ``` javascript
    //script/moudle/login/index.js
    define(function(require,exports,module) {
    var Vue = require('Vue');
    var store = require('services/store');
    var service = require('login/service');
    module.exports = {
    replace: true,
    template: __inline('login.tpl.html'),
    data: function () {
    return {
    email: '',
    password: '',
    errorTip: null
    }
    },
    filters: {
    emailValidator: {
    write: function (val) {
    this.errorTip = (appFunc.isEmail(val)) ? null : '邮箱必须是Email';
    return val
    }
    },
    pwdValidator: {
    write: function (val) {
    this.errorTip = (appFunc.isPasswd(val)) ? null : '密码在6-18位之间';
    return val
    }
    }
    },
    methods: {
    loginSubmit: function () {
    var data = {
    email : this.email,
    password: this.password
    };
    if(!this.errorTip & data.email !== '' && data.password !== '') {
    service.login(data, function(res){
    if(res.result){
    store.setCurrentUser(res.message.sid, res.message.user);
    appRouter.setRoute('index');
    }
    });
    }else{
    this.errorTip = '请输入正确的账号、密码'
    }
    }
    }
    };
    });

    打包部署

    通过配置 FIS 的,我们能对产出的代码进行 资源压缩 添加文件版本 资源合并 添加CDN域名 应用打包 , 其中 应用打包 比较蛋疼,我还在研究如何配置才能达到我最终想要的打包效果。

    项目通过 git hook 进行部署和更新。通过生产服务器上的 FIS 对仓库源码进行编译,编译目标指向 APP 目录。

    写在最后

    虽然标题上写着 设计和实现 ,但是本文基本上还是介绍系统的设计为主。希望有时间能写下 Web-IM 的一些实现,主要是 IM 这块比较有意思。

    因为前端的数据和界面都通过 WebSocket 主动通知来进行更新,为了减少模块间的耦合,我们还引入了一套基于事件的模块间的消息传递的组件。而且,因为 Vue.js 拥有数据双向绑定的能力,处理起频繁更新的 VM 层还是相当便捷的。

    大概就写到这里了,想到了就写下来,不然过几天又忘了。



沪ICP备19023445号-2号
友情链接