vue3滚动组件

笔者使用的是vue3-seamless-scroll:GitHub - xfy520/vue3-seamless-scroll: Vue3.0 无缝滚动组件

全局注册笔者的出现红色波浪线,但单个.vue文件局部注册不会

 我的代码:

<template>
    <div class="tabBox">
       <div class="tabBox-head">
            <div class="row">
               <span class="xh">序号</span> 
               <span v-for="item in tabHeadData" :key="item.id">{{ item.nickname }}</span>
            </div>
       </div>
       <div class="tabBox-body" :style="{ height: TBH + 'px' }">
            // limitScrollNum:tableData数据长度大于几条开始滚动
            // step:步进速度(滚动行数)
            // copyNum:拷贝列表次数
            // delay:动画延时时间
            <vue3-seamless-scroll :list="tableData" :limitScrollNum="1" :step="1" :copyNum="4" :delay="10">
                <div class="row" v-for="(item,index) in tableData" :key="item.id">
                    <span class="xh">{{index + 1}}</span>
                    <span v-for="it in tabHeadData" :key="it.id">{{ item[it.filed] }}</span>
                </div>
            </vue3-seamless-scroll>
       </div>
    </div>
</template>

<script setup lang="ts">
import { Vue3SeamlessScroll } from "vue3-seamless-scroll";

const tabHeadData:any = [
    {
        id:1,
        filed:'name',
        nickname:'名字'
    },
    {
        id:2,
        filed:'age',
        nickname:'年龄'
    }
]
const tableData:any = [
    {
        id:1,
        name:'张三',
        age:18
    },
    {
        id:2,
        name:'李四',
        age:25
    },
    {
        id:3,
        name:'王五',
        age:20
    },
    {
        id:4,
        name:'丁六',
        age:30
    },
    {
        id:5,
        name:'杨七',
        age:19
    }
]

const state:any = reactive({
    lineHeight:30,
    padding:10,
    num:5  //展示的行数
})
// 表体高度计算
const TBH = computed(() => {
    return (state.lineHeight + state.padding * 2 + 1) * state.num
})

</script>

<style lang="scss" scoped>

</style>

效果图:

以下展示的是笔者用js写的滚动:

<template>
  <div class="listBox" :style="[listBoxStyle]">
    <div class="screen">
      <div class="listBox-body" :id="eleProp.id">

        <div class="listBox-body-item">
          <div class="col" v-for="(item,index) in tableData" :key="index">
            <div class="text">
              <div class="l">
                <span class="order">{{ `No.${index+1}` }}</span>
                <span class="data name">{{ item.name }}</span>
              </div>
              <div class="r data num">{{ item.age }}</div>
            </div>
            <div class="line">
              <div class="bf" :style="{'width':getW(item.age,eleProp.max)}"></div>
            </div>
          </div>
        </div>

      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {animation} from '@/utils/animation.ts'

const tableData:any = [
    {
        id:1,
        name:'张三',
        age:30
    },
    {
        id:2,
        name:'李四',
        age:25
    },
    {
        id:3,
        name:'王五',
        age:20
    },
    {
        id:4,
        name:'丁六',
        age:30
    },
    {
        id:5,
        name:'杨七',
        age:19
    }
]

//样式
const listBoxStyle = computed(() => {
  return {
    '--col-h':'calc('+(300 - 20)+'px/'+ eleProp.scrollNum+')', //计算行高
    '--main-c': '#1370FB',
    '--data-c': '#000',
    '--border-c': '#CDD2F8',
    '--order-s': '20px',
    '--tit-s': '16px',
    '--num-s': '16px'
  }
})

// 获取类名为bf的Dom的宽度
const getW = (num:number,total:number) => {
  return (100 / total) * num + '%'
}
// 动画
const eleProp:any = reactive({
  ele:null,
  num:0,
  flag:true,
  count:0, //数据个数
  timer:null,
  id:'listBox-body'
  max:30,  //年龄最大值
  scrollNum:4 //滚动个数
})

onMounted(() => {
  eleProp.count = tableData.length

  if(eleProp.count >= eleProp.scrollNum) {
    eleProp.ele = document.querySelector('#' + eleProp.id)
    // 克隆一个.listBox-body-item及其子元素
    const sonDomCopy = eleProp.ele.children[0].cloneNode(true) 
    eleProp.ele.appendChild(sonDomCopy)

    autoEvent()
  }
  
})

const autoEvent = () => {
  eleProp.timer = setInterval(function(){
		listAnimation()
	}, 1000)
}

const listAnimation = () => {
  //为了预防上一次listAnimation未执行完又执行listAnimation导致滚动速度加快
  if(!eleProp.flag){ 
 	return;
  }
  eleProp.flag=false
  eleProp.num ++;
  animation({
	  ele: eleProp.ele,
	  target : -eleProp.ele.children[0].children[0].offsetHeight*eleProp.num, 
	  attr : 'top',
	  callback : function(){
          if(eleProp.num == eleProp.count){
            eleProp.num = 0;
            eleProp.ele.style.top = 0;
          }
          eleProp.flag=true;
	  }
	});
}

</script>

<style lang="scss" scoped>
@import '@/assets/styles/list.scss';
</style>
// utils/animation.ts

/**
 * * 列表动画
 * @param options
 */
export const animation = (options:any) => {
  //先清除再开启
  clearInterval(options.ele.timer);
  //使用定时器
  options.ele.timer = setInterval(function(){
		//获取到现在的位置
		var begin = parseInt(getStyle(options.ele, options.attr));
		//步长  step = (target - begin)/10
		var step = (options.target - begin)/10;
		step = step > 0 ? Math.ceil(step) : Math.floor(step); 
		//位置+步长
		var res = begin + step;
		//赋值
		options.ele.style[options.attr] = res + 'px';
		
		if(res == options.target){
			clearInterval(options.ele.timer);
			//当有这个函数名称的时候,再调用函数
			//两个条件必须都满足,才能执行
			options.callback && options.callback();
		}
  }, 30)
}

/**
 **获取元素样式
 */
const getStyle = (obj:any, attr:any) => {
  if((window as any).getComputedStyle){
		return getComputedStyle(obj, null)[attr];
	}else{
		return obj.currentStyle[attr];
	}
}
// list.scss

.listBox {
  width: 500px;
  height: 300px;
  padding: 10px;
  box-sizing: border-box;
  .screen {
    height: 100%;
    width: 100%;
    overflow: hidden;
    position: relative;
  }
  .listBox-body {
    position: absolute;
    width: 100%;
    left: 0;
  }

  .col {
    position: relative;
    height: var(--col-h);
    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;
    .text {
      display: flex;
      justify-content: space-between;
      align-items: center;
      width: 100%;
      div {
        display: inline-flex;
        align-items: center;
      }
      .data {color: var(--data-c);}
      .order {font-size: var(--order-s);color: var(--main-c);margin-right: 10px;}
      .name {font-size: var(--tit-s);}
      .num {font-size: var(--num-s);}
    }
    .line {
      border-bottom: 1px solid var(--border-c);
      width: 100%;
      .bf {
        height: 4px;
        background-color: var(--main-c);
        overflow: hidden;
        border-radius: 10px;
        position: relative;
        &::before {
            content: '';
            position: absolute;
            width: 100%;
            height: 100%;
            opacity: .3;
            background-color: white;
            left: 0;
            top: 0;
            animation: widthAnimate 2s linear infinite;
        }
      }
    }
    &:nth-child(5n+2) .bf::before{
      animation-delay: .5s;
    }
    &:nth-child(5n+3) .bf::before{
      animation-delay: 1s;
    }
    &:nth-child(5n+4) .bf::before{
      animation-delay: 1.5s;
    }
    &:nth-child(5n+5) .bf::before{
      animation-delay: 2s;
    }
  }
}
@keyframes widthAnimate {
  from {
    width: 0%;
  }
  to{
    width: 100%;
  }
}

 效果图

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值