公司项目主要是做股票及期货行情展示及交易,h5相应的做了一些功能---可以看行情图及模拟交易,实盘交易存在一定的风险,老板希望做自己的产品,这样h5就尴尬了,不过没关系,项目里还是有一定技术含量的---①设计到很多合约品种,场景多及复杂②设计一些功能模块的同时,后台没以前牛气了,这次需要他们的积极配合了(很感谢他们,主要是一些接口的配合),③涉及到大量的数据传输及缓存,④react组件与多组件配合使用(react+router+webpack+highstock+mobx)。下面图片可以说明上述几点问题:
废话不多说,问题如下:
一,官网的react-app脚手架 不支持ES7@装饰器 ,数据层需要用extendObservable 封装。需要用到数据的地方用inject包装获取下,代码如下(颜色字体):
//实时交易状态管理组件
import {extendObservable,observable, action} from 'mobx';// 官网的create_app 不支持es7的@装饰器 用extendObservable代替。
import UrlP from 'api/api';
import HttpP from "mixin/httpPub";
const Store = function(){
extendObservable(this, {//this指的就是 mobx Store
contractName:observable(""),//合约名字
/*历史订单*/
historyOrder:action(function(){
HttpP.NN_historyOrderP({data}).then(
(res)=>{
if(!res.result){
alert(res.message);
}else{
console.log(res)
if (res.result) {
。。。。。
}
}
}
);
}),
})
}
const traderStore = new Store();
export default traderStore;
上面是全局数据层,下面是获取数据dom层。
// 策略页面 import React, { Component } from 'react'; import './index.css'; import pubFn from "mixin/pubFn.js";//公共函数 import {Link,withRouter} from "react-router-dom"; import {observer,inject} from 'mobx-react';//mobx管里页面 可以inject为父级传过来的props const DifOrderList = inject("traderStore")(observer(class DifOrderList extends Component { constructor(props) { super(props); this.state = { }; } componentDidMount () { } /*点击切换持仓 历史 */ typeClick (event) {/*请求订单历史数据*/this.props.traderStore.historyOrder(); } render() {//列表的数量 来判断 合计dom 定位的位置 let style = { top:1.06*arrL+"rem", left:"0", } return ( <div className="difOrderList"> <ul className = "clearfix difOrderListTop"> { this.state.arrTypeChange.map( (Hname,index) => <li className = {Hname.clName} onClick = {this.typeClick.bind(this)} data-type = {Hname.type} key = {index}>{Hname.html}</li> ) } </ul> <ul className = "clearfix difOrderListPro"> { this.state.listA.map( (Hname,index) => <li className = "fl" style = {this.state.styleH} key = {index}>{Hname}</li> ) } </ul> </div> ); } })); export default withRouter(DifOrderList);
二,数据缓存如何去做?
合约列表在每次点击后,二次点击不需要再去后台请求历史数据,一是因为数据量大,二是因为不断请求大量数据,给后台增加好多压力,这样就不得不要求前端在数据层上做一下缓存,首先想到的就是localstorage。但是不同合约有不同分时图,不同k线图,所以数据储存是一个相当棘手的问题。
function FArr() {//三维数组 for (var i = 0; i < 4; i++) { publicArr.push([]); } for (var i = 0; i < 4; i++) { for (var j = 0; j < 8; j++) { publicArr[i].push([]); } } for (var i = 0; i < 4; i++) { for (var j = 0; j < 8; j++) { for (var p = 0; p < 6; p++) { publicArr[i][j].push([]); } } } }
想来想去,用了一个三维数组在本地存储数据,即:合约 k线类型 k线数据。但是在存储的时候,其实用的是合约信息作为属性来切换数组下标的以此存储不同的数据及对应不同的名称:
// 三维数组创建参数
var publicArr = [];
var M1 = 0,
M3 = 1,
M5 = 2,
M15 = 3,
M30 = 4,
H1 = 5,
D1 = 6,
M50 = 7;
var CL = 0,
GC = 1,
FDAX = 2,
HSI = 3;
var OP = 0,
HI = 1,
LO = 2,
CLO = 3,
VOL = 4,
Time = 5;
根据点击的合约,判断对应的下标。
publicArr[typeName][cNewNum][CLO].push(data.close);
publicArr[typeName][cNewNum][OP].push(data.open);
publicArr[typeName][cNewNum][HI].push(data.high);
publicArr[typeName][cNewNum][LO].push(data.low);
publicArr[typeName][cNewNum][Time].push(data.time);
publicArr[typeName][cNewNum][VOL].push(data.volume);
但是那么多合约总不能用户点击一个存储一个,往往这里需要跟后台配合,根据用户习惯及产品需求,前端根据后台字段来判断要不要缓存此数据。
三,不合理写法:不要在render里直接把全局的数据拿来进行渲染(粉色字体),应该按蓝色字体进行修改,
render() {
let ask = this.props.liveStore.handicapNavListObj.ask;
let bid = this.props.liveStore.handicapNavListObj.bid;
return ( <div className="futuresChangeNum clearfix"> <div className = "changeNumTop clearfix"> <div className = "fl clearfix changeNumTopLeft"> <div className = "clearfix changeNumTopLeftTop"> <i className = "fl"></i> <input className = "fl" value={this.props.liveStore.handicapNavListObj.key.contractKey} type="text" onChange = {this.contractNameChange.bind(this)}/> <b className = "fl"></b> </div> <div className = "clearfix changeNumTopLeftBot"> <div className = "fl clearfix changeNumTopLeftBotLeft"> <p className = "fl">手数</p> <h4 className = "fl">{this.state.num}</h4> </div> <div className = "fl clearfix changeNumTopLeftBotRight"> <p className = "fl">价格</p> <h4 className = "fl">{this.state.traderPricetype}</h4> </div> </div> </div> <div className = "fl changeNumTopRight"> <ul> <li className = "clearfix"> <span className = "fl">新</span> <h3 className = "fl">{this.props.liveStore.handicapNavListObj.lastPrice}</h3> <strong className = "fl">{this.props.liveStore.handicapNavListObj.volume}</strong> </li> <li className = "clearfix" > <span className = "fl">卖</span> <h3 className = "fl">{bid}</h3> <strong className = "fl">{this.props.liveStore.handicapNavListObj.bidSize}</strong> </li> <li className = "clearfix"> <span className = "fl">买</span> <h3 className = "fl">{ask}</h3> <strong className = "fl">{this.props.liveStore.handicapNavListObj.askSize}</strong> </li> </ul> </div> </div> </div> ); }
四,在项目里好多地方需要切换画图,不管横屏简单展示还是竖屏技术指标数据展示,都需要第三方插件highstock拿来画图,也就是需要把此插件接口暴露在全局,把highstock封装了一个函数,用extendObservable给暴露在了全局
//第三方画图插件 highstock import Highcharts from 'highcharts/highstock'; import {extendObservable,observable, action, computed, useStrict} from 'mobx';// 官网的create_app 不支持es7的@装饰器 用extendObservable代替。 var linecolor = "#000"; //x y轴线或刻度线的颜色值 var linecolor1 = "#2f84cc"; //k线图的颜色 var bgcolor = "#20212a"; //表格背景的颜色 Highcharts.setOptions({ global: { //设置为中国时间 useUTC: false }, lang:{ rangeSelectorZoom:"" } }); const ChartHcStore = function(){ extendObservable(this, {//this指的就是 mobox Store chartsetK:observable({}), isClickHc:action(function(id,time,data,weekflg,mk){ this.chartsetK = new Highcharts.StockChart(id, { chart: { }, tooltip:weekflg == 'MK' ? { }, //数据提示框。 credits: { // 网站标识 enabled: false //去版权 }, navigator: { // 底部导航内容 enabled: false }, scrollbar: { enabled: false }, }), }) } const chartHcStore = new ChartHcStore(); export default chartHcStore;
五,k线展示时间问题:股票后台过来的数据由于时间存在不连续问题,导致前端在画图的时候 出现不连续,不均匀的k线图,为了使x轴连续性前端根据请求来的数据个数,自行往数据数组里添加连续的时间,但是就会存在用户在查看每条k线的时候,时间不正确,所以在tooltip里面,再把正确的时间给显示出来即可。
data5MVoluem.push({
x: time + i * 60000,//自行定义的时间 是连续的
y: self.socket.volumDataAll[i],
color: oo > cc ? "#70edab" : "red",//判断颜色
trueTime: pubFn.getTime(tt)//数据真正的时间 是展示给用户看的
});
formatter: function() { //回调函数将格式化提示框中的文本。 var points = this.points; // console.log(points) if (points.length>=2) { var t = new Date(points[1].point.options.trueTime); var m = t.getMonth(); // 获取月份(0-11,0代表1月,用的时候记得加上1) var d = t.getDate(); // 获取日(1-31) var h = t.getHours(); // 获取小时数(0-23) var mi = t.getMinutes(); // 获取分钟数(0-59) var tStr = m+"/"+d+" "+h+":"+mi; } if (points[0].point.open != undefined) { var s = '<div style=""><b style="color:#ccc">T:</b><span style="color:green;">'+tStr+'<span></div>'+ '<div style=""><b style="color:#ccc">最高:</b><span style="color:green;">'+points[0].point.high+'<span></div>'+ '<div style=""><b style="color:#ccc">最低:</b><span style="color:green;">'+points[0].point.low+'<span></div>'+ '<div style=""><b style="color:#ccc">开盘:</b><span style="color:green;">'+points[0].point.open+'<span></div>'+ '<div style=""><b style="color:#ccc">收盘:</b><span style="color:green;">'+points[0].point.close+'<span></div>'; } return s; }
先写这么多吧,如今国家金融领域在开放,不免以后会有大量的期货在中国可以交易(昨天原油期上市了)有兴趣的朋友可以一起探讨,也希望js在这块领域做出自己的东西,而不再被那么轻视。谢谢。