前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于 VUE 技术栈的大前端三层架构简略

基于 VUE 技术栈的大前端三层架构简略

作者头像
LIYI
发布2019-09-02 17:20:02
1.3K0
发布2019-09-02 17:20:02
举报
文章被收录于专栏:艺述论专栏艺述论专栏

这里讲的架构,不是指一个项目的架构,而是指一个公司、一个团队所有整体项目的架构。

共分为上下三层:

  1. 项目层(包括具体的项目ABC,与公司业务密切相关)
  2. 组件层(包括 DAL 库及可复用UI组件库,与公司业务弱相关)
  3. 工具层(包括与具体项目无关的工具类库,与公司业务无关)

图表如下所示:

Q/A

1,项目中涉及到的网络请求如何处理?

统一放在第3层,可以由一个Http.js统一负责,包括JWT验证,token 验证都可以放在 Http.js 中自动处理。

在 Http.js 中可以引用 axios 或其它第三方类库。

关于接口缓存,也可以在Http.js中完成。示例代码:

代码语言:javascript
复制
let cache = {}; //数据缓存池
...
function bizGetCache(url, params) {
  // 接口数据之临时变量
  let data
  if (data = cache[url]) {
    return new Promise(function(resolve, reject) {
      resolve(data);
    });
  } else {
    return Http.bizGet(url, params).then(res => {
      return (cache[url] = Http.getData(res));
    });
  }
}

在以上代码中,以接口的 url 做为 key,在用户本地内存中缓存接口返回的数据对象。仅缓存,数据有效性、完整性不作任何判断。

2,如何处理错误?

项目中出现的错误共有三类:

  • 逻辑错误,例如变量为空、方法未找到等等,这类错误要在开发阶段解决,可能存在于任一层次。
  • 数据错误,数据完整性、安全性错误,这类错误发生在运行阶段,在第一层具体项目中处理。谁消费,谁调用,谁负责处理和验证接口返回的数据有效性、完整性及安全性。
  • 网络错误及底层错误,网络错误指http请求错误或websocket信令错误;底层错误来源于执行环境,发生在 Android、iOS 环境或 PC 客户端 CEF 环境等。这类错误发生在运行了阶段,无法在开发阶段完全避免。

所有错误统一这样处理:

在第三层完全使用throw抛出;在第二层DAL中,所有接口统一使用catch接管;最终在第一层具体项目中统一处理所有一般性错误,方式方法例如可以发出一个弹窗。

3,为什么要设立 DAL 层?

对于前端项目,所有项目都涉及到接口调用,而这些接口调用可能在多个项目中是重复的,但这些接口的调用方式及传递的参数却是固定的。将之放在一个地方,以链式方式提供,可以显著减少开发成本、提高复用效率。

例如,api 目录下 index.js 源码示例如下:

代码语言:javascript
复制
import classroom from './classroom'
import account from './account'
import consts from './consts'
import im from './im_adapter'
import lesson from './lesson'
import cef from './cef'
import track from './track'

export default {
  account,
  classroom,
  consts,
  im,
  lesson,
  cef,
  track
}

每一个文件,例如 classroom、account 等,均对应于后端一个 controller 类。

在使用 api 时,这样引用:

代码语言:javascript
复制
import api from '@/api'

这种声明和调用方式具有形式上扩展的自由。例如,当接口很少时,可以只定义 api.js 这样一个接口文件;当接口复杂数量增多后,可以扩展一个 api 目录,并声明一个 index.js 文件,但此时旧的引用代码不用修改。

在vue组件中调用具体 api 的代码是这样的:

代码语言:javascript
复制
let res = await api.classroom.markQuestionStatusCloseBarrage(
  api.consts.classroomId,
  api.consts.lessonId
);

基于 api 的链式调用,链条相当于其它语言(例如Java、C#)的命名空间。

4,接口对象如何声明?如何实现继承?

子接口对象模块有两种输出方式,一种是输出类,另一种是输出对象。默认状态中,放在 api 访问链条中的子对象均以对象的形式输出。

对象输出的模块,相当于输出了一个全局 的singleton 类。

如果要在一个对象中,实现对另一个对象的继承,被继承者必须以类的形式输出,代码示例如下:

代码语言:javascript
复制
class Emiter{
  constructor() {
    this.events = {};
  }
  $on(event, cb) {
    //多个事件
    if (event instanceof Array) {
      event.forEach(fn => $on(fn, cb));
    }
    //单个事件
    if (this.events[event]) {
      this.events[event].push(cb);
    } else {
      this.events[event] = [cb];
    }
  }
  
  $emit(event) {
    let args = Array.from(arguments).slice(1);
    let cbs = this.events[event];
    if (cbs) {
      cbs.forEach(cb => cb.apply(this, args));
    }
  }
  
  $once(event, cb) {
    function handler() {
      //先执行回调,然后清除该事件的对应回调
      cb.apply(this, arguments);
      $off(event, cb);
    } //on函数的fn属性添加一个标记,cb,方便循环off清除(提供了事件与回调的时候)
    handler.cb = cb;
    $on(event, handler);
  }
  
  $off(event, cb) {
    if (!arguments) {
      this.events = {};
    }
    if (event instanceof Array) {
      event.forEach(e => $off(e, cb));
    }
    if (!cb) {
      this.events[event] = null;
    }
    if (cb) {
      let cbs = this.events[event];
      if (cbs) {
        for (let i = 0; i < cbs.length; i++) {
          if (cb === cbs[i] || cb === cbs[i].cb) {
            cbs.splice(i, 1);
            break;
          }
        }
      }
    }
  }
}

export default Emiter;

这是一个Emiter类,实现了与VUE事件模式相同接口的事件观察者模式。假如有一个接口对象需要派发事件,可以在对象中这样继承Emiter:

代码语言:javascript
复制
export default {
  __proto__: new Emiter()
  ...
}

而如果子接口对象要输出类,而不是对象(虽然一般不需要这样做,这里只展示实现方式)可以这样实现:

代码语言:javascript
复制
class SomeInterfaceObject extends Emiter{...}

5,关于命名规范

鉴于windows与linux大小写敏感不一致,而命名规范主要关乎大小写,所以这个问题值得重视。命名是小问题,处理不好,代码不易读事小,引起难以跟踪的Bug事大。

  • 所有文件名,使用小写、间以下划线间隔。
  • 所有函数名、方法名使用小驼峰命名法。
  • 所有类名、接口名(JS没有接口这里是伪接口),使用大驼峰命名法。
  • 所有局部变量、文件变量,全部使用小驼峰命名名。
  • 所有常量,任何地方的常量,所有字母大写、间以下划线。
  • 所有被引入的对象或类,对象名使用小驼峰、类名使用大驼峰。
  • 所有css class名称,所有字母小写、单词间以中划线。使用less scoped模式,可以有效避免名字过长。如果是 UI 组件库,需要对处暴露样式名,可以参照weui的做法,以“.”分段。

6,这样三层架构的优点是什么?

  • DAL 数据接口层可以在所有项目中共享使用。
  • 常用的工具类库做为第三层沉淀下来,可以长期在所有项目中复用。即是一种控制,又是一种开发效率的提高。
  • 第一层具体项目层网格请求用第三层,常用组件用第二层,调用接口用第二层中的DAL库,只需要处理页面UI组装及具体业务逻辑代码、交互代码编写,这样可以在一定程度上减少Bug,提高软件质量及开发效率。

不知道我讲明白没有,以上。

石桥码农 2019/04/04

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 艺述论 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Q/A
    • 1,项目中涉及到的网络请求如何处理?
      • 2,如何处理错误?
        • 3,为什么要设立 DAL 层?
          • 4,接口对象如何声明?如何实现继承?
            • 5,关于命名规范
              • 6,这样三层架构的优点是什么?
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档