使用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)髯?,在子組件可以拿到接口數(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)文章
vue3使用vuedraggable實(shí)現(xiàn)拖拽功能
這篇文章主要為大家詳細(xì)介紹了vue3使用vuedraggable實(shí)現(xiàn)拖拽功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
vue實(shí)現(xiàn)前端展示后端實(shí)時(shí)日志帶顏色示例詳解
這篇文章主要為大家介紹了vue實(shí)現(xiàn)前端展示后端實(shí)時(shí)日志帶顏色示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
vue自定義指令實(shí)現(xiàn)懶加載的優(yōu)化指南
這篇文章主要為大家詳細(xì)介紹了vue如何通過(guò)自定義指令實(shí)現(xiàn)懶加載并進(jìn)行相關(guān)優(yōu)化,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-07-07
如何將iconfont圖標(biāo)引入到vant的Tabbar標(biāo)簽欄里邊
這篇文章主要介紹了如何將iconfont圖標(biāo)引入到vant的Tabbar標(biāo)簽欄里邊,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
Vue中CSS動(dòng)畫(huà)原理的實(shí)現(xiàn)
這篇文章主要介紹了Vue中CSS動(dòng)畫(huà)原理的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02

