大屏项目整理

310 阅读5分钟

开发项目中涉及到了很多未涉及的知识,项目完结后来总结下

1.大屏设备适配

在项目中适配的方案是rem,通过rem原理,先获取屏幕宽度划分N块,每一块都是1rem.

// 首先是一个立即执行函数,执行时传入的参数是window和document(function flexible(window, document) {  // 返回文档的root元素  var docEl = document.documentElement;   // 获取设备的dpr,即当前设置下物理像素与虚拟像素的比值  var dpr = window.devicePixelRatio || 1;   // 设置默认字体大小,默认的字体大小继承自body  function setBodyFontSize() {    if (document.body) {      // 调整body标签的fontSizefontSize = (12 * dpr) + 'px'      document.body.style.fontSize = 12 * dpr + 'px';    } else {      document.addEventListener('DOMContentLoaded', setBodyFontSize);    }  }  setBodyFontSize();  // set 1rem = viewWidth / 24  function setRemUnit() {    // 设置root元素的fontSize = 其clientWidth / 24 + 'px'    var rem = docEl.clientWidth / 24;    docEl.style.fontSize = rem + 'px';  }  setRemUnit();  // 当页面展示或重新设置大小的时候,触发重新  window.addEventListener('resize', setRemUnit);  window.addEventListener('pageshow', function(e) {    if (e.persisted) {      setRemUnit();    }  });  // 检测0.5px的支持,支持则root元素的class中有hairlines  if (dpr >= 2) {    var fakeBody = document.createElement('body');    var testElement = document.createElement('div');    testElement.style.border = '.5px solid transparent';    fakeBody.appendChild(testElement);    docEl.appendChild(fakeBody);    if (testElement.offsetHeight === 1) {      docEl.classList.add('hairlines');    }    docEl.removeChild(fakeBody);  }})(window, document);

最后在页面里引入 import "@/assets/js/flexible"; 比如说设计图的尺寸是3840,然后你划分的是24块,那你的根元素就是 3840/24=160。如果你在设计图量的是16px,转换成rem就是16/160=1rem。

echarts图表自适应;通过设计图的高宽决定缩放程度

// 屏幕缩放export function screenSize(editorDom) {  let screenWidth = document.body.clientWidth || document.documentElement.clientWidth;  let screenHeight = document.body.clientHeight || document.documentElement.clientHeight;  let defWidth = 3840;  let defHeight = 2160;  let xScale = screenWidth / defWidth;  let yScale = screenHeight / defHeight;  editorDom.style.cssText += ';transform: scale(' + xScale + ',' + yScale + ')';  $(window).resize(() => {    let screenWidth = document.body.clientWidth || document.documentElement.clientWidth;    let screenHeight = document.body.clientHeight || document.documentElement.clientHeight;    xScale = screenWidth / defWidth;    yScale = screenHeight / defHeight;    editorDom.style.cssText += ';transform: scale(' + xScale + ',' + yScale + ')';  })}

然后在每次在setoption时

let myChart = echarts.init(document.getElementById("chart_circular1"));
let option={...};
myChart.setOption(option, true); window.addEventListener("resize", () => {  myChart.resize();});

2.Echarts使用

**1.**echarts获取dom

   两种方法:普遍的就是getElementById,在vue里面还有一种方法,就是使用ref,在标签中写上ref=“test”,在methods里面就使用this.$ref.test 就可以实现获取dom;

  •   <div class="chart" id="charts"></div> let myChart = echarts.init(document.getElementById("charts"));
    
  •   <div class="chart" ref="test"></div>
       let myChart = echarts.init(this.$refs.test);
    

ref 需要在dom渲染完成后才会有,在使用的时候确保dom已经渲染完成。比如在生命周期 mounted(){} 钩子中调用,或者在 this.$nextTick(()=>{}) 中调用。

2.echarts生成图表

在获取dom之后,配置option(配置项详细说明 ),最后使用setoption方法生成图表

        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);

3. echarts更新图表

echarts创建后,数据变化后,仍然使用setoption方法进行修改所需的项(创建时的其他配置项可以不写,只修改所需的);

var myChart = echarts.init(document.getElementById('main'));
myChart.setOption({
  //如需更新数据
    series:[{
      name:'',
      type:'bar',
      data:['a'] 
    }]
});

4.echarts图表位置的放置

echarts有一个配置项grid,简单的设置为如下

grid:{
    left:10, //也可以用百分比设置 例: left:'10%'
    right:10,
    top:10,
    bottom:10
}

5.echarts图例设置

图例组件展现了不同系列的标记(symbol),颜色和名字。可以通过点击图例控制哪些系列不显示,配置legend即可,默认legend是一个对象,但也可以是多个即legend数组,图例有时候设置了不显示,这时候有可能配置的series没有跟图例相关联,如series

legend: {  orient: "vertical",  //设置列表的布局朝向  right: "10%",//图例位置  top: "10%",  itemWidth: 15, //图例宽  itemHeight: 10,//图例高  textStyle: {     color: "#f2f2f2",     fontSize: 8,  },  icon: "Rect",  //图标的形状,可设置不同的  data: ['测试','测试'],},

也可以是这种形式(多个图例)

legend: [          {            orient: "vertical",            right: "10%",            top: "10%",            itemWidth: 15,            itemHeight: 10,            textStyle: {              color: "#f2f2f2",              fontSize: 8,            },            icon: "Rect",             data: ['测试','测试'],          },          {            orient: "vertical",            right: "10%",            top: "10%",            itemWidth: 15,            itemHeight: 10,            textStyle: {              color: "#f2f2f2",              fontSize: 8,            },            icon: "Rect",             data: ['测试','测试'],          },]

图例可以监听点击事件

 myChart.on("legendselectchanged", (obj) => {        // console.log('点击',obj); });

6.图表的x轴label文字设置垂直

 xAxis: {     axisLabel: {      textStyle: {         fontSize: 10,         color: "#b9b8be",      },      formatter: function(value) {          return value.split("").join("\n");     },   },
}

更详细的配置可以查下官网的配置项

3.websocket使用

因项目中需要实时更新数据 ,所以直接使用websocket。websocket这边也不详细说明是什么了,只是简单的说下用法:

示例:

var ws = new WebSocket("wss://echo.websocket.org");  //需要连接的服务器端的URL  注意: ws或者wss一定要有 两者就是http协议和https协议的区别

ws.onopen = function(evt) { 
  console.log("Connection open ..."); 
  ws.send("Hello WebSockets!");  //向服务器端发送数据的方法
};

ws.onmessage = function(evt) {  //发送完数据后,从服务器端接收相应返回的方法
  console.log( "Received Message: " + evt.data); 
  ws.close();
};

ws.onclose = function(evt) {  //与服务器端断开连接后执行的方法
  console.log("Connection closed.");
};

这里是我项目中的封装好的socket.js

let socket = null;let lockReconnet = false;   //避免重复连接const wsUrl = ''; //服务器端的urllet isReconnet = false;let globalCallback = null, sendData = null; //把要发送给socket的数据和处理socket返回数据的回调保存起来let createSocket = url => { //创建socket    try {        if ('WebSocket' in window) {            socket = new WebSocket(url)        }        initSocket()    } catch (e) {        reconnet(url)    }}let sendMsg = (data, callback) => { //发送数据,接收数据    if (socket.readyState === 1) {        globalCallback = callback;        sendData = data;        data = JSON.stringify(data);        socket.send(data);    } else {        setTimeout(() => {            sendMsg(data, callback)        }, 1500)        return false    }    socket.onmessage = ev => {        let responseData = JSON.parse(ev.data);           callback && callback(ev)    }}let initSocket = () => {    //初始化websocket    socket.onopen = () => {        console.log('socket连接成功')        //heartCheck.reset().start()    //后端说暂时不需要做心跳检测        if (isReconnet) {//执行全局回调函数            //console.log('websocket重新连接了')            sendMsg(sendData, globalCallback)            isReconnet = false        }    }    socket.onmessage = (ev) => {        console.log(ev, '连接正常')        //heartCheck.reset().start()        }    socket.onerror = () => {        console.log('websocket服务出错了---onerror');        reconnet(wsUrl)    }    socket.onclose = () => {        console.log('websocket服务关闭了+++onclose');        reconnet(wsUrl)    }}let reconnet = url => { //重新连接websock函数    if (lockReconnet)        return false    isReconnet = true;    lockReconnet = true    setTimeout(() => {        createSocket(url)        lockReconnet = false    }, 2000)}let heartCheck = {  //心跳检测    timeout: 60 * 1000,    timeoutObj: null,    serverTimeoutObj: null,    reset() {        clearTimeout(this.timeoutObj)        clearTimeout(this.serverTimeoutObj)        return this;    },    start() {        let that = this;        this.timeoutObj = setTimeout(() => {            //发送数据,如果onmessage能接收到数据,表示连接正常,然后在onmessage里面执行reset方法清除定时器            socket.send('heart check')            this.serverTimeoutObj = setTimeout(() => {                socket.close()            }, that.timeout)        }, this.timeout)    }}createSocket(wsUrl)export default { sendMsg }

设置全局

import socket from '@/util/socket'Vue.prototype.sendMsg = socket.sendMsg

用法:

this.sendMsg({ class: "Statistics", action: "setScreenFds" },(ev)=>{
    console.log(ev)
});

我在刚开始使用时不太适应,因为websocket客户端发送一条消息,服务端会异步返回。

比如,发送a,b,c三条消息,服务端只会在c消息的回调中,返回三条相应的消息,然后我这边做的调整就是让服务端返回不同的字段,在c消息的回调中做出不同的处理。如果是服务端主动发出的消息,客户端这边只能存储在vuex,然后在页面中更新。

如果有更好的处理方式,麻烦请在评论区告知下^_^

4.vuex的使用

在之前接触的项目,项目并不多使用vuex,等到用的时候就是手忙脚乱的

vuex的安装什么的可以在网上找找,很多的.这里只说下用法:

在js中引用,比如上面的自己封装好的socket.js

//引入
import store from '@/store/index'

//储存数据store.commit('editfunc', data);  //editfunc是mutations里设置data值的一个方法

store.js

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({  state: {
   cdata:''
  },  getters: {  },  mutations: {    editfunc(state, val) {      state.editfunc= val    },  },  actions: {  },  modules: {  }})

index.vue

 computed: {    ...mapState({      cdata: (state) => state.cdata,    }),  },