vue3+elementPlus:实现数字滚动效果(用于大屏可视化)

文章介绍了如何在Vue中自定义NumberScroll组件实现数字滚动效果,并展示了如何在Vue3中使用requestAnimationFrame和vue-count-to插件进行计数动画,以及uniapp中的预览图片功能uni.previewImage的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自行封装注册一个公共组件

案例一:

//成功案例:
//NumberScroll.vue
/*
数字滚动特效组件 NumberScroll
*/

<template>
  <span class="number-scroll-grow">
    <span
      ref="numberScroll"
      :data-time="time"
      class="number-scroll"
      :data-value="value">
      0
      </span>
  </span>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
  name: "numberScroll",
  props: {
    time: {
      type: Number,
      default: 2,
    },
    value: {
      type: Number,
      default: 0,
    },
    thousandSign: {
      type: Boolean,
      default: () => false,
    },
  },
  data() {
    return {
      oldValue: 0,
    };
  },
  watch: {
    value: function (value, oldValue) {
      this.numberScroll(this.$refs.numberScroll);
    },
  },
  methods: {
    numberScroll(ele) {
      let _this = this;
      let value = _this.value - _this.oldValue;
      let step = (value * 10) / (_this.time * 100);
      let current = 0;
      let start = _this.oldValue;
      let t = setInterval(function () {
        start += step;
        if (start > _this.value) {
          clearInterval(t);
          start = _this.value;
          t = null;
        }
        if (current === start) {
          return;
        }
        current = parseInt(start);
        _this.oldValue = current;
        if (_this.thousandSign) {
          ele.innerHTML = current
            .toString()
            .replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, "$1,");
        } else {
          ele.innerHTML = current.toString();
        }
      }, 10);
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.numberScroll(this.$refs.numberScroll);
    });
  },
});
</script>

<style lang="scss" scoped>
.number-scroll-grow {
  transform: translateZ(0);
}
</style>

//单页面
//html
<div class="count">
  <!-- 组件 -->
  <numberScroll :value="datalist.equip.realTimeDeviceCount" :time="30"></numberScroll>
</div>

案例二

这个是拉取vue-count-to插件源码,因为这个插件在vue3里不能用

//先在common文件夹建立requestAnimationFrame.js
let lastTime = 0
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀

let requestAnimationFrame
let cancelAnimationFrame

const isServer = typeof window === 'undefined'
if (isServer) {
 requestAnimationFrame = function () {
 }
 cancelAnimationFrame = function () {
 }
} else {
 requestAnimationFrame = window.requestAnimationFrame
 cancelAnimationFrame = window.cancelAnimationFrame
 let prefix
 // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
 for (let i = 0; i < prefixes.length; i++) {
 if (requestAnimationFrame && cancelAnimationFrame) { break }
 prefix = prefixes[i]
 requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
 cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
 }

 // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
 if (!requestAnimationFrame || !cancelAnimationFrame) {
 requestAnimationFrame = function (callback) {
 const currTime = new Date().getTime()
 // 为了使setTimteout的尽可能的接近每秒60帧的效果
 const timeToCall = Math.max(0, 16 - (currTime - lastTime))
 const id = window.setTimeout(() => {
 const time = currTime + timeToCall
 callback(time)
 }, timeToCall)
 lastTime = currTime + timeToCall
 return id
 }

 cancelAnimationFrame = function (id) {
 window.clearTimeout(id)
 }
 }
}

export { requestAnimationFrame, cancelAnimationFrame }

//再在components文件夹建立CountTo.vue
<template>
  <span>
  {{displayValue}}
  </span>
 </template>
 <script>
 import { requestAnimationFrame, cancelAnimationFrame } from '../common/js/requestAnimationFrame.js'
 export default {
  props: {
  startVal: {
  type: Number,
  required: false,
  default: 0
  },
  endVal: {
  type: Number,
  required: false,
  default: null
  },
  duration: {
  type: Number,
  required: false,
  default: 3000
  },
  autoplay: {
  type: Boolean,
  required: false,
  default: true
  },
  //小数点位数
  decimals: {
  type: Number,
  required: false,
  default: 0,
  validator (value) {
  return value >= 0
  }
  },
  decimal: {
  type: String,
  required: false,
  default: '.'
  },
  separator: {
  type: String,
  required: false,
  default: ','
  },
  prefix: {
  type: String,
  required: false,
  default: ''
  },
  suffix: {
  type: String,
  required: false,
  default: ''
  },
  useEasing: {
  type: Boolean,
  required: false,
  default: true
  },
  easingFn: {
  type: Function,
  default (t, b, c, d) {
  return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b
  }
  }
  },
  data () {
  return {
  localStartVal: this.startVal,
  displayValue: this.formatNumber(this.startVal),
  printVal: null,
  paused: false,
  localDuration: this.duration,
  startTime: null,
  timestamp: null,
  remaining: null,
  rAF: null
  }
  },
  computed: {
  countDown () {
  return this.startVal > this.endVal
  }
  },
  watch: {
  startVal () {
  if (this.autoplay) {
  this.start()
  }
  },
  endVal () {
  if (this.autoplay) {
  this.start()
  }
  }
  },
  mounted () {
  if (this.autoplay) {
  this.start()
  }
  this.$emit('mountedCallback')
  },
  methods: {
  start () {
  this.localStartVal = this.startVal
  this.startTime = null
  this.localDuration = this.duration
  this.paused = false
  this.rAF = requestAnimationFrame(this.count)
  },
  pauseResume () {
  if (this.paused) {
  this.resume()
  this.paused = false
  } else {
  this.pause()
  this.paused = true
  }
  },
  pause () {
  cancelAnimationFrame(this.rAF)
  },
  resume () {
  this.startTime = null
  this.localDuration = +this.remaining
  this.localStartVal = +this.printVal
  requestAnimationFrame(this.count)
  },
  reset () {
  this.startTime = null
  cancelAnimationFrame(this.rAF)
  this.displayValue = this.formatNumber(this.startVal)
  },
  count (timestamp) {
  if (!this.startTime) this.startTime = timestamp
  this.timestamp = timestamp
  const progress = timestamp - this.startTime
  this.remaining = this.localDuration - progress
 
  if (this.useEasing) {
  if (this.countDown) {
  this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration)
  } else {
  this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration)
  }
  } else {
  if (this.countDown) {
  this.printVal = this.localStartVal - ((this.localStartVal - this.endVal) * (progress / this.localDuration))
  } else {
  this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration)
  }
  }
  if (this.countDown) {
  this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal
  } else {
  this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal
  }
 
  this.displayValue = this.formatNumber(this.printVal)
  if (progress < this.localDuration) {
  this.rAF = requestAnimationFrame(this.count)
  } else {
  this.$emit('callback')
  }
  },
  isNumber (val) {
  return !isNaN(parseFloat(val))
  },
  formatNumber (num) {
  num = num.toFixed(this.decimals)
  num += ''
  const x = num.split('.')
  let x1 = x[0]
  const x2 = x.length > 1 ? this.decimal + x[1] : ''
  const rgx = /(\d+)(\d{3})/
  if (this.separator && !this.isNumber(this.separator)) {
  while (rgx.test(x1)) {
  x1 = x1.replace(rgx, '$1' + this.separator + '$2')
  }
  }
  return this.prefix + x1 + x2 + this.suffix
  }
  },
  unmounted () {
  cancelAnimationFrame(this.rAF)
  }
 }
 </script>
 
 //最后在单文件的html里直接使用
<count-to :
startVal="0" 
:endVal="datalist.equip.realTimeDeviceCount" 
:duration="4000">
</count-to>

上一篇文章,

uniapp踩坑之项目:uni.previewImage简易版预览单图片-优快云博客文章浏览阅读547次。uniapp踩坑之项目:uni.previewImage简易版预览单图片,主要使用uni.previewImage_uni.previewimagehttps://blog.youkuaiyun.com/weixin_43928112/article/details/136565397?spm=1001.2014.3001.5501

### Vue3 中使用 Element Plus 实现表格滚动 #### 表格滚动的基础设置 为了使 `el-table` 组件能够支持滚动,需配置其属性来适应不同的需求。对于水平和垂直方向上的滚动效果,可以通过设定 `height` 或者 `max-height` 属性让表格具备固定的头部,在内容超出容器高度时自动显示滚动条[^2]。 ```html <template> <div class="table-container"> <!-- 设置最高度 --> <el-table :data="tableData" style="width: 100%" max-height="400"> <el-table-column prop="date" label="日期"></el-table-column> <el-table-column prop="name" label="姓名"></el-table-column> <el-table-column prop="address" label="地址"></el-table-column> </el-table> </div> </template> <script setup> import { ref } from &#39;vue&#39; const tableData = ref([ { date: &#39;2016-05-03&#39;, name: &#39;Tom&#39;, address: &#39;No. 189, Grove St, Los Angeles&#39; }, // 更多的数据项... ]) </script> ``` #### 动态监听滚动事件并响应 当需要对用户的滚动行为做出反应时,可以利用 JavaScript 的原生方法获取到 `.el-table__body-wrapper` 这个特定类名下的 DOM 节点,并为其绑定自定义的滚动事件处理器函数 `onScrollHandler()` 来执行相应的逻辑操作。 ```javascript // 在 mounted 生命周期钩子内初始化滚动事件监听器 mounted() { const bodyWrapper = document.querySelector( &#39;.detailTable .el-table__body-wrapper .el-scrollbar__wrap&#39; ); if (bodyWrapper) { bodyWrapper.addEventListener(&#39;scroll&#39;, this.onScollbar); } } methods: { onScollbar(event) { console.log(`当前滚动距离:${event.target.scrollTop}`); // 可在此处添加更多业务逻辑代码 } } ``` 需要注意的是,上述方式适用于全局范围内捕获指定元素的滚动动作;如果希望仅针对某个实例内的组件,则建议采用更安全的方式——通过模板引用(refs)机制访问内部节点,从而避免潜在的选择符冲突风险。 #### 自动加载新数据(懒加载) 为了让用户体验更加流畅,可以在用户接近页面底部之前预先加载下一页的内容。这通常涉及到计算可视区域小以及判断何时触发新的请求去拉取额外的信息片段。 ```javascript computed: { isNearBottom() { const wrapper = document.querySelector(&#39;.el-table__body-wrapper&#39;); return ( wrapper && wrapper.scrollHeight - Math.ceil(wrapper.scrollTop + wrapper.clientHeight) < 500 ); // 当剩余未见部分小于等于500px时认为即将触底 } }, watch: { async isNearBottom(val) { if (!this.loading && val) { await fetchData(); this.loading = false; } } } ``` 以上就是有关于 Vue3 结合 Element Plus 库创建具有滚动特性的交互式表格的一些基本指导和技术要点介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值