Vue2大屏项目的简要总结

1、屏幕自适应 — v-scale-screen
简介

实现的主要核心手段就是使用css属性transform实现缩放效果,会进行等比例计算达到等比缩放效果

使用
// 1、安装依赖
npm install v-scale-screen -save
# or
yarn add v-scale-screen

// 2、main.js中引入
import VScaleScreen from 'v-scale-screen'
Vue.use(VScaleScreen)

// 3、使用
<v-scale-screen width="1920" height="1080">
	<!--页面内容-->
</v-scale-screen>
简要说明
  1. 通过该方法实现屏幕自适应无需考虑使用rem等单位,直接px布局即可。
实现效果
  1. 正常打开情况下
    在这里插入图片描述

  2. 调整浏览器大小后显示情况
    在这里插入图片描述

2、数字翻牌器 - vue-count-to
简介

是一个组件插件,像组件一样注册就可使用

使用
// 1、安装
npm install vue-count-to

// 2、引入
import CountTo from 'vue-count-to'

// 3、注册
components: {
  CountTo
},

// 4、使用
// 变化前数据startVal:Number
// 变化后数据endVal:Number
// 变化时间间隔duration:ms
<CountTo
  :startVal='startVal'
  :endVal='endVal'
  :duration='duration'
/>
项目中使用

封装数字翻牌部分,将数据以对象的形式传递过去

// 数据(假设父组件传递过来的数据是下面这个)
testData: {
	startVal: 0,
	endVal: 32,
}

// 至于duration的话看个人情况吧,直接再翻牌组件中写死也行
补充说明

其实dataV也有数字翻牌器功能,但这种方法和dataV的数字翻牌器更加易于理解并且更加直观,大家可以研究研究

3、Echarts图表的使用
简介

大屏中echarts图表展示几乎是不可避免的,以图表的形式展示数据给人的感官更加直观舒服,能够清除的反映数据的变化。下面是Vue项目中echarts图表的使用

使用
// 1、下包
 npm install echarts --save
 
// 2、全局引入
import * as echarts from "echarts"; // 引入echarts
Vue.prototype.$echarts = echarts;

// 3、组件中使用 HuLiDengJi.vue
// 模板
<template>
  <div ref="huLiRef"></div>
</template>

// 逻辑部分
async mounted() {
  this.huLiEcharts = this.$echarts.init(this.$refs.huLiRef);
  this.drawLine();
},

data() {
    return {
      huLiEcharts: "",
 	  options: {}, // echarts图表的数据,可在线上调试后复制即可,但里面的数据部分需要父组件传递,因为是会变化的
    };
  },

// 方法
methods: {
	drawLine() {
      	this.huLiEcharts.setOption(this.option);
    }
},

// 侦听器 -- 数据变化重新渲染
watch: {
    huLiData: {
    	deep: true,
      	// immediate: true,
      	handler() {
        	this.drawLine();
      	},
    },
},
4、echarts图表自动轮播tooltip
简介

最终效果是实现鼠标在不移入echarts图的情况下,能够让他以一定时间间隔自动顺序选中内容进行展示,当鼠标移入后会停止自动轮播,鼠标移除后又回复轮播

代码
1、先将自动轮播方法封装成一个单独的js文件
/**
 * echarts tooltip轮播
 * @param chart ECharts实例
 * @param chartOption echarts的配置信息
 * @param options object 选项
 * {
 *  interval    轮播时间间隔,单位毫秒,默认为2000
 *  loopSeries  boolean类型,默认为false。
 *              true表示循环所有series的tooltip,false则显示指定seriesIndex的tooltip
 *  seriesIndex 默认为0,指定某个系列(option中的series索引)循环显示tooltip,
 *              当loopSeries为true时,从seriesIndex系列开始执行。
 *  updateData  自定义更新数据的函数,默认为null;
 *              用于类似于分页的效果,比如总数据有20条,chart一次只显示5条,全部数据可以分4次显示。
 * }
 * @returns {{clearLoop: clearLoop}|undefined}
 */
export function loopShowTooltip(chart, chartOption, options) {
  let defaultOptions = {
    interval: 2000,
    loopSeries: false,
    seriesIndex: 0,
    updateData: null,
  };

  if (!chart || !chartOption) {
    return;
  }

  let dataIndex = 0; // 数据索引,初始化为-1,是为了判断是否是第一次执行
  let seriesIndex = 0; // 系列索引
  let timeTicket = 0;
  let seriesLen = chartOption.series.length; // 系列个数
  let dataLen = 0; // 某个系列数据个数
  let chartType; // 系列类型
  let first = true;
  let lastShowSeriesIndex = 0;
  let lastShowDataIndex = 0;

  if (seriesLen === 0) {
    return;
  }

  // 待处理列表
  // 不循环series时seriesIndex指定显示tooltip的系列,不指定默认为0,指定多个则默认为第一个
  // 循环series时seriesIndex指定循环的series,不指定则从0开始循环所有series,指定单个则相当于不循环,指定多个
  // 要不要添加开始series索引和开始的data索引?

  if (options) {
    options.interval = options.interval || defaultOptions.interval;
    options.loopSeries = options.loopSeries || defaultOptions.loopSeries;
    options.seriesIndex = options.seriesIndex || defaultOptions.seriesIndex;
    options.updateData = options.updateData || defaultOptions.updateData;
  } else {
    options = defaultOptions;
  }

  // 如果设置的seriesIndex无效,则默认为0
  if (options.seriesIndex < 0 || options.seriesIndex >= seriesLen) {
    seriesIndex = 0;
  } else {
    seriesIndex = options.seriesIndex;
  }

  /**
   * 清除定时器
   */
  function clearLoop() {
    if (timeTicket) {
      clearInterval(timeTicket);
      timeTicket = 0;
    }

    chart.off("mousemove", stopAutoShow);
    zRender.off("mousemove", zRenderMouseMove);
    zRender.off("globalout", zRenderGlobalOut);
  }

  /**
   * 取消高亮
   */
  function cancelHighlight() {
    /**
     * 如果dataIndex为0表示上次系列完成显示,如果是循环系列,且系列索引为0则上次是seriesLen-1,否则为seriesIndex-1;
     * 如果不是循环系列,则就是当前系列;
     * 如果dataIndex>0则就是当前系列。
     */
    let tempSeriesIndex =
      dataIndex === 0
        ? options.loopSeries
          ? seriesIndex === 0
            ? seriesLen - 1
            : seriesIndex - 1
          : seriesIndex
        : seriesIndex;
    let tempType = chartOption.series[tempSeriesIndex].type;

    if (tempType === "pie" || tempType === "radar" || tempType === "map") {
      chart.dispatchAction({
        type: "downplay",
        seriesIndex: lastShowSeriesIndex,
        dataIndex: lastShowDataIndex,
      }); // wait 系列序号为0且循环系列,则要判断上次的系列类型是否是pie、radar
    }
  }

  /**
   * 自动轮播tooltip
   */
  function autoShowTip() {
    let invalidSeries = 0;
    let invalidData = 0;
    function showTip() {
      // chart不在页面中时,销毁定时器
      let dom = chart.getDom();
      if (document !== dom && !document.documentElement.contains(dom)) {
        clearLoop();
        return;
      }

      // 判断是否更新数据
      if (
        dataIndex === 0 &&
        !first &&
        typeof options.updateData === "function"
      ) {
        options.updateData();
        chart.setOption(chartOption);
      }

      let series = chartOption.series;
      let currSeries = series[seriesIndex];
      if (
        !series ||
        series.length === 0 ||
        !currSeries ||
        !currSeries.type ||
        !currSeries.data ||
        !currSeries.data.length
      ) {
        return;
      }

      chartType = currSeries.type; // 系列类型
      dataLen = currSeries.data.length; // 某个系列的数据个数

      let tipParams = {
        seriesIndex: seriesIndex,
      };
      switch (chartType) {
        case "pie":
          // 处理饼图中数据为0或系列名为空的不显示tooltip
          if (
            !currSeries.data[dataIndex].name ||
            currSeries.data[dataIndex].name === "空" ||
            !currSeries.data[dataIndex].value
          ) {
            invalidData += 1;
            dataIndex = (dataIndex + 1) % dataLen;
            if (options.loopSeries && dataIndex === 0) {
              // 数据索引归0表示当前系列数据已经循环完
              // 无效数据个数个总数据个数相等,则该系列无效
              if (invalidData === dataLen) {
                invalidSeries += 1;
              }

              // 新系列,重置无效数据个数
              invalidData = 0;

              // 系列循环递增1
              seriesIndex = (seriesIndex + 1) % seriesLen;
              // 系列数循环至起始值时重置无效系列数
              if (seriesIndex === options.seriesIndex) {
                if (seriesLen !== invalidSeries) {
                  // 下一次系列轮回,重置无效系列数
                  invalidSeries = 0;
                  showTip();
                } else {
                  // 下一次系列轮回,重置无效系列数
                  invalidSeries = 0;
                  clearLoop();
                }
              } else {
                showTip();
              }
            } else if (!options.loopSeries && dataIndex === 0) {
              if (dataLen !== invalidData) {
                invalidData = 0;
                showTip();
              } else {
                invalidData = 0;
                clearLoop();
              }
            } else {
              showTip();
            }

            return;
          }
        // eslint-disable-next-line no-fallthrough
        case "map":
        case "chord":
          tipParams.name = currSeries.data[dataIndex].name;
          break;
        case "radar": // 雷达图
          tipParams.seriesIndex = seriesIndex;
          // tipParams.dataIndex = dataIndex;
          break;
        case "lines": // 线图地图上的lines忽略
          dataIndex = 0;
          seriesIndex = (seriesIndex + 1) % seriesLen;
          invalidSeries++; // 记录无效系列数,如果无效系列数和系列总数相等则取消循环显示
          if (seriesLen !== invalidSeries) {
            showTip();
          } else {
            clearLoop();
          }
          return;
        default:
          tipParams.dataIndex = dataIndex;
          break;
      }

      if (chartType === "pie" || chartType === "radar" || chartType === "map") {
        if (!first) {
          cancelHighlight();
        }

        // 高亮当前图形
        chart.dispatchAction({
          type: "highlight",
          seriesIndex: seriesIndex,
          dataIndex: dataIndex,
        });
      }

      // 显示 tooltip
      tipParams.type = "showTip";
      chart.dispatchAction(tipParams);

      lastShowSeriesIndex = seriesIndex;
      lastShowDataIndex = dataIndex;

      dataIndex = (dataIndex + 1) % dataLen;
      if (options.loopSeries && dataIndex === 0) {
        // 数据索引归0表示当前系列数据已经循环完
        invalidData = 0;
        seriesIndex = (seriesIndex + 1) % seriesLen;
        if (seriesIndex === options.seriesIndex) {
          invalidSeries = 0;
        }
      }

      first = false;
    }

    showTip();
    timeTicket = setInterval(showTip, options.interval);
  }

  // 关闭轮播
  function stopAutoShow() {
    if (timeTicket) {
      clearInterval(timeTicket);
      timeTicket = 0;

      if (chartType === "pie" || chartType === "radar" || chartType === "map") {
        cancelHighlight();
      }
    }
  }

  let zRender = chart.getZr();

  function zRenderMouseMove(param) {
    if (param.event) {
      // 阻止canvas上的鼠标移动事件冒泡
      // param.event.cancelBubble = true;
    }
    stopAutoShow();
  }

  // 离开echarts图时恢复自动轮播
  function zRenderGlobalOut() {
    // console.log("移出了")
    // console.log(timeTicket)
    if (!timeTicket) {
      autoShowTip();
    }
  }

  // 鼠标在echarts图上时停止轮播
  chart.on("mousemove", stopAutoShow);
  zRender.on("mousemove", zRenderMouseMove);
  zRender.on("globalout", zRenderGlobalOut);

  autoShowTip();

  return {
    clearLoop: clearLoop,
  };
}
2、在需要使用改方法的文件中引入
import { loopShowTooltip } from "../../../tooltip-auto-show-vue.js";
export default {
  data() {
    return {
      tootipTimer:""
    };
  },
}
3、引用刚才封装的js方法
myChart.setOption(option);
this.tootipTimer && this.tootipTimer.clearLoop(); // this.tootipTimer 在data里定义
this.tootipTimer = 0;
// 调用轮播的方法
this.tootipTimer = loopShowTooltip(myChart, option, {
	interval: 2000, // 轮播间隔时间
	loopSeries: true, // 是否开启轮播循环
    // loopSeries: boolean类型,默认为false。true表示循环所有series的tooltip;false则显示指定seriesIndex的tooltip。
    // seriesIndex: 默认为0,指定某个系列(option中的series索引)循环显示tooltip,当loopSeries为true时,从seriesIndex系列开始执行。
});
效果
初始效果

请添加图片描述

会自动的顺序选中显示

请添加图片描述

参考文献

vue项目中的echarts图表,实现自动轮播tooltip_echarts 自动轮播tooltip

5、echarts图标禁用legend默认的点击行为实现
简介

我遇到的场景是基于上面的一个场景,默认情况下点击图标的legend时会隐藏对应区域,但如果存在自动轮播的时候,就会产生一个空缺,也就是你让点击的legend内容隐藏了,但轮播的时候还会对隐藏区域进行轮播,造成轮播到隐藏部分时会出现显示的一个空缺,如果我们去禁用掉隐藏区域这个功能后,那么也就不会出现这一问题了

代码
myChart.on('legendselectchanged', function (params) {
	myChart.setOption({
		legend:{selected:{[params.name]: true}}
	})
	 console.log('点击了', params.name);
	// do something
});
参考文献

Echarts 自定义、覆盖legend点击事件、禁用legend默认的点击行为的实现_legend禁止点击

6、表格自动滚动
简介

大屏中很可能遇到图标自动滚动效果,这个可以使用dataV的一个组件进行实现

代码
// 模板使用
<dv-scroll-board :config="config" style="width:500px;height:220px" />

// 数据部分
export default {
  header: ['列1', '列2', '列3'], // 表头
  data: [
    ['行1列1', '行1列2', '行1列3'],
    ['行2列1', '行2列2', '行2列3'],
    ['行3列1', '行3列2', '行3列3'],
    ['行4列1', '行4列2', '行4列3'],
    ['行5列1', '行5列2', '行5列3'],
    ['行6列1', '行6列2', '行6列3'],
    ['行7列1', '行7列2', '行7列3'],
    ['行8列1', '行8列2', '行8列3'],
    ['行9列1', '行9列2', '行9列3'],
    ['行10列1', '行10列2', '行10列3']
  ]
}
注意事项
  1. 数据改变时用修改整个config对象的形式进行修改,因为它组件内部没用设置deep进行深度侦听,因此只修改configdata是监测不到的,刷新不了
  2. 轮播表还有很多配置可参考,具体可以看一下dataV官网
参考文献

轮播表 | DataV (jiaminghi.com)

7、公告类的部分实现自动滚动
简介

需要一个类似公告消息滚动的实现,移动端一般有对应的vant或者uView可以使用,pc的话element-ui暂时没有,但也是有方法可以实现的

代码
新建一个组件使用就行
<template>
  <div
    id="box"
    ref="box"
  >
    <div
      class="marquee-box"
      ref="marquee"
      @mouseover="menter"
      @mouseleave="mleave"
    >
      <p
        ref="cmdlist"
        id="pWidth"
      >
        {{ sendVal }}
      </p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ScrollMessageTwo',
  props: {
    sendVal: {
      type: String,
      default: '暂无'
    }
  },
  data() {
    return {
      value: 0,
      timer: '', //计时器
      pwidth: 0, //公告文本的宽度
      windowWidth: 0 // 设备屏幕的宽度
    }
  },

  mounted() {
    this.windowWidth = document.querySelector('#box').clientWidth
    let element = this.$refs.cmdlist
    this.pwidth = document.defaultView
      .getComputedStyle(element, '')
      .width.split('px')
    this.timer = setInterval(this.clickCommend, 20)
  },

  watch: {
    value(newValue) {
      let allWidth = parseInt(this.windowWidth) + parseInt(this.pwidth[0])
      if (newValue <= -allWidth) {
        this.$refs.cmdlist.style.marginLeft = this.windowWidth + 'px'
        this.value = 0
      }
    }
  },

  methods: {
    clickCommend() {
      let _this = this
      this.$nextTick(() => {
        this.value -= 1
        this.$refs.cmdlist.style.marginLeft =
          _this.windowWidth + this.value + 'px'
      })
    },
    menter() {
      clearInterval(this.timer)
    },
    mleave() {
      this.timer = setInterval(this.clickCommend, 20)
    }
  },
  beforeDestroy() {
    clearInterval(this.timer)
  }
}
</script>

<style scoped lang="scss">
#box {
  display: flex;
  align-items: center;
  overflow: hidden;
}
.marquee-box {
  display: inline-block;
  overflow: auto;
}
#pWidth {
  display: inline-block;
  word-break: keep-all;
  white-space: nowrap;
  overflow: hidden;
}
</style>
参考文献

vue实现横屏滚动公告效果_vue.js_脚本之家 (jb51.net)

说明

原参考文章是获取整个屏幕的宽度,也就是屏幕宽度的一个消息滚动,但我遇到的场景只是一小块内容区域滚动,因此对它windowWidth的值进行了修改,大家也可以按自己的情况进行修改

8、区域内容自动滚动实现
简介

类似于表格自动滚动,但这不是一个表格却也要进行滚动

当内容超过高度时,开启自动滚动

默认向下滚动,触底后在向上

点击内容区域后还会停止滚动,此时你可以通过鼠标滚轮进行滚动

代码实现
<template>
  <div
    :id="scrollId"
    style="border:1px solid red;
    height: 300px;
    width: 200px;
    overflow-y: scroll;
    position: absolute;
    text-align: center;
    top: 10%;
    left: 40%;"
  >
    <div>
      滚动内容1<br>
      滚动内容2<br>
      滚动内容3<br>
      滚动内容4<br>
      滚动内容5<br>
      滚动内容6<br>
      滚动内容7<br>
      滚动内容8<br>
      滚动内容9<br>
      滚动内容10<br>
      滚动内容11<br>
      滚动内容12<br>
      滚动内容13<br>
      滚动内容14<br>
      滚动内容15<br>
      滚动内容16<br>
      滚动内容17<br>
      滚动内容18<br>
    </div>
  </div>
</template>

<script>

export default {
  data() {
    return {
      scrollTimer: null, // 滚动定时器
      pauseTimer: null, // 暂停定时器
      scrollId: 'scrollId', // 滚动容器id
      scrollDirection: 'down' // 滚动方向 up向上 down向下
    }
  },
  destroyed() {
    // 清理定时器
    clearTimeout(this.pauseTimer)
    this.pauseTimer = null
    clearInterval(this.scrollTimer)
    this.scrollTimer = null
    // 清理点击监听
    window.document.removeEventListener('click', this.pauseScroll)
  },
  mounted() {
    this.dataCompleteFun()
  },
  methods: {
    // 数据加载完成方法
    dataCompleteFun() {
      // 开启滚动
      this.autoScroll()
    },
    autoScroll() {
      const scrollHeight = document.getElementById(this.scrollId).scrollHeight
      const clientHeight = document.getElementById(this.scrollId).clientHeight
      const scroll = scrollHeight - clientHeight
      // 滚动长度为0
      if (scroll === 0) {
        return
      }
      // 触发滚动方法
      this.scrollFun()
      // 去除点击监听
      window.document.removeEventListener('click', this.pauseScroll)
      // 重设点击监听
      window.document.addEventListener('click', this.pauseScroll, false)
    },
    pauseScroll() {
      // 定时器不为空
      if (this.scrollTimer) {
        // 清除定时器
        clearInterval(this.scrollTimer)
        this.scrollTimer = null
        // 一秒钟后重新开始定时器
        this.pauseTimer = setTimeout(() => {
          this.scrollFun()
        }, 2000)
      }
    },
    scrollFun() {
      // 如果定时器存在
      if (this.scrollTimer) {
        // 则先清除
        clearInterval(this.scrollTimer)
        this.scrollTimer = null
      }
      this.scrollTimer = setInterval(() => {
        const scrollHeight = document.getElementById(this.scrollId).scrollHeight
        const clientHeight = document.getElementById(this.scrollId).clientHeight
        const scroll = scrollHeight - clientHeight
        // 获取当前滚动条距离顶部高度
        const scrollTop = document.getElementById(this.scrollId).scrollTop
        // 向下滚动
        if (this.scrollDirection === 'down') {
          const temp = scrollTop + 1
          document.getElementById(this.scrollId).scrollTop = temp // 滚动
          // 距离顶部高度  大于等于 滚动长度
          if (scroll <= temp) {
            // 滚动到底部 停止定时器
            clearInterval(this.scrollTimer)
            this.scrollTimer = null
            // 改变方向
            this.scrollDirection = 'up'
            // 一秒后重开定时器
            setTimeout(() => {
              this.scrollFun()
            }, 1000)
          }
          // 向上滚动
        } else if (this.scrollDirection === 'up') {
          const temp = scrollTop - 0.5
          document.getElementById(this.scrollId).scrollTop = temp // 滚动
          // 距离顶部高度  小于等于 0
          if (temp <= 0) {
            // 滚动到底部 停止定时器
            clearInterval(this.scrollTimer)
            this.scrollTimer = null
            // 改变方向
            this.scrollDirection = 'down'
            // 一秒后重开定时器
            setTimeout(() => {
              this.scrollFun()
            }, 1000)
          }
        }
      }, 150)
    }
  }
}
</script>
参考文献

vue实现自动滚动效果(上下往复) - 前端 - 华仔部落 (zjh336.cn)

更新

后期对排版进行了调整
在这里插入图片描述

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐