vue 2
1 安装插件,vue3.0安装运行会报错
npm install vue-animate-number
2 在main.js 引入
import Vue from 'vue'
import VueAnimateNumber from 'vue-animate-number'
Vue.use(VueAnimateNumber)
3 使用,from是开始值,to是结束值,加载速度duration
<animate-number from="1" to="500" duration="1000" :formatter="formatter" </animate-number>
vue3
1 安装
$ npm install animated-number-vue3
2 在main.js 引入
import AnimatedNumber from 'animated-number-vue3'
app.use(AnimatedNumber)
3 使用,(发现问题:接口筛选查询,显示数字没变化,暂时没解决)
<AnimatedNumber :from="0" :to="1000"></AnimatedNumber>
vue2和vue3 都可以使用其他组件
- 在
components
里创建文件:vue-count-to
,下创建animationFrame.js
,vue-countTo.vue
,代码如下:
- 页面引入组件
import countTo from '@/components/vue-count-to/vue-countTo'
export default {
components:{countTo},
},
- 使用 end值,duration加载速度
<countTo :end='500' :autoPlay="true" :duration='2000' />
组件vue-countTo.vue
<template>
<span>
{{ state.displayValue }}
</span>
</template>
<script setup>
import { onMounted, onUnmounted, reactive, watch, computed } from "vue";
import {
requestAnimationFrame,
cancelAnimationFrame,
} from "./animationFrame.js";
const props = defineProps({
start: {
type: Number,
required: false,
default: 0,
},
end: {
type: Number,
required: false,
default: 2021,
},
duration: {
type: Number,
required: false,
default: 5000,
},
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;
},
},
});
const isNumber = (val) => {
return !isNaN(parseFloat(val));
};
// 格式化数据,返回想要展示的数据格式
const formatNumber = (val) => {
val = Number(val).toFixed(props.default);
val += "";
const x = val.split(".");
let x1 = x[0];
const x2 = x.length > 1 ? props.decimal + x[1] : "";
const rgx = /(\d+)(\d{3})/;
if (props.separator && !isNumber(props.separator)) {
while (rgx.test(x1)) {
x1 = x1.replace(rgx, "$1" + props.separator + "$2");
}
}
return props.prefix + x1 + x2 + props.suffix;
};
// 相当于vue2中的data中所定义的变量部分
const state = reactive({
localStart: props.start,
displayValue: formatNumber(props.start),
printVal: null,
paused: false,
localDuration: props.duration,
startTime: null,
timestamp: null,
remaining: null,
rAF: null,
});
// 定义一个计算属性,当开始数字大于结束数字时返回true
const stopCount = computed(() => {
return props.start > props.end;
});
// 定义父组件的自定义事件,子组件以触发父组件的自定义事件
const emits = defineEmits(["onMountedcallback", "callback"]);
const startCount = () => {
state.localStart = props.start;
state.startTime = null;
state.localDuration = props.duration;
state.paused = false;
state.rAF = requestAnimationFrame(count);
};
watch(
() => props.start,
() => {
if (props.autoPlay) {
startCount();
}
}
);
watch(
() => props.end,
() => {
if (props.autoPlay) {
startCount();
}
}
);
// dom挂在完成后执行一些操作
onMounted(() => {
if (props.autoPlay) {
startCount();
}
emits("onMountedcallback");
});
// 暂停计数
const pause = () => {
cancelAnimationFrame(state.rAF);
};
// 恢复计数
const resume = () => {
state.startTime = null;
state.localDuration = +state.remaining;
state.localStart = +state.printVal;
requestAnimationFrame(count);
};
const pauseResume = () => {
if (state.paused) {
resume();
state.paused = false;
} else {
pause();
state.paused = true;
}
};
const reset = () => {
state.startTime = null;
cancelAnimationFrame(state.rAF);
state.displayValue = formatNumber(props.start);
};
const count = (timestamp) => {
if (!state.startTime) state.startTime = timestamp;
state.timestamp = timestamp;
const progress = timestamp - state.startTime;
state.remaining = state.localDuration - progress;
// 是否使用速度变化曲线
if (props.useEasing) {
if (stopCount.value) {
state.printVal =
state.localStart -
props.easingFn(
progress,
0,
state.localStart - props.end,
state.localDuration
);
} else {
state.printVal = props.easingFn(
progress,
state.localStart,
props.end - state.localStart,
state.localDuration
);
}
} else {
if (stopCount.value) {
state.printVal =
state.localStart -
(state.localStart - props.end) * (progress / state.localDuration);
} else {
state.printVal =
state.localStart +
(props.end - state.localStart) * (progress / state.localDuration);
}
}
if (stopCount.value) {
state.printVal = state.printVal < props.end ? props.end : state.printVal;
} else {
state.printVal = state.printVal > props.end ? props.end : state.printVal;
}
state.displayValue = formatNumber(state.printVal);
if (progress < state.localDuration) {
state.rAF = requestAnimationFrame(count);
} else {
emits("callback");
}
};
// 组件销毁时取消动画
onUnmounted(() => {
cancelAnimationFrame(state.rAF);
});
</script>
组件animationFrame.js
let lastTime = 0
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
let requestAnimationFrame
let cancelAnimationFrame
// 判断是否是服务器环境
const isServer = typeof window === 'undefined'
if (isServer) {
requestAnimationFrame = function() {
return
}
cancelAnimationFrame = function() {
return
}
} 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(() => {
callback(currTime + timeToCall)
}, timeToCall)
lastTime = currTime + timeToCall
return id
}
cancelAnimationFrame = function(id) {
window.clearTimeout(id)
}
}
}
export { requestAnimationFrame, cancelAnimationFrame }
如果想学全栈开发,从写接口到,前端实现调接口,一整套流程,可以进群获取视频资料学习!
Java全栈交流①群要是满了可以加2群 1135453115, ②群 821596752