【性能优化】在大批量数据下使用 HTML+CSS实现走马灯,防止页面卡顿(二)

上一篇只是简单演示了'下一张'的操作和整体的设计思路,这两天把剩余功能补全了,代码经过精简,可封装当成轮播组件使用,详细如下.

代码

html 复制代码
<template>
    <div class="container">

        <button @click="checkNext('last')">上一张</button>
        <button @click="checkNext('next')">下一张</button>
        <div class="windows" @mousemove="stopPlay" @mouseleave="autoPlay">
            <div class="scrollBox">
                <div class="scrollItem">
                    <div class="img">
                        <el-image :src="initialData.imgUrl"></el-image>
                    </div>
                    <div class="messBox">{{ initialData.mess }}</div>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
  data () {
    return {
      localData: [
        { imgUrl: '', mess: '11111' },
        { imgUrl: '', mess: '2222' },
        { imgUrl: '../assets/dz.png', mess: '3333' },
        { imgUrl: '../assets/logo.png', mess: '44444' },
        { imgUrl: '', mess: '55555' },
        { imgUrl: '', mess: '66666' }
      ],
      initialData: '', // 初始展示数据
      nowIndex: 0, // 当前展示数据的索引
      progressControler: false, // 控制切换的变量
      autoPlayTimer: '', // 自动播放定时器id
      nextShowData: { imgUrl: '', mess: '' }// 下一批展示的数据
    }
  },
  mounted () {
    this.initData()
  },
  beforeRouteLeave (to, from, next) {
    // 清除定时器
    clearInterval(this.autoPlayTimer)
    console.log('离开当前页面')
    next()
  },
  methods: {
    initData () {
      // 初始赋值
      this.initialData = this.localData[this.nowIndex]
      // 自动播放
      this.autoPlay()
    },

    // 查看上一张/下一张
    checkNext (type) {
      // 信息展示列表无数据或只有一条数据时,不执行
      if (!this.localData || this.localData.length <= 1) return
      // 防止猛点
      if (this.progressControler) {
        console.log('当前操作过快')
        return
      }
      this.progressControler = true // 将当前操作进程锁死,完成后才允许下一次操作
      this.readyBox(type)// 准备新的dom元素
      let removeDomIndex = ''
      let createDomIndex = ''
      if (type === 'last') {
        console.log('查看上一张')
        removeDomIndex = 1
        createDomIndex = 0
        this.nowIndex--
        if (this.nowIndex < 0) { this.nowIndex = this.localData.length - 1 }// 循环播放
      }
      if (type === 'next') {
        console.log('查看下一张')
        removeDomIndex = 0
        createDomIndex = 1
        this.nowIndex++
        if (this.localData.length < this.nowIndex + 1) { this.nowIndex = 0 }// 循环播放
      }
      // 获取dom,准备移动和删除节点
      const fatherDom = document.querySelector('.windows')
      const moveDistanceX = fatherDom.offsetWidth
      const domArr = fatherDom.querySelectorAll('.scrollBox')

      // 根据类名判断要移除的子盒子的偏移值
      const isRealDom = domArr[removeDomIndex].classList.contains('newScrollBox')
      const isRightCreatDom = domArr[removeDomIndex].classList.contains('RightnewScrollBox')
      const isLeftCreatDom = domArr[removeDomIndex].classList.contains('LeftnewScrollBox')

      // 实现走马灯移动效果
      if (!isRealDom) {
        domArr[removeDomIndex].style.transform = `translate(${type === 'next' ? -moveDistanceX : moveDistanceX}px,0px)`
      }

      if ((type === 'next' && isRightCreatDom) || (type === 'last' && isLeftCreatDom)) {
        domArr[removeDomIndex].style.transform = `translate(${type === 'next' ? -moveDistanceX * 2 : moveDistanceX * 2}px,0px)`
      }
      if ((type === 'next' && isLeftCreatDom) || (type === 'last' && isRightCreatDom)) {
        domArr[removeDomIndex].style.transform = 'translate(0px,0px)'
      }
      domArr[createDomIndex].style.transform = `translateX(${type === 'next' ? -moveDistanceX : moveDistanceX}px)`

      const timeId1 = setTimeout(() => {
        fatherDom.removeChild(domArr[removeDomIndex])
        this.progressControler = false // 允许进行下一次操作
        clearTimeout(timeId1)
      }, 501)
    },

    // 为下一次移动准备dom元素
    readyBox (type) {
      let nextShowData = ''// 上一张或下一张要展示的数据
      const fatherDom = document.querySelector('.windows')// 获取父元素
      const newDom = document.createElement('div')// 创建新元素
      // 设置新元素的样式
      newDom.className = 'scrollBox'
      newDom.classList.add('newScrollBox')
      newDom.style.width = '100%'
      newDom.style.height = '100%'
      newDom.style.position = 'absolute'
      newDom.style.transition = 'all 0.5s'

      // 上一张
      if (type === 'last') {
        // 确定下一条播放数据的取值
        if (this.nowIndex === 0) {
          nextShowData = this.localData[this.localData.length - 1]
        } else {
          nextShowData = this.localData[this.nowIndex - 1]
        }
        newDom.style.left = '-100%'
        newDom.classList.add('LeftnewScrollBox')
        // 插入子元素
        newDom.innerHTML = manageHtml(nextShowData)
        fatherDom.insertBefore(newDom, fatherDom.firstChild)
      }
      // 下一张的数据
      if (type === 'next') {
        // 确定下一条播放数据的取值
        if (this.localData.length === this.nowIndex + 1) {
          nextShowData = this.localData[0]
        } else {
          nextShowData = this.localData[this.nowIndex + 1]
        }

        newDom.style.left = '100%'
        newDom.classList.add('RightnewScrollBox')

        // 插入子元素
        newDom.innerHTML = manageHtml(nextShowData)
        fatherDom.appendChild(newDom)
      }

      // 管理动态页面结构
      function manageHtml (nextShowData) {
        // 新元素的内部结构
        const innerHtml = `
                <div class="scrollItem" style=" display: flex;  width: 100%; height: 100%; background-color: pink;">
                    <div class="img" style="width:50%; height:100%" >
                        <el-image src="${nextShowData.imgUrl}"></el-image>
                    </div>
                    <div class="messBox" style=" font-size: 16px; width:50%; height:100%; background-color: skyblue; ">
                        ${nextShowData.mess}
                    </div>
                </div>
        `
        return innerHtml
      }
    },
    // 自动播放
    autoPlay () {
      this.autoPlayTimer = setInterval(() => {
        this.checkNext('next')
      }, 3000)
    },

    // 暂停播放
    stopPlay () {
      if (this.progressControler) {
        console.log('鼠标移入时进程被打断')
        this.progressControler = !this.progressControler
      }
      clearInterval(this.autoPlayTimer)
    }
  }
}
</script>
<style lang='scss' scoped>
.container {
    width: 100%;
    height: 100%;
}

.container .windows {
    position: relative;
    left: 30%;
    top: 30%;
    font-size: 0px;
    overflow: hidden;
    width: 40%;
    height: 40%;
}

.scrollBox {
    position: absolute;
    width: 100%;
    height: 100%;
    transition: all 0.5s;
}

.windows .scrollItem {
    display: flex;
    width: 100%;
    height: 100%;
    background-color: pink;
}

.windows .scrollItem .img {
    width: 50%;
    height: 100%;
}

.windows .messBox {
    font-size: 16px;
    width: 50%;
    height: 100%;
    background-color: skyblue;
}
</style>
相关推荐
dlnu20152506221 分钟前
ssr实现方案
前端·javascript·ssr
古木20195 分钟前
前端面试宝典
前端·面试·职场和发展
轻口味2 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef5 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6415 小时前
【CSS】实现tag选中对钩样式
前端·css·css3