Vue3滚动条(Scrollbar)

效果如下图:

在这里插入图片描述
在这里插入图片描述

在线预览

APIs

Scrollbar

参数说明类型默认值
contentClass内容 div 的类名stringundefined
contentStyle内容 div 的样式CSSProperties{}
size滚动条的大小,单位 pxnumber5
trigger显示滚动条的时机,'none' 表示一直显示‘hover’ | ‘none’‘hover’
autoHide是否自动隐藏滚动条,仅当 trigger: 'hover' 时生效;为 true 时表示鼠标在滚动区域且不滚动时自动隐藏,滚动时自动显示;为 false 时表示鼠标在滚动区域时始终显示,无论是否在滚动booleantrue
delay滚动条自动隐藏的延迟时间,单位 msnumber500
xScrollable是否使用横向滚动booleanfalse
yScrollable是否使用纵向滚动booleantrue
xPlacement横向滚动时滚动条的位置‘top’ | ‘bottom’‘bottom’
yPlacement纵向滚动时滚动条的位置‘left’ | ‘right’‘right’

Slots

名称说明类型
default自定义内容v-slot:default

Methods

名称说明类型
scrollTo滚动到指定坐标位置(options: { left?: number, top?: number, behavior?: ScrollBehavior })=> void | (x: number, y: number) => void
scrollBy滚动一段特定距离(options: { left?: number, top?: number, behavior?: ScrollBehavior })=> void | (x: number, y: number) => void
getScrollData获取滚动元素数据() => { scrollWidth: number, clientWidth: number, scrollHeight: number, clientHeight: number }

ScrollBehavior Type

说明
smooth平滑滚动并产生过渡效果
instant滚动会直接跳转到目标位置,没有过渡效果
auto或缺省值表示浏览器会自动选择滚动时的过渡效果

Events

名称说明类型
scroll滚动的回调(e: Event, direction: ‘left’ | ‘right’ | ‘top’ | ‘bottom’) => void
scrollend滚动结束的回调(e: Event, direction: ‘left’ | ‘right’ | ‘top’ | ‘bottom’) => void

创建滚动条组件Scrollbar.vue

其中引入使用了以下工具函数:

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import type { CSSProperties } from 'vue'
import { debounce, useResizeObserver, useScroll } from 'components/utils'
export interface Props {
  contentClass?: string // 内容 div 的类名
  contentStyle?: CSSProperties // 内容 div 的样式
  size?: number // 滚动条的大小,单位 px
  trigger?: 'hover' | 'none' // 显示滚动条的时机,'none' 表示一直显示
  autoHide?: boolean // 是否自动隐藏滚动条,仅当 trigger: 'hover' 时生效;为 true 时表示鼠标在滚动区域且不滚动时自动隐藏,滚动时自动显示;为 false 时表示鼠标在滚动区域时始终显示,无论是否在滚动
  delay?: number // 滚动条自动隐藏的延迟时间,单位 ms
  xScrollable?: boolean // 是否使用横向滚动
  yScrollable?: boolean // 是否使用纵向滚动
  xPlacement?: 'top' | 'bottom' // 横向滚动时滚动条的位置
  yPlacement?: 'left' | 'right' // 纵向滚动时滚动条的位置
}
const props = withDefaults(defineProps<Props>(), {
  contentClass: undefined,
  contentStyle: () => ({}),
  size: 5,
  trigger: 'hover',
  autoHide: true,
  delay: 500,
  xScrollable: false,
  yScrollable: true,
  xPlacement: 'bottom',
  yPlacement: 'right'
})
const containerRef = ref() // 滚动容器 DOM 引用
const contentRef = ref() // 滚动内容 DOM 引用
const railVerticalRef = ref() // 垂直滚动条 DOM 引用
const railHorizontalRef = ref() // 水平滚动条 DOM 引用
const showYTrack = ref(false) // 是否显示垂直滚动条
const showXTrack = ref(false) // 是否显示横向滚动条
const containerScrollHeight = ref(0) // 滚动区域高度,包括溢出高度
const containerScrollWidth = ref(0) // 滚动区域宽度,包括溢出宽度
const containerClientHeight = ref(0) // 滚动区域高度,不包括溢出高度
const containerClientWidth = ref(0) // 滚动区域宽度,不包括溢出宽度
const containerHeight = ref(0) // 容器高度
const containerWidth = ref(0) // 容器宽度
const contentHeight = ref(0) // 内容高度
const contentWidth = ref(0) // 内容宽度
const railHeight = ref(0) // 滚动条高度
const railWidth = ref(0) // 滚动条宽度
const containerScrollTop = ref(0) // 垂直滚动距离
const containerScrollLeft = ref(0) // 水平滚动距离
const mouseEnter = ref(false) // 鼠标是否在滚动区域内
const trackYPressed = ref(false) // 垂直滚动条是否被按下
const trackXPressed = ref(false) // 水平滚动条是否被按下
const mousePressedLeave = ref(false) // 鼠标在按下滚动条并拖动时是否离开滚动区域
const memoYTop = ref<number>(0) // 鼠标选中并按下垂直滚动条时已滚动的垂直距离
const memoXLeft = ref<number>(0) // 鼠标选中并按下水平滚动条时已滚动的水平距离
const memoMouseY = ref<number>(0) // 鼠标选中并按下垂直滚动条时的鼠标 Y 坐标
const memoMouseX = ref<number>(0) // 鼠标选中并按下水平滚动条时的鼠标 X 坐标
const horizontalContentStyle = { width: 'fit-content' } // 水平滚动时内容区域默认样式
const yTrackHover = ref(false) // 鼠标是否在垂直滚动条上
const xTrackHover = ref(false) // 鼠标是否在水平滚动条上
const emits = defineEmits(['scroll', 'scrollend'])
const autoShowTrack = computed(() => {
  return props.trigger === 'hover' && props.autoHide
})
const notAutoShowTrack = computed(() => {
  return props.trigger === 'hover' && !props.autoHide
})
const isYScroll = computed(() => {
  // 是否存在垂直滚动
  return containerScrollHeight.value > containerClientHeight.value
})
const isXScroll = computed(() => {
  // 是否存在水平滚动
  return containerScrollWidth.value > containerClientWidth.value
})
const isScroll = computed(() => {
  // 是否存在滚动,水平或垂直
  if (containerScrollHeight.value || containerScrollWidth.value) {
    return (props.yScrollable && isYScroll.value) || (props.xScrollable && isXScroll.value)
  }
  return true
})
const trackHeight = computed(() => {
  // 垂直滚动条高度
  if (props.yScrollable && isYScroll.value) {
    if (containerHeight.value && contentHeight.value && railHeight.value) {
      const value = Math.min(
        containerHeight.value,
        (railHeight.value * containerHeight.value) / contentHeight.value + 1.5 * props.size
      )
      return Number(value.toFixed(4))
    }
  }
  return 0
})
const trackTop = computed(() => {
  // 滚动条垂直偏移
  if (containerHeight.value && contentHeight.value && railHeight.value) {
    return (
      (containerScrollTop.value / (contentHeight.value - containerHeight.value)) *
      (railHeight.value - trackHeight.value)
    )
  }
  return 0
})
const verticalTrackStyle = computed(() => {
  // 垂直滚动条样式
  return {
    top: `${trackTop.value}px`,
    height: `${trackHeight.value}px`
  }
})
const trackWidth = computed(() => {
  // 横向滚动条宽度
  if (props.xScrollable && isXScroll.value) {
    if (containerWidth.value && contentWidth.value && railWidth.value) {
      const value = (railWidth.value * containerWidth.value) / contentWidth.value + 1.5 * props.size
      return Number(value.toFixed(4))
    }
  }
  return 0
})
const trackLeft = computed(() => {
  // 滚动条水平偏移
  if (containerWidth.value && contentWidth.value && railWidth.value) {
    return (
      (containerScrollLeft.value / (contentWidth.value - containerWidth.value)) * (railWidth.value - trackWidth.value)
    )
  }
  return 0
})
const horizontalTrackStyle = computed(() => {
  // 水平滚动条样式
  return {
    left: `${trackLeft.value}px`,
    width: `${trackWidth.value}px`
  }
})
onMounted(() => {
  updateState()
})
const {
  left: scrollingLeft,
  right: scrollingRight,
  top: scrollingTop,
  bottom: scrollingBottom
} = useScroll(containerRef)
useResizeObserver([containerRef, contentRef], updateState)
function updateScrollState(): void {
  containerScrollTop.value = containerRef.value.scrollTop
  containerScrollLeft.value = containerRef.value.scrollLeft
}
function updateScrollbarState(): void {
  containerScrollHeight.value = containerRef.value.scrollHeight
  containerScrollWidth.value = containerRef.value.scrollWidth
  containerClientHeight.value = containerRef.value.clientHeight
  containerClientWidth.value = containerRef.value.clientWidth
  containerHeight.value = containerRef.value.offsetHeight
  containerWidth.value = containerRef.value.offsetWidth
  contentHeight.value = contentRef.value.offsetHeight
  contentWidth.value = contentRef.value.offsetWidth
  railHeight.value = railVerticalRef.value.offsetHeight
  railWidth.value = railHorizontalRef.value.offsetWidth
}
function updateState(): void {
  updateScrollState()
  updateScrollbarState()
}
const debounceYScrollEnd = debounce(yScrollEnd, 100)
const debounceXScrollEnd = debounce(xScrollEnd, 100)
const debounceHideYScrollbar = debounce(hideYScrollbar, 100 + props.delay)
const debounceHideXScrollbar = debounce(hideXScrollbar, 100 + props.delay)
function yScrollEnd(e: Event, direction: 'left' | 'right' | 'top' | 'bottom'): void {
  emits('scrollend', e, direction)
}
function xScrollEnd(e: Event, direction: 'left' | 'right' | 'top' | 'bottom'): void {
  emits('scrollend', e, direction)
}
function hideYScrollbar(): void {
  if (autoShowTrack.value && !yTrackHover.value) {
    showYTrack.value = false
  }
  if (notAutoShowTrack.value && !mouseEnter.value) {
    showYTrack.value = false
  }
}
function hideXScrollbar(): void {
  if (autoShowTrack.value && !xTrackHover.value) {
    showXTrack.value = false
  }
  if (notAutoShowTrack.value && !mouseEnter.value) {
    showXTrack.value = false
  }
}
function onScroll(e: Event): void {
  if (scrollingLeft.value || scrollingRight.value) {
    let direction: string = ''
    if (scrollingLeft.value) {
      direction = 'left'
    }
    if (scrollingRight.value) {
      direction = 'right'
    }
    emits('scroll', e, direction)
    if (autoShowTrack.value) {
      showXTrack.value = true
      if (!trackXPressed.value) {
        debounceXScrollEnd(e, direction)
        debounceHideXScrollbar()
      }
    }
  }
  if (scrollingTop.value || scrollingBottom.value) {
    let direction: string = ''
    if (scrollingTop.value) {
      direction = 'top'
    }
    if (scrollingBottom.value) {
      direction = 'bottom'
    }
    emits('scroll', e, direction)
    if (autoShowTrack.value) {
      showYTrack.value = true
      if (!trackYPressed.value) {
        debounceYScrollEnd(e, direction)
        debounceHideYScrollbar()
      }
    }
  }
  updateScrollState()
}
function onMouseEnter(): void {
  mouseEnter.value = true
  if (trackXPressed.value || trackYPressed.value) {
    mousePressedLeave.value = false
  } else {
    if (!autoShowTrack.value) {
      showXTrack.value = true
      showYTrack.value = true
    }
  }
}
function onMouseLeave(): void {
  mouseEnter.value = false
  if (trackXPressed.value || trackYPressed.value) {
    mousePressedLeave.value = true
  } else {
    if (!autoShowTrack.value) {
      if (showXTrack.value) {
        debounceHideXScrollbar()
      }
      if (showYTrack.value) {
        debounceHideYScrollbar()
      }
    }
  }
}
function onEnterYTrack(): void {
  yTrackHover.value = true
}
function onLeaveYTrack(): void {
  yTrackHover.value = false
  if (autoShowTrack.value && !trackYPressed.value) {
    debounceHideYScrollbar()
  }
}
function onEnterXTrack(): void {
  xTrackHover.value = true
}
function onLeaveXTrack(): void {
  xTrackHover.value = false
  if (autoShowTrack.value && !trackXPressed.value) {
    debounceHideXScrollbar()
  }
}
function handleYTrackMouseDown(e: MouseEvent): void {
  trackYPressed.value = true
  memoYTop.value = containerScrollTop.value
  memoMouseY.value = e.clientY
  document.addEventListener('mousemove', handleYTrackMouseMove)
  document.addEventListener('mouseup', handleYTrackMouseUp)
  handleYTrackMouseMove(e)
}
function handleYTrackMouseMove(e: MouseEvent): void {
  const diffY = e.clientY - memoMouseY.value
  const dScrollTop =
    (diffY * (contentHeight.value - containerHeight.value)) / (containerHeight.value - trackHeight.value)
  const toScrollTopUpperBound = contentHeight.value - containerHeight.value
  let toScrollTop = memoYTop.value + dScrollTop
  toScrollTop = Math.min(toScrollTopUpperBound, toScrollTop)
  toScrollTop = Math.max(toScrollTop, 0)
  containerRef.value.scrollTop = toScrollTop
}
function handleYTrackMouseUp(): void {
  trackYPressed.value = false
  if (autoShowTrack.value && !yTrackHover.value) {
    debounceHideYScrollbar()
  } else if (notAutoShowTrack.value && mousePressedLeave.value) {
    mousePressedLeave.value = false
    debounceHideYScrollbar()
  }
  document.removeEventListener('mousemove', handleYTrackMouseMove)
  document.removeEventListener('mouseup', handleYTrackMouseUp)
}
function handleXTrackMouseDown(e: MouseEvent): void {
  trackXPressed.value = true
  memoXLeft.value = containerScrollLeft.value
  memoMouseX.value = e.clientX
  document.addEventListener('mousemove', handleXTrackMouseMove)
  document.addEventListener('mouseup', handleXTrackMouseUp)
  handleXTrackMouseMove(e)
}
function handleXTrackMouseMove(e: MouseEvent): void {
  const diffX = e.clientX - memoMouseX.value
  const dScrollLeft = (diffX * (contentWidth.value - containerWidth.value)) / (containerWidth.value - trackWidth.value)
  const toScrollLeftUpperBound = contentWidth.value - containerWidth.value
  let toScrollLeft = memoXLeft.value + dScrollLeft
  toScrollLeft = Math.min(toScrollLeftUpperBound, toScrollLeft)
  toScrollLeft = Math.max(toScrollLeft, 0)
  containerRef.value.scrollLeft = toScrollLeft
}
function handleXTrackMouseUp(): void {
  trackXPressed.value = false
  if (autoShowTrack.value && !xTrackHover.value) {
    debounceHideXScrollbar()
  } else if (notAutoShowTrack.value && mousePressedLeave.value) {
    mousePressedLeave.value = false
    debounceHideXScrollbar()
  }
  document.removeEventListener('mousemove', handleXTrackMouseMove)
  document.removeEventListener('mouseup', handleXTrackMouseUp)
}
function scrollTo(...args: any[]): void {
  containerRef.value?.scrollTo(...args)
}
function scrollBy(...args: any[]): void {
  containerRef.value?.scrollBy(...args)
}
function getScrollData(): object {
  return {
    scrollTop: containerScrollTop.value,
    scrollWidth: containerScrollWidth.value,
    scrollHeight: containerScrollHeight.value,
    clientWidth: containerClientWidth.value,
    clientHeight: containerClientHeight.value
  }
}
defineExpose({
  scrollTo,
  scrollBy,
  getScrollData
})
</script>
<template>
  <div
    class="m-scrollbar"
    :style="`
      --scrollbar-width: ${size}px;
      --scrollbar-height: ${size}px;
      --scrollbar-border-radius: ${size}px;
      --scrollbar-color: rgba(0, 0, 0, 0.25);
      --scrollbar-color-hover: rgba(0, 0, 0, 0.4);
      --scrollbar-rail-horizontal-top: 4px 2px auto 2px;
      --scrollbar-rail-horizontal-bottom: auto 2px 4px 2px;
      --scrollbar-rail-vertical-right: 2px 4px 2px auto;
      --scrollbar-rail-vertical-left: 2px auto 2px 4px;
      --scrollbar-rail-color: transparent;
    `"
    @mouseenter="isScroll && trigger === 'hover' ? onMouseEnter() : () => false"
    @mouseleave="isScroll && trigger === 'hover' ? onMouseLeave() : () => false"
  >
    <div ref="containerRef" class="scrollbar-container" :class="{ 'container-scroll': isScroll }" @scroll="onScroll">
      <div
        ref="contentRef"
        class="scrollbar-content"
        :class="contentClass"
        :style="[xScrollable ? { ...horizontalContentStyle, ...contentStyle } : contentStyle]"
      >
        <slot></slot>
      </div>
    </div>
    <div
      v-show="yScrollable"
      ref="railVerticalRef"
      class="scrollbar-rail rail-vertical"
      :class="`rail-vertical-${yPlacement}`"
    >
      <div
        class="scrollbar-track"
        :class="{ 'track-visible': trigger === 'none' || showYTrack }"
        :style="verticalTrackStyle"
        @mouseenter="autoShowTrack ? onEnterYTrack() : () => false"
        @mouseleave="autoShowTrack ? onLeaveYTrack() : () => false"
        @mousedown.prevent.stop="handleYTrackMouseDown"
      ></div>
    </div>
    <div
      v-show="xScrollable"
      ref="railHorizontalRef"
      class="scrollbar-rail rail-horizontal"
      :class="`rail-horizontal-${xPlacement}`"
    >
      <div
        class="scrollbar-track"
        :class="{ 'track-visible': trigger === 'none' || showXTrack }"
        :style="horizontalTrackStyle"
        @mouseenter="autoShowTrack ? onEnterXTrack() : () => false"
        @mouseleave="autoShowTrack ? onLeaveXTrack() : () => false"
        @mousedown.prevent.stop="handleXTrackMouseDown"
      ></div>
    </div>
  </div>
</template>
<style lang="less" scoped>
.m-scrollbar {
  overflow: hidden;
  position: relative;
  z-index: auto;
  height: 100%;
  width: 100%;
  .scrollbar-container {
    width: 100%;
    height: 100%;
    min-height: inherit;
    max-height: inherit;
    scrollbar-width: none;
    &::-webkit-scrollbar,
    &::-webkit-scrollbar-track-piece,
    &::-webkit-scrollbar-thumb {
      width: 0;
      height: 0;
      display: none;
    }
    .scrollbar-content {
      box-sizing: border-box;
      min-width: 100%;
    }
  }
  .container-scroll {
    overflow: scroll;
  }
  .scrollbar-rail {
    position: absolute;
    pointer-events: none;
    user-select: none;
    background: var(--scrollbar-rail-color);
    -webkit-user-select: none;
    .scrollbar-track {
      z-index: 9;
      position: absolute;
      cursor: pointer;
      opacity: 0;
      pointer-events: none;
      background-color: var(--scrollbar-color);
      transition:
        background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
        opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      &:hover {
        background-color: var(--scrollbar-color-hover);
      }
    }
    .track-visible {
      opacity: 1;
      pointer-events: all;
    }
  }
  .rail-vertical {
    width: var(--scrollbar-width);
    .scrollbar-track {
      width: var(--scrollbar-width);
      border-radius: var(--scrollbar-border-radius);
      bottom: 0;
    }
  }
  .rail-vertical-left {
    inset: var(--scrollbar-rail-vertical-left);
  }
  .rail-vertical-right {
    inset: var(--scrollbar-rail-vertical-right);
  }
  .rail-horizontal {
    height: var(--scrollbar-height);
    .scrollbar-track {
      height: var(--scrollbar-height);
      border-radius: var(--scrollbar-border-radius);
      right: 0;
    }
  }
  .rail-horizontal-top {
    inset: var(--scrollbar-rail-horizontal-top);
  }
  .rail-horizontal-bottom {
    inset: var(--scrollbar-rail-horizontal-bottom);
  }
  .scrollbar-thumb {
    position: absolute;
    background-color: rgba(0, 0, 0, 0.5);
    transition: background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  }
}
</style>

在要使用的页面引入

其中引入使用了以下组件:

<script setup lang="ts">
import Scrollbar from './Scrollbar.vue'
function onScroll(e: Event, direction: 'left' | 'right' | 'top' | 'bottom') {
  console.log('scroll', e, direction)
}
function onScrollEnd(e: Event, direction: 'left' | 'right' | 'top' | 'bottom') {
  console.log('scrollend', e, direction)
}
</script>
<template>
  <div>
    <h1>{{ $route.name }} {{ $route.meta.title }}</h1>
    <h2 class="mt30 mb10">基本使用</h2>
    <Scrollbar style="max-height: 120px" @scroll="onScroll" @scrollend="onScrollEnd">
      我们在田野上面找猪<br />
      想象中已找到了三只<br />
      小鸟在白云上面追逐<br />
      它们在树底下跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      想象中我们是如此的疯狂<br />
      我们在城市里面找猪<br />
      想象中已找到了几百万只<br />
      小鸟在公园里面唱歌<br />
      它们独自在想象里跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      许多年之后我们又开始想象<br />
      啦啦啦啦啦啦啦啦咧
    </Scrollbar>
    <h2 class="mt30 mb10">横向滚动</h2>
    <Scrollbar x-scrollable @scroll="onScroll" @scrollend="onScrollEnd">
      <div style="white-space: nowrap; padding: 12px">
        我们在田野上面找猪 想象中已找到了三只 小鸟在白云上面追逐 它们在树底下跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧
        我们在想象中度过了许多年 想象中我们是如此的疯狂 我们在城市里面找猪 想象中已找到了几百万只 小鸟在公园里面唱歌
        它们独自在想象里跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧 我们在想象中度过了许多年 许多年之后我们又开始想象
        啦啦啦啦啦啦啦啦咧
      </div>
    </Scrollbar>
    <h2 class="mt30 mb10">垂直及横向滚动</h2>
    <Scrollbar style="max-height: 120px" x-scrollable @scroll="onScroll" @scrollend="onScrollEnd">
      <div style="white-space: nowrap; padding-right: 12px" v-for="n in 9" :key="n">
        我们在田野上面找猪 想象中已找到了三只 小鸟在白云上面追逐 它们在树底下跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧
        我们在想象中度过了许多年 想象中我们是如此的疯狂 我们在城市里面找猪 想象中已找到了几百万只 小鸟在公园里面唱歌
        它们独自在想象里跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧 我们在想象中度过了许多年 许多年之后我们又开始想象
        啦啦啦啦啦啦啦啦咧
      </div>
      <div style="white-space: nowrap; padding-bottom: 12px">
        我们在田野上面找猪 想象中已找到了三只 小鸟在白云上面追逐 它们在树底下跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧
        我们在想象中度过了许多年 想象中我们是如此的疯狂 我们在城市里面找猪 想象中已找到了几百万只 小鸟在公园里面唱歌
        它们独自在想象里跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧 我们在想象中度过了许多年 许多年之后我们又开始想象
        啦啦啦啦啦啦啦啦咧
      </div>
    </Scrollbar>
    <h2 class="mt30 mb10">触发方式</h2>
    <Scrollbar style="max-height: 120px" trigger="none">
      我们在田野上面找猪<br />
      想象中已找到了三只<br />
      小鸟在白云上面追逐<br />
      它们在树底下跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      想象中我们是如此的疯狂<br />
      我们在城市里面找猪<br />
      想象中已找到了几百万只<br />
      小鸟在公园里面唱歌<br />
      它们独自在想象里跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      许多年之后我们又开始想象<br />
      啦啦啦啦啦啦啦啦咧
    </Scrollbar>
    <h2 class="mt30 mb10">鼠标在滚动区域时不自动隐藏</h2>
    <Scrollbar style="max-height: 120px" :auto-hide="false" :delay="1000">
      我们在田野上面找猪<br />
      想象中已找到了三只<br />
      小鸟在白云上面追逐<br />
      它们在树底下跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      想象中我们是如此的疯狂<br />
      我们在城市里面找猪<br />
      想象中已找到了几百万只<br />
      小鸟在公园里面唱歌<br />
      它们独自在想象里跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      许多年之后我们又开始想象<br />
      啦啦啦啦啦啦啦啦咧
    </Scrollbar>
    <h2 class="mt30 mb10">自定义样式</h2>
    <h3 class="mb10">可通过设置 size 属性,自定义相关 --scrollbar 变量进行各种样式自定义</h3>
    <Scrollbar
      style="
        max-height: 120px;
        border-radius: 12px;
        --scrollbar-color: rgba(0, 0, 0, 0.45);
        --scrollbar-color-hover: rgba(0, 0, 0, 0.65);
        --scrollbar-rail-vertical-right: 2px 6px 2px auto;
      "
      :size="8"
      :content-style="{ backgroundColor: '#e6f4ff', padding: '16px 24px', fontSize: '16px' }"
    >
      我们在田野上面找猪<br />
      想象中已找到了三只<br />
      小鸟在白云上面追逐<br />
      它们在树底下跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      想象中我们是如此的疯狂<br />
      我们在城市里面找猪<br />
      想象中已找到了几百万只<br />
      小鸟在公园里面唱歌<br />
      它们独自在想象里跳舞<br />
      啦啦啦啦啦啦啦啦咧<br />
      啦啦啦啦咧<br />
      我们在想象中度过了许多年<br />
      许多年之后我们又开始想象<br />
      啦啦啦啦啦啦啦啦咧
    </Scrollbar>
    <h2 class="mt30 mb10">滚动条位置</h2>
    <Flex vertical>
      <Scrollbar style="max-height: 120px; padding-left: 12px" y-placement="left">
        我们在田野上面找猪<br />
        想象中已找到了三只<br />
        小鸟在白云上面追逐<br />
        它们在树底下跳舞<br />
        啦啦啦啦啦啦啦啦咧<br />
        啦啦啦啦咧<br />
        我们在想象中度过了许多年<br />
        想象中我们是如此的疯狂<br />
        我们在城市里面找猪<br />
        想象中已找到了几百万只<br />
        小鸟在公园里面唱歌<br />
        它们独自在想象里跳舞<br />
        啦啦啦啦啦啦啦啦咧<br />
        啦啦啦啦咧<br />
        我们在想象中度过了许多年<br />
        许多年之后我们又开始想象<br />
        啦啦啦啦啦啦啦啦咧
      </Scrollbar>
      <Scrollbar x-scrollable x-placement="top">
        <div style="white-space: nowrap; padding: 12px">
          我们在田野上面找猪 想象中已找到了三只 小鸟在白云上面追逐 它们在树底下跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧
          我们在想象中度过了许多年 想象中我们是如此的疯狂 我们在城市里面找猪 想象中已找到了几百万只 小鸟在公园里面唱歌
          它们独自在想象里跳舞 啦啦啦啦啦啦啦啦咧 啦啦啦啦咧 我们在想象中度过了许多年 许多年之后我们又开始想象
          啦啦啦啦啦啦啦啦咧
        </div>
      </Scrollbar>
    </Flex>
  </div>
</template>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

theMuseCatcher

您的支持是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值