You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

22 KiB

---11111111111111111111 ​--- title: virgox-global前端项目文档 date: 2020-07-03 09:25:00 author: lautin 1538731090@qq.com summary: 该文档用于技术分享,项目说明和工作交接,不得商用! categories: Markdown tags:

  • Typora
  • Markdown node版本:14.16.1 npm版本:6.14.12 ​---

项目架构

框架环境

virgox-global,以下简称VG ,基于vue-cli3+开发,使用MPA结构,整站分为以下几个页面:

  • 首页
  • 现货交易
  • 合约交易:包含永续合约外汇合约
  • 理财
  • 联系我们
  • 学院:包含入口展示分类列表详情页
  • 登录模块:登录页注册页忘记(重置)密码
  • 个人中心:资产、合约账户、理财账户、资金划转、现货委托、合约委托、充提记录、账号安全等

每个页面维护一套独立的SPA环境,拥有自己的模板文件入口文件路由模块 等,其他文件如:静态资源、工具包、接口模块为公用。页面之间为超级链接连接,页面内为**hash**路由,为达到兼容目的,将每个SPA设为history模式 :

// router/index.js 文件
export default new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

采用MPA是为了更好的对每个页面进行差异化管理,虽然页面的总体结构相同,但细节差别很多,总体来说体现在以下几个方面:

  • 网页头部SEO 以及页面所需的依赖环境不同
  • 页面头部样式不尽相同,有包含背景色,有包含背景图,并且背景图往往自头部渗透到内容区,和当前页面的耦合度高。
  • 移动端适配的需求不同,除了基本的视口外,部分页面需要特殊处理:例如 登陆、注册页、文章详情页等

有了MPA ,我们可以定制不同的HTML模板满足不同页面的需求,例如:在登陆页面,头部和内容区放在一个容器 设置整体的背景,并且头部单独设置了移动端的下拉菜单aside

<!--login.html-->
<div class="main-bg">
    
    <aside>
    	<!-- 移动端下拉菜单 -->
    </aside>
    
    <!-- 页面头部内容 -->
    <% include('../src/assets/html/header.tpl') %>
    <entry id="app"></entry>
    
</div>

vue/cli@3

  • vue/cl3配置多页面的步骤:

    1. vue.config.js pages选项中 添加一条记录,例如:

      login: {
          entry: "src/login.js", // 入口文件
          template: "public/login.html", // 模板文件
          filename: "login.html", // 生成文件
          chunks: ['chunk-vendors', 'chunk-common', 'login']  // 公共和第三方模块提取
      }
      
    2. 进入/public添加一个模板文件,如上配置的login.html,模板文件可以参照其他页面来写

    3. 进入/src添加一个入口文件,如上配置的login.js,这里面的配置同样参照其他页面

    4. /src/router中添加路由文件,并设置该页面的路由入口

  • vue/cli3接入的是vue中间配置,不直接匹配webpack,具体的配置项需要参照官方文档配置参考。如果要检查vuecli配置结果,可以通过vue inspect指令导出到文件,默认根目录中已经存在output.js

elementUI

UI框架选型为ELEMNET,为了适配当前站点风格,我们改写了element样式。虽然ELEMENT本身可以定制主题,但功能有限且调试麻烦,因此我们选择手动重置element默认样式,即src/assets/style/Common/ele.less文件。

公共头尾

虽然每个页面头和尾的样式有所区别,但总体而言,结构和内容是相同的。为了便于维护,需要将它们提取为公共文件。公共文件中只包含基本样式,页面的特定样式还需要在每个模板文件中单独处理,例如 上面login.html中重置头部的背景图片:

<!--login.html-->
<style>
    .main-bg {
        background: rgb(17, 10, 22) url(<%= require ('../src/assets/images/Registration-bg@1x.png') %>) 
            no-repeat left top;
        background-size: 100% auto;
    }
</style>

公共文件作为静态资源放入src/assets/html目录中,默认扩展名.tpl。模板文件通常是.html,但服务端部署缓存时 可能是统一设置html文件, 为了与其他html资源区分,这里特别改为.tpl勿动

公共头尾文件,虽然放置于src打包目录,但它是以模板引擎方式的方式加载,而不在打包资源(入口文件)中,因此不能以vue环境编码。模板为html单页面应用环境,头尾部的动画和数据交互使用jquery,需要注意以下几点:

  • 头部样式遵循BEM规范,并且将导航封装为样式组件,用法参见src/assets/style/common/components.less
  • 头尾的样式为全局加载,无需手动引入。样式文件目录同导航组件一起:~/header.less~/footer.less
  • 头尾的国际化,使用jquery.$i18n ,该库存在一个bug -- 每次总是先查找strings.properties文件配置再查询相应的语言包。解决办法是,将所有变量在strings.properties中复制一份,默认空值,避免查询不到返回错误。当然如果你觉得这样不够优雅 也可以修改它的源码,不过需要谨慎操作。

规范说明

代码工具

编辑器推荐使用vscode,安装一下插件:

  • vue-helper 支持方法跳转
  • vue-format
  • vue 语法高亮
  • html snippets 支持管理各种类型的html文档 包括.tpl .art .html等

命名规范

  • htmlcss样式的属性名类名等不得大写,可以是小驼峰,建议使用-来连接多个逻辑断点,例如:login-formlogin-button

  • css尽量做到可扩展,每个组件至少需要一个模块名。模块布局和内容结构使用__来标记;模块状态、主题相关的结构使用--标记。例如:nav-itemnav-item__titlenav-item--active

  • 国际化变量名应当使用小写, 当存在多个逻辑断点时,可以用_来连接,例如:no_login_tipsstart_trade_now

  • 目录和文件名通常小写,逻辑组件(.vue)和类文件可以使用大写。vue组件在html文件中推荐使用小写的标签引入,例如:

    <secondary-nav></secondary-nav> <!--推荐-->
    <SecondaryNav /> <!--不推荐-->
    
  • 命名要见名知意,采用习惯用语,例如: loginsign-in、而非landing等。

    由于历史原因,很多命名并没有严格遵循此规范,可以逐步迭代。

代码规范

  • html模板内容采用H5布局标签,尽量做到语义化,满足SEO需求。例如:使用header footer main section 等替代div.header、div.footer等,h1~h6替代div.title,使用figure关联图片和文字,多使用emstrong替代span

  • css样式采用less编码,css代码应当遵循BEM规范,即可扩展和可维护的css,在设置效果时 需要有效分离 布局、内容、状态、主题这些因素,目前只在头部的代码中能看到这样的风格。对于常规样式和操作,做了统一的设置和封装,它们都被放在了src/assets/styles/Common目录中:

    • 对于全局设置,例如 字体、图标、颜色等在varibles.less中配置,这样确保站点内所使用的颜色是一致的:

      // varibles.less
      @cls-purple : rgba(193, 187, 242, 1); // 经典浅紫色
      // exchange & contract
      @claret : #FF5959; // decreace 酒红色
      @turquoise : #25BC67; // increace 青绿色
      
    • 对于常用样式块,例如 弹性盒子、字体相关等 有封装函数:

      // functions.less
      .font(@face, @size, @lineH, @clr: inherit, @weight: normal, @style: normal) {
          .ff(@face);
          .fs(@size);
          // 行高传入一个非数字值时 使用默认的normal值
          line-height: if((isnumber(@lineH)), ~"@{lineH}px", normal);
          color      : @clr;
          font-weight: @weight;
          font-style : @style;
      }
      
    • 处理页面自适应时 优先使用弹性盒子,弹性盒子应该有类似这样的封装,历史原因 只有混入类样式 而无样式函数

      // base.less
      .mainFlex-row {
          .mainW;
          .flex-row;
      }
      
      .mainFlex-column {
          .mainW;
          .flex-column;
      }
      
      .w100Flex-row {
          .w100pc;
          .flex-row;
          align-items: center;
      }
      
      .w100Flex-column {
          .w100pc;
          .flex-column;
          align-items: center;
      }
      
      // 如果有时间 建议替换成下面的函数
      .flexible(@direction :  row, @horizontal : flex-start, @vertical : flex-start) {
          display : flex;
          flex-direction : @direction;
          justify-content : @horizontal;
          align-items : @vertical
      }
      
    
    
    
  • js逻辑代码优先使用es6语法,方法则推荐lodash库,不足部分自己封装,

    • 封装方法有三种使用形式:

      • js中使用 utils.方法名() 调用,例如: utils.omitTo(1.234, 2)

      • 封装方法 也被植入内置对象中,你还可以使用内置对象来访问:Math.omitTo(1.234, 2)

      • 所有封装方法都可作为vue过滤器使用,例如:<span>1.234|omitTo(2)</span>

        // 每个页面的入口文件 例如 src/index.js
        Object.keys(utils).forEach(key => {
            Vue.filter(key, function (value, ...args) {
                if (utils[key] instanceof Function) {
                    // 将value作为第一个参数值,剩余参数分别传入方法中
                    return utils[key](value, ...args);
                }
            });
        });
        
    • 使用_.throttle()替代自定义的 utils.throttle(),自定义防抖和节流方法只是一种探索和尝试,寻求心理上的平衡而已

    • 自定义方法 主要是针对一些非常规的需求,例如 处理小数点精度、格式化日期时间、文件上传操作封装等

业务规范

  • 后端接口返回值会结构为:{status, code, message, data};在axios请求时 会拦截返回值,对于code != 0或者status != true 统一拦截,输出message提示。

    server.interceptors.response.use(
        // 请求成功
        response => {
            let { code, msg, data, success } = response.data;
            if (!success && code != 0) {
                // 错误提示...
                // 进入catch
                throw new Error(msg);
            }
            return response.data;
        },
    
        // 请求发生错误
        error => {
            let message = ret.includes("timeout") ? "连接超时!" : "系统错误!";
            // 错误提示 ...
            // 进入catch
            throw new Error(message);
        }
    )
    
  • 分页原则:对于列表数据,后端接口普遍支持分页获取,但从体验角度说 推荐前端进行分页。

    • 对于大量记录的值,通过接口参数pageSizepageNo查询指定页码的数据,每次点击页码时都需要发送一次请求。

    • 对于百条级别数据,给pageSize一个超出值并设置pageNo为1,这样一次性取出所有,接下来使用element Pagination组件实现前端分页。例如 理财产品列表。

  • 插件管理:对于复用的功能,除了封装组件外,也有提取的插件,例如 sliderCaptchaKline 等:

    • 公共组件统一放置在 src/components目录并已经全局加载,在vue文件中可以直接使用
    • 插件统一放在public/目录,在页面中 多以iframe方式引入,

目录文件

icomoon

字体图标库管理文件,使用iconmoon 图标库,

  • demo-files
  • fonts 图标字体库文件,包含常用格式.eot, .svg, .ttf, .woff
  • selection.json 升级图标库时 需要上传该文件 包含原有的图标
  • demo.html 演示文稿 查看图标样式和对应字符
  • style.css 演示文稿加载的css样式

public

存储非打包和用于缓存的资源

  • img: 非打包环境中使用的图片 以及 需要缓存的图片,具体包括有:
    • 404和维护页面所使用的图片
    • bg-index.png 首页头部背景图,因图片较大 放在此处非打包环境中 便于缓存
  • kline: k线包,支持在页面中 使用iframe方式引入,在币币交易和合约交易页面使用
    • <iframe src='~/kline.index.html?type=1&id=91'> type用来区分现货或合约,id确定具体交易对行情
  • lang: 页面公共头部和尾部的语言包,包含三个文件,中英文国家化分别对应_cn$_en$的文件
  • libs: 第三方库文件和工具包,为减小打包时vendorcommon文件的体积,多采用cdn方式下载
    • element-ui
      • index.css element样式文件
      • index.js 核心功能模块
      • 图标字体文件,缺少此文件时 element界面中会缺少图标
      • localeelement组件本身的国际化包 支持中英文(zh-CNen)
    • swiper
    • vue全家桶文件:vue + axios + vue-router
    • fastclick:处理移动端点击300ms延迟
    • lodash库
  • sliderCaptcha 滑块验证码,支持在页面中使用iframe方式引入,在登陆和注册时使用
    • <iframe src='~/sliderCaptha/index.html?sliderType=register&callback=&account'>
    • 参数sliderType表示注册或登陆类型,account为要验证的账号,callback为验证成功后的回掉
  • favicon.ico 站点收藏夹图标
  • 各个页面模板文件:index.html(首页) login.html(登陆) assets.html(个人中心)......

src

运行时代码

  • api:接口封装文件
    • server目录
      • conventions.js axios惯例配置文件
      • index.js axios 功能接入模块文件,该文件中设置了请求loading、请求错误拦截等 最终返回一个server对象
    • member.js 用户模块相关的接口
    • market.js 行情页面相关的接口
    • coinTrading 币币交易(exchange)页面接口
  • assets:打包资源目录
    • fonts:字体库文件,包含英文字体(metropolis)和等宽的数值字体(opensans
    • html:公共头部和尾部的html文件
    • i18n:国际化语言包
    • icons:字体图标库文件
    • images:打包的图片
    • styles:所有页面的样式
      • common:公共样式文件
      • assets:资产页面样式文件
      • ...
  • components:公共组件目录,目前只封装了导航栏的组件
  • introduce:
  • router:路由文件地址,在index.js中完成加载
  • store:vuex数据
  • utils:自定义方法库文件,
  • views:页面视图组件
    • Home:首页
    • Login:包含登陆、注册、忘记密码
    • Financial:理财产品
    • Exchange:现货交易
    • Contract:合约交易
    • ContactUs:联系我们
    • Assets:资产,包含主账户资产、合约账户资产管理、理财账户资产管理、委托订单管理、充值提笔、账户安全等
    • Detail:交易历史数据
    • Article:博客
  • main.js:这里代表每个页面的入口文件... 例如 article.js assets.js
  • vue.config.js:webpack配置文件
  • 其他配置文件

全局组件

按钮

通用的按钮组件,主要是适配当前站点风格,支持多种状态,封装属性如下:

属性 类型 默认值 说明
width Number null 按钮宽度
height Number null 按钮高度
background String true 按钮背景色,
true表示背景样式 false表示边框样式 rgba() 指定背景色
clickable Boolean true 是否可点击,如果不可点击 则加载禁用样式
@click Function null 订阅点击事件,
<v-button :width="" :height="" background="false" :clickable="false"></v-button>

验证码

发送验证码的组件,支持倒计时和初始化自动发送,内置了几种不同环境的发送接口,登陆时的短信和邮箱验证等:

属性 类型 默认值 说明
type Number 1 1为请求短信登陆的验证码
2为请求邮箱登陆的验证码
5为通用的短信验证码
6为通用的邮箱验证码
account String null 短信接口所需的参数,账号或者nonce值,
统一使用该参数发送
autosend Boolean true 是否自动发送,如果为true 则初始化执行发送任务
width Number null 发送按钮的宽度,继承自v-button的属性
height Number null 发送按钮的高度,继承自v-button的属性
background String true 按钮背景色,继承自v-button的属性
<verify-code :type="1" :account="user.nonce" :autoSend="isFirst"></verify-code>

弹框

v网定制的弹框,适配v网风格,支持拖拽:

属性 类型 默认值 说明
width Number 400 内容区宽度
opacity Number .7 遮罩层透明度
title String System Tips 盒子标题
movable Boolean true 窗口是否可移动,默认不可移动
hideclose Boolean false 是否禁用关闭按钮,默认不禁用
load Function null mounted对应的钩子函数
close Function null 关闭蒙层时的回调动作
simple Boolean false 简洁模式,去除了标题
<v-box :width="435" :title="资金划转" :opacity="0.5" v-model="showTranster" :movable="false" @onclose="reset">
    <!-- 内容区 -->     
    <div class="transferBox chkBox">
           <!-- ... -->      
    </div>
</v-box>

表单验证

登陆模块

登陆和注册表单数据的前端验证和样式基于H5并且有封装Validate工具类,在提交表单时调用utils.validate(fm),其中validate为工具类调用方法并内置于utils对象中。validate方法返回布尔值表示验证是否通过,它有一个参数fm指代表单控件所覆盖的区域,你只需指定一个包含了所有验证控件的容器即可,例如:

<!---将.register-body绑定即可--->
<div class=".register-body">
    <input type="text" />
    <input type="password" />
</div>

对于每个输入控件的具体验证规则,则通过h5的属性配置即可,这里需要注意的是验证提示信息 遵循规则:

  • require 为空性验证提示 采集顺序为: data.has -> placeholder -> ${name} 不能为空
  • 其他输入框返回提示信息 采集顺序为: data.message -> placeholder -> 输入不符合要求
<div class=".register-body">
   <el-input v-model="user.parentCode" name="parentCode" pattern="^\w{8}$" 
             data-message="邀请码应该为8位长度字符">
   </el-input>
   <button @click="handle">
       登陆
   </button>
</div>

<script>
   methods : {
       handle() {
           if (utils.validate('.register-body')) {
               // 验证通过 执行后续任务
               // 验证不通过 页面会反馈h5提示信息
               
           }
       }
   }
</script>

交易表单

交易页面的表单验证和样式基于element组件,通过组件输入限制+Popover弹框提示实现,对于element输入控件和提示框的使用具体见官方文档。

文件上传

个人认证页面需要提交用户材料证明,提供了文件上传并预览的功能。为了方便对文件上传过程进行管理,封装了Upload工具类,同样内置于utils对象中。utils.uplode()支持对上传文件进行基础信息验证,如 文件类型、文件大小等。upload返回一个Promise对象,上传失败返回错误号,上传成功返回文件信息:

  • success 返回值:
    • file:File对象
    • name : 文件信息
    • data : 文件数据, 如果是图片返回base64格式文件数据,如果是txt返回utf-8编码的内容
  • error 返回值:
    • errno : 错误代号 101(类型不合法) 102 (大小超出) 103(意外失败) 104(发生错误)
utils.upload({
    ele : 'avatar', // 事件源DOM
    allowType : ['image/jpeg', 'image/png'], // 合法的mime文件类型
    allowSize : 2, 	// 限定文件大小,单位M
}).then(result => {
    console.dir(result);
})

K线包

  • 图表库使用基于tradingView封装的包 -public/kline/

    • 现货交易和合约交易,统一使用该图表库,因此在业务设计时需要区分处理

    • index.html 为外部引入文件,在使用时通过iframe引入该文件即可,注意:需要传入一些必要参数:交易对编号idk线类型

      <iframe class="chart" ref="assembly" :src="/kline/index.html?id=91&type=1"></iframe>
      
  • K线包主要的配置文件为 /kline/datafeeds/wsconfig.js 这里面用来配置websocket请求数据:

业务模块

首页

登陆注册

现货交易

合约交易

上线流程

  • 更新bug状态并在项目根目录下CHANGLOG.md补充本次更新的内容
  • 本地npm run build 打包源码 生成dist包,手动添加版本号;或者在线上环境打包也可
  • dist包使用ftp提交到测试服务器并通知测试人员
  • 与运维沟通,测试转移正式环境时 需要调整的内容,例如 websocket请求地址更新为正式服务器