使用vue封裝一個(gè)自定義樣式的滾動(dòng)條
話不多說(shuō),步入正題,先創(chuàng)建測(cè)試文件,測(cè)試手寫(xiě)滾動(dòng)條是否可用
// test.vue <template> <div class="scrollLayout"> <!-- 內(nèi)容 --> <div class="content" ref="content" @scroll="scroll"> <template v-for="i in 30"> <div style="width: 10rem; text-align: center">{{ i }}</div> </template> </div> <!-- 滾動(dòng)條 --> <div class="scrollBar" ref="scrollBar"> <div class="slider" :style="sliderStyle"></div> </div> </div> </template> <script setup> import { ref, onMounted } from 'vue' const content = ref(null); // ref綁定的內(nèi)容元素 const scrollBar = ref(null); // ref綁定的手寫(xiě)滾動(dòng)條 const sliderHeight = ref(0); // 滑塊高度 const position = ref(0); // 手寫(xiě)滾動(dòng)條的位置 const sliderStyle = ref(`height:${sliderHeight}%;margin-top:${position}px;`); const contentCH = ref(0); // content盒子高度 const contentSH = ref(0); // content內(nèi)容高度 const scrollBarCH = ref(0); // 滾動(dòng)條高度 const activeScrollDistance = ref(0); // 內(nèi)容滾動(dòng)的距離 const contentScrollDistance = ref(0); // 內(nèi)容滾動(dòng)的距離 onMounted(() => { const { clientHeight, scrollHeight } = content.value; contentCH.value = clientHeight; contentSH.value = scrollHeight; scrollBarCH.value = scrollBar.value.clientHeight; sliderHeight.value = (clientHeight / scrollHeight) * 100; activeScrollDistance.value = scrollBarCH.value - scrollBarCH.value * (sliderHeight.value / 100); contentScrollDistance.value = contentSH.value - contentCH.value; }) // 內(nèi)容滾動(dòng)時(shí) const scroll = () => { const { scrollTop } = content.value; position.value = (scrollTop * activeScrollDistance.value) / contentScrollDistance.value; // 滑塊需要滑動(dòng)的距離 }; </script> <style scoped> .scrollLayout { position: relative; padding: 1rem; font-size: 1rem; } .content { height: 20rem; overflow: auto; background: skyblue; } .scrollBar { position: absolute; top: 0; right: 1rem; width: 5px; /* 滾動(dòng)條的寬度 */ height: 18rem; /* 滾動(dòng)條的高度 */ background-color: pink; /* 滾動(dòng)條的顏色 */ } .slider { width: 100%; background-color: palevioletred; /* 滑塊的顏色 */ border-radius: 0.5rem; /* 滑塊圓角 */ } </style>
獲取元素的 clientHeight 和 scrollHeight 來(lái)計(jì)算滑塊的高度以及可滾動(dòng)距離,通過(guò)scrollTop獲取滾動(dòng)的距離通過(guò) scroll 事件來(lái)監(jiān)聽(tīng)內(nèi)容的滾動(dòng),從而實(shí)現(xiàn)一個(gè)簡(jiǎn)單的手搓滾動(dòng)條,下面開(kāi)始封裝。
封裝前還要考慮到的問(wèn)題:可否在同一頁(yè)面多次復(fù)用;內(nèi)容容器一般都是調(diào)接口數(shù)據(jù)進(jìn)行遍歷渲染,而v-for在渲染每個(gè)條目時(shí)是逐個(gè)插入到DOM中的,這說(shuō)明vue會(huì)先創(chuàng)建一個(gè)空的父元素,并將每個(gè)條目插入到該父元素中,這意味著 通過(guò)用ref綁定父頁(yè)面的內(nèi)容容器provide給子組件,子組件inject到dom元素的scrollHeight 這種方法不可行。
我想了一個(gè)辦法,父頁(yè)面把內(nèi)容通過(guò)slot給子組件把接口數(shù)據(jù)父?jìng)髯樱谧咏M件可以拿到接口數(shù)據(jù)和內(nèi)容dom的scrollHeight,然后用watch監(jiān)聽(tīng)props的接口數(shù)據(jù),若發(fā)生變化,重新獲取scrollHeight即可。
父頁(yè)面使用setTimeout模擬接口:
// test.vue <template> <div class="scrollLayout"> <scroll :data="arrList"> <template v-for="i in arrList"> <div style="width: 10rem; text-align: center">num: {{ i.num }}</div> </template> </scroll> </div> </template> <script setup> import { ref } from 'vue'; import scroll from '../components/scroll.vue'; const arrList = ref([]); setTimeout(() => { for (let i = 1; i <= 30; i++) { const obj = { num: i < 10 ? '0' + i : i }; arrList.value.push(obj); } }, 3000); </script> <style lang="scss" scoped> .scrollLayout { height: 10rem; background: pink; } </style>
組件部分:
// scroll.vue <template> <div class="scrollable"> <div class="content" ref="content" @scroll="scroll"> <slot></slot> </div> <div class="scrollBar" ref="scrollBar" :style="scrollBarStyle"> <div class="slider" :style="sliderStyle"></div> </div> </div> </template> <script setup> import { ref, onMounted, computed, watch, nextTick } from 'vue'; const props = defineProps({ scrollColor: { type: String, default: '', }, sliderColor: { type: String, default: '#000', }, data: { type: Array, default: [], }, right: { type: String, default: '0', }, }); const content = ref(null); // ref內(nèi)容 const scrollBar = ref(null); // ref滾動(dòng)條 const contentCH = ref(0); // content盒子高度 const contentSH = ref(0); // content內(nèi)容高度 const scrollBarCH = ref(0); // 滾動(dòng)條高度 const activeScrollDistance = ref(0); // 內(nèi)容滾動(dòng)的距離 const contentScrollDistance = ref(0); // 內(nèi)容滾動(dòng)的距離 const sliderHeight = ref(0); // 滑塊高度 const position = ref(0); // 滾動(dòng)條滑動(dòng)距離 const scrollBarStyle = computed(() => `right:${props.right}px;background:${props.scrollColor};`); const sliderStyle = computed(() => `height:${sliderHeight.value}%;margin-top:${position.value}px;background:${props.sliderColor};`); onMounted(() => { watch( () => props.data, () => { // nextTick確保在DOM更新完畢后再執(zhí)行 nextTick(() => { const { clientHeight, scrollHeight } = content.value; console.log('容器的高度:', clientHeight, '內(nèi)容高度:', scrollHeight); contentCH.value = clientHeight; contentSH.value = scrollHeight; scrollBarCH.value = scrollBar.value.clientHeight; sliderHeight.value = (clientHeight / scrollHeight) * 100; activeScrollDistance.value = scrollBarCH.value - scrollBarCH.value * (sliderHeight.value / 100); contentScrollDistance.value = contentSH.value - contentCH.value; }); }, { immediate: true, deep: true } ); }); // 監(jiān)聽(tīng)滾動(dòng) const scroll = () => { const { scrollTop } = content.value; position.value = (scrollTop * activeScrollDistance.value) / contentScrollDistance.value; }; </script> <style lang="scss" scoped> .scrollable { position: relative; display: flex; height: 100%; overflow: hidden; } .content { height: 100%; overflow: auto; &::-webkit-scrollbar { display: none; } } .scrollBar { position: absolute; top: 0; width: 5px; height: 100%; border-radius: 5px; .slider { width: 100%; border-radius: 3px; } } </style>
這樣就可以解決初始獲取的scrollHeight是內(nèi)容插入前的高度——即容器高度。
以上就是使用vue封裝一個(gè)自定義樣式的滾動(dòng)條的詳細(xì)內(nèi)容,更多關(guān)于vue封裝滾動(dòng)條的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vuex state中同步數(shù)據(jù)和異步數(shù)據(jù)方式
這篇文章主要介紹了Vuex state中同步數(shù)據(jù)和異步數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08Vue 中 reactive創(chuàng)建對(duì)象類型響應(yīng)式數(shù)據(jù)的方法
在 Vue 的開(kāi)發(fā)世界里,響應(yīng)式數(shù)據(jù)是構(gòu)建交互性良好應(yīng)用的基礎(chǔ),之前我們了解了ref用于定義基本類型的數(shù)據(jù),今天就來(lái)深入探討一下如何使用reactive定義對(duì)象類型的響應(yīng)式數(shù)據(jù),感興趣的朋友一起看看吧2025-02-02Vue3使用Vue Router實(shí)現(xiàn)前端路由控制
在現(xiàn)代Web應(yīng)用中,前端路由控制是非常重要的一部分,它可以幫助我們將不同的頁(yè)面內(nèi)容展示給用戶,同時(shí)保持用戶在瀏覽不同頁(yè)面時(shí)的連貫性,本文將介紹如何使用Vue Router來(lái)實(shí)現(xiàn)前端路由控制,需要的朋友可以參考下2024-10-10解決vue父組件調(diào)用子組件只執(zhí)行一次問(wèn)題
開(kāi)發(fā)中,需求是將內(nèi)容展示作為一個(gè)組件,輸入為contentId,請(qǐng)求在組件中,只需根據(jù)父組件傳過(guò)來(lái)的contentId去請(qǐng)求內(nèi)容的詳情即可,但是過(guò)程中卻發(fā)現(xiàn)一個(gè)問(wèn)題,父組件調(diào)用子組件只執(zhí)行一次,所以本文就給大家介紹解決vue父組件調(diào)用子組件只執(zhí)行一次問(wèn)題2023-09-09vue elementui 動(dòng)態(tài)追加下拉框、輸入框功能
這篇文章主要介紹了vue elementui 動(dòng)態(tài)追加下拉框、輸入框功能,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-04-04vue?目錄樹(shù)的展開(kāi)與關(guān)閉的實(shí)現(xiàn)
Vue作為一款流行的前端框架,提供了一種數(shù)據(jù)驅(qū)動(dòng)的方式來(lái)實(shí)現(xiàn)目錄樹(shù),本文主要介紹了vue?目錄樹(shù)的展開(kāi)與關(guān)閉的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11vue-router權(quán)限控制(簡(jiǎn)單方式)
這篇文章主要介紹了vue-router權(quán)限控制(簡(jiǎn)單方式),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10vue3手動(dòng)設(shè)置滾動(dòng)條位置自動(dòng)定位功能
這篇文章介紹了vue3手動(dòng)設(shè)置滾動(dòng)條位置自動(dòng)定位功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-12-12Vue項(xiàng)目三級(jí)聯(lián)動(dòng)路由跳轉(zhuǎn)與傳參的思路詳解
這篇文章主要介紹了Vue項(xiàng)目三級(jí)聯(lián)動(dòng)的路由跳轉(zhuǎn)與傳參的思路詳解,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08