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配置多页面的步骤:-
vue.config.js的pages选项中 添加一条记录,例如:login: { entry: "src/login.js", // 入口文件 template: "public/login.html", // 模板文件 filename: "login.html", // 生成文件 chunks: ['chunk-vendors', 'chunk-common', 'login'] // 公共和第三方模块提取 } -
进入
/public添加一个模板文件,如上配置的login.html,模板文件可以参照其他页面来写 -
进入
/src添加一个入口文件,如上配置的login.js,这里面的配置同样参照其他页面 -
在
/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等
命名规范
-
html和css样式的属性名、类名等不得大写,可以是小驼峰,建议使用-来连接多个逻辑断点,例如:login-form、login-button -
css尽量做到可扩展,每个组件至少需要一个模块名。模块布局和内容结构使用__来标记;模块状态、主题相关的结构使用--标记。例如:nav-item、nav-item__title、nav-item--active。 -
国际化变量名应当使用小写, 当存在多个逻辑断点时,可以用
_来连接,例如:no_login_tips、start_trade_now -
目录和文件名通常小写,逻辑组件(
.vue)和类文件可以使用大写。vue组件在html文件中推荐使用小写的标签引入,例如:<secondary-nav></secondary-nav> <!--推荐--> <SecondaryNav /> <!--不推荐--> -
命名要见名知意,采用习惯用语,例如:
login、sign-in、而非landing等。由于历史原因,很多命名并没有严格遵循此规范,可以逐步迭代。
代码规范
-
html模板内容采用
H5布局标签,尽量做到语义化,满足SEO需求。例如:使用header footer main section等替代div.header、div.footer等,h1~h6替代div.title,使用figure关联图片和文字,多使用em和strong替代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); } ) -
分页原则:对于列表数据,后端接口普遍支持分页获取,但从体验角度说 推荐前端进行分页。
-
对于大量记录的值,通过接口参数
pageSize和pageNo查询指定页码的数据,每次点击页码时都需要发送一次请求。 -
对于百条级别数据,给
pageSize一个超出值并设置pageNo为1,这样一次性取出所有,接下来使用element Pagination组件实现前端分页。例如 理财产品列表。
-
-
插件管理:对于复用的功能,除了封装组件外,也有提取的插件,例如
sliderCaptcha、Kline等:- 公共组件统一放置在
src/components目录并已经全局加载,在vue文件中可以直接使用 - 插件统一放在
public/目录,在页面中 多以iframe方式引入,
- 公共组件统一放置在
目录文件
icomoon
字体图标库管理文件,使用iconmoon 图标库,
demo-filesfonts图标字体库文件,包含常用格式.eot, .svg, .ttf, .woffselection.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: 第三方库文件和工具包,为减小打包时
vendor和common文件的体积,多采用cdn方式下载- element-ui
- index.css element样式文件
- index.js 核心功能模块
- 图标字体文件,缺少此文件时 element界面中会缺少图标
locale,element组件本身的国际化包 支持中英文(zh-CN,en)
- swiper
- vue全家桶文件:
vue+axios+vue-router - fastclick:处理移动端点击
300ms延迟 - lodash库
- element-ui
- 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.jsaxios惯例配置文件index.jsaxios 功能接入模块文件,该文件中设置了请求loading、请求错误拦截等 最终返回一个server对象
- member.js 用户模块相关的接口
- market.js 行情页面相关的接口
- coinTrading 币币交易(exchange)页面接口
- server目录
- assets:打包资源目录
- fonts:字体库文件,包含英文字体(
metropolis)和等宽的数值字体(opensans) - html:公共头部和尾部的
html文件 - i18n:国际化语言包
- icons:字体图标库文件
- images:打包的图片
- styles:所有页面的样式
- common:公共样式文件
- assets:资产页面样式文件
- ...
- fonts:字体库文件,包含英文字体(
- components:公共组件目录,目前只封装了导航栏的组件
- introduce:
- router:路由文件地址,在
index.js中完成加载 - store:
vuex数据 - utils:自定义方法库文件,
- views:页面视图组件
- Home:首页
- Login:包含登陆、注册、忘记密码
- Financial:理财产品
- Exchange:现货交易
- Contract:合约交易
- ContactUs:联系我们
- Assets:资产,包含主账户资产、合约账户资产管理、理财账户资产管理、委托订单管理、充值提笔、账户安全等
- Detail:交易历史数据
- Article:博客
- main.js:这里代表每个页面的入口文件... 例如
article.jsassets.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引入该文件即可,注意:需要传入一些必要参数:交易对编号id和k线类型<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请求地址更新为正式服务器