滚动组件 Scrollbar
由于默认浏览器滚动条极为丑陋切不同浏览器之间样式不统一,故封装一个滚动组件用于实现滚动
基础用法
使用b-scrollbar进行包裹,默认slot为内容显示区域,如当前示例所包含的滚动结构如下:
<template>
<div style="height: 300px">
<b-scrollbar ref="componentScrollBar" style="height: 100%">
<div class="scrollbar-demo-list">
<div v-for="i in 12" :key="i" class="scrollbar-demo-item">滚动示例块 {{ i }}</div>
</div>
</b-scrollbar>
</div>
</template>
<style scoped>
.scrollbar-demo-list {
padding: 4px;
}
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
margin: 10px 0;
border-radius: 8px;
background: linear-gradient(135deg, #f8fbff 0%, #eef5ff 100%);
color: #3a4a66;
font-weight: 500;
}
</style>注意:如果内容区域不超过容器高度则不会生成滚动条
最大高度
通过 max-height 可以限制滚动区域的最大高度,只有内容超出时才会出现滚动条。
第 1 项内容
第 2 项内容
第 3 项内容
第 4 项内容
第 5 项内容
<template>
<div>
<div style="margin-bottom: 12px">
<b-button size="small" @click="add">增加内容</b-button>
<b-button size="small" style="margin-left: 8px" @click="remove">删除内容</b-button>
</div>
<b-scrollbar max-height="320px">
<p v-for="item in count" :key="item" class="scrollbar-demo-item">
第 {{ item }} 项内容
</p>
</b-scrollbar>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(5)
function add() {
count.value++
}
function remove() {
if (count.value > 0) {
count.value--
}
}
</script>
<style scoped>
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
margin: 10px 0;
border-radius: 6px;
background: #f5f7fa;
color: #606266;
}
</style>手动滚动
可以通过组件暴露的 setScrollTop、setScrollLeft 方法手动控制滚动位置。
手动滚动示例 1
手动滚动示例 2
手动滚动示例 3
手动滚动示例 4
手动滚动示例 5
手动滚动示例 6
手动滚动示例 7
手动滚动示例 8
手动滚动示例 9
手动滚动示例 10
手动滚动示例 11
手动滚动示例 12
手动滚动示例 13
手动滚动示例 14
手动滚动示例 15
手动滚动示例 16
手动滚动示例 17
手动滚动示例 18
手动滚动示例 19
手动滚动示例 20
<template>
<div>
<b-scrollbar ref="scrollbarRef" height="320px" always @scroll="handleScroll">
<div ref="innerRef">
<p v-for="item in 20" :key="item" class="scrollbar-demo-item">
手动滚动示例 {{ item }}
</p>
</div>
</b-scrollbar>
<div style="margin-top: 16px">
<b-slider v-model="value" :max="max" :format-tooltip="formatTooltip"></b-slider>
</div>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref, watch } from 'vue'
const max = ref(0)
const value = ref(0)
const innerRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<{
setScrollTop: (scrollTop: number) => void
wrapRef?: {
value: HTMLElement | null
}
} | null>(null)
function handleScroll({ scrollTop }: { scrollTop: number }) {
value.value = scrollTop
}
function formatTooltip(currentValue: number) {
return `${currentValue}px`
}
function updateMaxScroll() {
const wrapElement = scrollbarRef.value?.wrapRef?.value
const contentHeight = innerRef.value?.clientHeight || 0
const viewportHeight = wrapElement?.clientHeight || 0
max.value = Math.max(contentHeight - viewportHeight, 0)
}
watch(value, currentValue => {
scrollbarRef.value?.setScrollTop(currentValue)
})
onMounted(async () => {
await nextTick()
updateMaxScroll()
})
</script>
<style scoped>
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
margin: 10px 0;
border-radius: 6px;
background: #f5f7fa;
color: #606266;
}
</style>始终显示
使用always可以让滚动条始终显示出来
<template>
<div style="height: 300px">
<b-scrollbar ref="componentScrollBar" always noresize>
<div class="scrollbar-demo-list">
<div v-for="i in 12" :key="i" class="scrollbar-demo-item">始终显示滚动块 {{ i }}</div>
</div>
</b-scrollbar>
</div>
</template>
<style scoped>
.scrollbar-demo-list {
padding: 4px;
}
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
margin: 10px 0;
border-radius: 8px;
background: linear-gradient(135deg, #f8fbff 0%, #eef5ff 100%);
color: #3a4a66;
font-weight: 500;
}
</style>定制滚动条的样式
可以借助不同的props来定制滚动条的样式,也可以使用css来实现样式修改。
<template>
<div style="height: 300px">
<b-scrollbar
ref="componentScrollBar"
always
noresize
:bar-style="{ background: 'rgba(110, 23, 122, 0.3)' }"
:bar-wrap-style="{ background: 'rgba(0, 0, 0, 0.03)' }"
>
<div class="scrollbar-demo-list">
<div v-for="i in 12" :key="i" class="scrollbar-demo-item">自定义样式滚动块 {{ i }}</div>
</div>
</b-scrollbar>
</div>
</template>
<style scoped>
.scrollbar-demo-list {
padding: 4px;
}
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
margin: 10px 0;
border-radius: 8px;
background: linear-gradient(135deg, #f7efff 0%, #efe4ff 100%);
color: #5c2a86;
font-weight: 500;
}
</style>无限滚动
滚动到边缘时会触发 end-reached 事件,事件参数支持 top / bottom / left / right 四个方向,常用于无限加载。
无限滚动内容 1
无限滚动内容 2
无限滚动内容 3
无限滚动内容 4
无限滚动内容 5
无限滚动内容 6
无限滚动内容 7
无限滚动内容 8
无限滚动内容 9
无限滚动内容 10
无限滚动内容 11
无限滚动内容 12
无限滚动内容 13
无限滚动内容 14
无限滚动内容 15
无限滚动内容 16
无限滚动内容 17
无限滚动内容 18
无限滚动内容 19
无限滚动内容 20
<template>
<b-scrollbar height="320px" :distance="16" @end-reached="loadMore">
<p v-for="item in count" :key="item" class="scrollbar-demo-item">
无限滚动内容 {{ item }}
</p>
</b-scrollbar>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(20)
function loadMore(direction: 'top' | 'bottom' | 'left' | 'right') {
if (direction === 'bottom') {
count.value += 5
}
}
</script>
<style scoped>
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
margin: 10px 0;
border-radius: 6px;
background: #f5f7fa;
color: #606266;
}
</style>注意事项
- b-scrollbar的父层要有固定高度
- b-scrollbar的高度要设成100%
- 如果出现横滚动条,请添加css(.bin-scrollbar__wrap{overflow-x:hidden;})
Props
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| distance | 触发 end-reached 的距离阈值,单位 px | Number | - | 0 |
| height | 滚动区域高度 | String / Number | - | — |
| maxHeight | 滚动区域最大高度 | String / Number | - | — |
| native | 是否采用原生滚动 (隐藏原生滚动条) | Boolean | true | false |
| always | 是否一直显示,而非悬停显示 | Boolean | true | false |
| wrapStyle | 内联方式自定义 wrap 容器样式 | String / Object / Array | - | — |
| wrapClass | 类名方式自定义 wrap 容器样式 | String / Array | - | — |
| viewClass | 类名方式自定义 view 容器样式 | String / Array | - | — |
| viewStyle | 内联方式自定义 view 容器样式 | String / Object / Array | - | — |
| noresize | 如果 container 尺寸不会发生变化,最好设置它可以优化性能 | Boolean | true | false |
| tag | 视图容器元素标签 | String | - | div |
| minSize | 滚动条最小尺寸 | Number | - | 20 |
| tabindex | wrap 容器的 tabindex | String / Number | - | — |
| barStyle | 滚动条 thumb 样式 | Object | - | {} |
| barWrapStyle | 滚动条 bar 容器样式 | Object | - | {} |
Events
| 事件名称 | 说明 | 回调参数 |
|---|---|---|
| scroll | 滚动时触发 | { scrollTop, scrollLeft } |
| end-reached | 滚动触达边界时触发 | direction: 'top' | 'bottom' | 'left' | 'right' |
Methods
| 方法名 | 说明 | 参数 |
|---|---|---|
| handleScroll | 手动触发一次滚动处理 | — |
| scrollTo | 滚动到指定位置 | (options) 或 (x, y) |
| setScrollTop | 设置纵向滚动距离 | (scrollTop: number) |
| setScrollLeft | 设置横向滚动距离 | (scrollLeft: number) |
| update | 手动更新滚动条状态 | — |
| wrapRef | 滚动容器实例引用 | — |