Vue2實(shí)現(xiàn)數(shù)字滾動(dòng)翻頁(yè)效果的示例代碼
前言
最近大屏項(xiàng)目中有數(shù)值需要數(shù)值變化時(shí)有一個(gè)炸裂的效果,對(duì)用戶來(lái)說(shuō)明顯一點(diǎn),經(jīng)過(guò)幾番查找,自己又重新修改總結(jié),發(fā)出下面文,防止下次遇到。
實(shí)現(xiàn)這種效果有兩種方法:
第一種方法
參考文章:【vue2】實(shí)現(xiàn)數(shù)字縱向滾動(dòng)效果(計(jì)時(shí)器效果)
第一種方法雖然實(shí)現(xiàn)了效果,但是數(shù)值變化整體都重新滾動(dòng)了,不太好。
效果
新建文件FlipItem.vue
<template> <div style=" display: inline-flex; justify-content: flex-start; align-items: center; " > <div v-for="(item, index) in numberList" :key="index" style=" display: inline-flex; justify-content: flex-start; align-items: center; padding-bottom: 0.3rem; box-sizing: border-box; " > <span v-if="isNaN(item)">{{ item }}</span> <div class="number" v-else :style="{ color: TextColor }"> <span class="number-item" ref="numberItem" :data-number="item" :data-index="index" >0123456789</span > </div> </div> </div> </template> <script> export default { name: "ScrollNumber", props: { value: { type: [String, Number], default: 0, }, TextColor: { type: String, default: "black", }, }, watch: { value: { handler(newValue, oldValue) { // console.log("?? ~ value ~ newVal:", newValue); if (newValue) { this.$nextTick(() => { this.setNumberTransform(); }); } }, deep: true, immediate: true, }, TextColor: { handler(newValue, oldValue) { console.log("?? ~ handler ~ newValue:", newValue); this.TextColor = newValue; }, deep: true, immediate: true, }, }, computed: { numberList() { return String(this.value).split(""); }, pageColor() { return { "--TextColor": this.TextColor, }; }, }, data() { return { hasShow: false, // 是否已展示過(guò)動(dòng)畫(huà) // TextColor: "red", }; }, mounted() { window.addEventListener("scroll", this.scrollHandle, true); // 監(jiān)聽(tīng) 監(jiān)聽(tīng)元素是否進(jìn)入/移出可視區(qū)域 }, methods: { scrollHandle() { const offset = this.$el.getBoundingClientRect(); const offsetTop = offset.top; const offsetBottom = offset.bottom; // 進(jìn)入可視區(qū)域 if (offsetTop <= window.innerHeight && offsetBottom >= 0) { this.setNumberTransform(); this.hasShow = true; window.removeEventListener("scroll", this.scrollHandle, true); } else { // 移出可視區(qū)域 if (this.hasShow) { window.removeEventListener("scroll", this.scrollHandle, true); } } }, // 設(shè)置每一位數(shù)字的偏移 setNumberTransform() { let numberItems = this.$refs.numberItem; let obj = {}; Array.from(numberItems).forEach((c) => { let key = c.dataset.index; let value = c.dataset.number; let init = 0; obj[key] = setInterval(() => { if (init < value * 10) { init += 1; c.style.transform = `translateY(-${init}%)`; } else { clearInterval(obj[key]); obj[key] = null; } }, 8); }); }, }, }; </script> <style scoped lang="scss"> .number { width: 30px; height: 30px; font-size: 25px; font-weight: 800; color: var(--TextColor); text-align: center; overflow: hidden; span { text-align: center; writing-mode: vertical-rl; text-orientation: upright; transform: translateY(0%); } } </style>
父組件引用
<template> <div class="father"> <FlipItemVue :value="num.toString()" :TextColor="TextColor"></FlipItemVue> <button @click="NumChangeFn">點(diǎn)擊變更數(shù)字</button> </div> </template> <script> import FlipItemVue from "./FlipItem.vue"; export default { components: { FlipItemVue, }, data() { return { num: 123456, TextColor: "red", }; }, methods: { NumChangeFn() { this.num = 9999999; }, }, }; </script> <style lang="scss" scoped> </style>
第二種方法
第二種方法效果更好一點(diǎn),數(shù)字滾動(dòng)更絲滑自然只有變化的數(shù)值滾動(dòng)。這里我就沒(méi)有封裝也就copy了一個(gè)demo過(guò)來(lái)了,問(wèn)題:1、我封裝了首次接受數(shù)值時(shí)只有第一個(gè)數(shù)字滾動(dòng),2、頁(yè)面首次渲染如果是三個(gè)數(shù)字,那么寬度就固定了。這時(shí)候傳過(guò)來(lái)新值是四個(gè)字,可能就會(huì)出現(xiàn)內(nèi)容超出。(可能我個(gè)人問(wèn)題)
效果
新建文件Index.vue
<template> <div class="days-box"> <div class="operating-title">安全運(yùn)行天數(shù)</div> <div class="box-item"> <li :class="{ 'number-item': !isNaN(item), 'mark-item': isNaN(item), }" v-for="(item, index) in runningDays" :key="index" > <span v-if="!isNaN(item)"> <i ref="numberItem">0123456789</i> </span> <span class="comma" v-else>{{ item }}</span> </li> </div> <button @click="toRunningNum(399)">點(diǎn)擊</button> </div> </template> <script> export default { data() { return { runningDays: ["0", "0", "0", "0", "0", "0", "0", "0"], }; }, mounted() { // 獲取當(dāng)前日期 var today = new Date(); // 設(shè)置起始日期 var startDate = new Date("2023-04-24"); // 計(jì)算天數(shù)差 var timeDiff = Math.abs(today.getTime() - startDate.getTime()); var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24)); this.$nextTick(() => { this.toRunningNum(diffDays); // 這里輸入數(shù)字即可調(diào)用 this.setNumberTransform(); }); }, methods: { // 設(shè)置文字滾動(dòng) setNumberTransform() { const numberItems = this.$refs.numberItem; // 拿到數(shù)字的ref,計(jì)算元素?cái)?shù)量 console.log("?? ~ setNumberTransform ~ numberItems:", numberItems); const numberArr = this.runningDays.filter((item) => !isNaN(item)); // 結(jié)合CSS 對(duì)數(shù)字字符進(jìn)行滾動(dòng),顯示訂單數(shù)量 for (let index = 0; index < numberItems.length; index++) { const elem = numberItems[index]; elem.style.transform = `translate(-50%, -${numberArr[index] * 10}%)`; } }, // 處理數(shù)字 toRunningNum(num) { num = num.toString(); this.runningDays = num.split(""); // 將其便變成數(shù)據(jù),渲染至滾動(dòng)數(shù)組 this.setNumberTransform(); }, }, }; </script> <style lang="scss" scoped> .days-box { display: flex; flex-direction: column; justify-content: center; align-items: center; } /*滾動(dòng)數(shù)字設(shè)置*/ .operating-title { color: black; font-size: 16px; margin-bottom: 10px; } .box-item { position: relative; height: 80px; font-size: 54px; line-height: 41px; text-align: center; list-style: none; // color: #2d7cff; color: #fff; writing-mode: vertical-lr; text-orientation: upright; /*文字禁止編輯*/ -moz-user-select: none; /*火狐*/ -webkit-user-select: none; /*webkit瀏覽器*/ -ms-user-select: none; /*IE10*/ -khtml-user-select: none; /*早期瀏覽器*/ user-select: none; /* overflow: hidden; */ } /* 默認(rèn)逗號(hào)設(shè)置 */ .mark-item { width: 10px; height: 100px; margin-right: 5px; line-height: 10px; font-size: 48px; position: relative; & > span { position: absolute; width: 100%; bottom: 0; writing-mode: vertical-rl; text-orientation: upright; } } /*滾動(dòng)數(shù)字設(shè)置*/ .number-item { width: 41px; height: 75px; // background: #ccc; list-style: none; margin-right: 5px; // background: rgb(7, 50, 207); border-radius: 4px; // border: 1px solid rgba(7, 50, 207, 1); color: black; & > span { position: relative; display: inline-block; margin-right: 10px; width: 100%; height: 100%; writing-mode: vertical-rl; text-orientation: upright; overflow: hidden; & > i { font-style: normal; position: absolute; top: 11px; left: 50%; transform: translate(-50%, 0); transition: transform 1s ease-in-out; letter-spacing: 10px; } } } </style>
到此這篇關(guān)于Vue2實(shí)現(xiàn)數(shù)字滾動(dòng)翻頁(yè)效果的示例代碼的文章就介紹到這了,更多相關(guān)Vue2數(shù)字滾動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue3+vite兼容低版本的白屏問(wèn)題詳解(安卓7/ios11)
這篇文章主要給大家介紹了關(guān)于vue3+vite兼容低版本的白屏問(wèn)題的相關(guān)資料,還給大家介紹了vue打包項(xiàng)目以后白屏和圖片加載不出來(lái)問(wèn)題的解決方法,需要的朋友可以參考下2022-12-12Vue3新屬性之css中使用v-bind的方法(v-bind?in?css)
這篇文章主要介紹了Vue3新屬性css中使用v-bind(v-bind?in?css)的方法,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01Vue 報(bào)錯(cuò)Error: No PostCSS Config foun
這篇文章主要介紹了Vue 報(bào)錯(cuò)Error: No PostCSS Config found問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07vue實(shí)現(xiàn)點(diǎn)擊復(fù)制到粘貼板
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)點(diǎn)擊復(fù)制到粘貼板,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Vue3中關(guān)于ref和reactive的區(qū)別分析
這篇文章主要介紹了vue3關(guān)于ref和reactive的區(qū)別分析,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-06-06setup+ref+reactive實(shí)現(xiàn)vue3響應(yīng)式功能
這篇文章介紹了通過(guò)setup+ref+reactive實(shí)現(xiàn)vue3響應(yīng)式功能,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11vue下拉菜單組件(含搜索)的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue下拉菜單組件(含搜索)的實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11