【性能优化】在大批量数据下使用 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>
相关推荐
艾小码14 小时前
告别加班!这些数组操作技巧让前端开发效率翻倍
前端·javascript
Rhys..15 小时前
ES6是什么
前端·javascript·es6
Jammingpro16 小时前
【Vue专题】前端JS基础Part1(含模版字符串、解构赋值、变量常量与对象)
前端·javascript·vue.js
jiangzhihao051520 小时前
前端自动翻译插件webpack-auto-i18n-plugin的使用
前端·webpack·node.js
软件技术NINI1 天前
html css网页制作成品——HTML+CSS盐津铺子网页设计(5页)附源码
前端·css·html
Pu_Nine_91 天前
教程: 在网页中利用原生CSS实现3D旋转动画
css·3d·css3
mapbar_front1 天前
面试问题—我的问题问完了,你还有什么想问我的吗?
前端·面试
quweiie1 天前
thinkphp8+layui多图上传,带删除\排序功能
前端·javascript·layui
李鸿耀1 天前
React 项目 SVG 图标太难管?用这套自动化方案一键搞定!
前端
闲蛋小超人笑嘻嘻1 天前
树形结构渲染 + 选择(Vue3 + ElementPlus)
前端·javascript·vue.js