echart图表重绘一种方式,实现带滚动条的无限滚动列表的一种方案

317 阅读1分钟

1.echarts想要重新绘制,可以删除容器上的 _echarts_instance属性,然后重新init容器(有时需要更改容器id)

2.判断数组中元素是否相同

function isAllEqual(array) {
      if (array.length > 0) {
          return !array.some(function (value, index) {
              return value !== array[0];
          });
      } else {
          return true;
      }
  }

3.js的cloneNode无法科龙事件,可以使用jQuery的clone(true)实现dom节点的事件的克隆

4.带滚动条的列表循环滚动 1.使用setInterval和scrollTop方式

  • 要实现无缝衔接,在原有ul后面还要有一个一样内容的ul;
  • 最外层div为可视区域,设overflow:hidden;
  • 2个ul的高度 > 外层可视div高度,才能滚动;

2277801-20221016135817948-1361142908.gif

<!-- vue -->
<div id="review_box" @mouseenter="rollStop()" @mouseleave="rollStart(60)">
    <ul id="comment1">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <ul id="comment2"></ul>
</div>
div {
    height: 100px; /* 必须 */
    overflow: hidden;/* 必须 */
}
//vue data
data (){
    return {
        timer: null,
    }
},
mounted() {
      this.roll(60);
},
beforeDestroy() {
      if (this.timer) clearInterval(this.timer);
},
//vue methods
roll(t) {
    var ul1 = document.getElementById("comment1");
    var ul2 = document.getElementById("comment2");
    var ulbox = document.getElementById("review_box");
    ul2.innerHTML = ul1.innerHTML;
    ulbox.scrollTop = 0;
    this.rollStart(t);
},
rollStart(t) {
    var ul1 = document.getElementById("comment1");
    var ul2 = document.getElementById("comment2");
    var ulbox = document.getElementById("review_box");
    this.rollStop();
    this.timer = setInterval(()=>{
        // 当滚动高度大于列表内容高度时恢复为0
        if (ulbox.scrollTop >= ul1.scrollHeight) {
            ulbox.scrollTop = 0;
        } else {
            ulbox.scrollTop++;
        }
    }, t);
},
rollStop(){
    clearInterval(this.timer);
},

2.使用transition和绝对定位,当第一个元素完全隐藏后,剪切到队列末尾

1760390-20201105222512278-933754829.gif

<template>
  <div class="main">
    <div class="scroll-container">
      <div
        v-for="index in 8"
        :key="index"
        class="scroll-item"
        :style="styleFormatter(index - 1)"
        ref="scrollItem"
      >
        {{ index }}
      </div>
    </div>
    <div class="controller">
      <button class="btn" @click="toggleClick">{{ isScrolling ? '暂停滚动' : '开始滚动' }}</button>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      colorList: [
        'gray',
        'antiquewhite',
        'aquamarine',
        'cadetblue',
        'darkgoldenrod',
        'mediumaquamarine',
        'violet',
        'royalblue'
      ],

      // 每个元素的宽度
      width: 200,

      // 滚动速度
      speed: 100,

      isScrolling: false
    }
  },
  mounted () {
    this.initListener()
  },
  methods: {
    toggleClick () {
      if (this.isScrolling) {
        this.isScrolling = false
        this.pause()
      } else {
        this.isScrolling = true
        this.scroll()
      }
    },

    // 根据索引计算当前元素所在位置
    styleFormatter (index) {
      return {
        backgroundColor: this.colorList[index],
        left: `${index * this.width}px`
      }
    },

    // 控制滚动开始
    scroll () {
      const elementList = this.$refs.scrollItem
      elementList.forEach(ele => {
        ele.style.transitionDuration = `${(ele.offsetLeft + this.width) / this.speed}s`
        ele.style.left = `-${this.width}px`
      })
    },

    // 暂停滚动
    pause () {
      const elementList = this.$refs.scrollItem
      elementList.forEach(ele => {
        const styles = getComputedStyle(ele, null)
        console.log(styles.left)
        ele.style.transitionDuration = '0s'
        ele.style.left = `${styles.left}`
      })
    },

    // 初始化listener,监听滚动动画
    // 当元素完全滚动至显示范围外时,则将该元素插入队尾
    initListener () {
      const elementList = this.$refs.scrollItem

      elementList.forEach(ele => {
        // 当动画结束后会触发transitionend事件
        ele.addEventListener('transitionend', () => {
          // 计算队尾位置
          const lastestElementPosition = this.lastestElementPosition()
          ele.style.transitionDuration = `0s`
          ele.style.left = `${lastestElementPosition + this.width}px`

          // 渲染完毕之后开始滚动
          this.$nextTick(() => {
            ele.style.transitionDuration = `${(ele.offsetLeft + 200) / this.speed}s`
            ele.style.left = `-${this.width}px`
          })
        })
      })
    },

    // 计算最后一个元素的位置
    lastestElementPosition () {
      const elementList = this.$refs.scrollItem
      return Math.max(...elementList.map(ele => {
        // 注意,这里不能直接读取ele.style.left,这样只能读到终点位置的偏移量,而我们需要的是当前元素的实际位置,需要通过getComputedStyle来获取
        const styles = getComputedStyle(ele, null)
        return parseFloat(styles.left)
      }))
    }
  }
}
</script>

<style scoped>
  .scroll-container {
    width: 100%;
    height: calc(100% - 50px);
    display: flex;
    flex-direction: row;
    position: relative;
    overflow: hidden;
  }

  .scroll-item {
    display: flex;
    flex-shrink: 0;
    width: 200px;
    height: 100%;
    position: absolute;
    transition-property: left;
    transition-timing-function: linear;
  }

  .btn {
    margin-top: 20px;
    height: 30px;
    line-height: 30px;
  }
</style>