mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
@@ -39,39 +39,43 @@ scrollbar/manual-scroll
|
||||
|
||||
:::
|
||||
|
||||
## Scrollbar Attributes
|
||||
## API
|
||||
|
||||
| Name | Description | Type | Accepted Values | Default |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------- | --------------- | --------------- | ------- |
|
||||
| height | height of scrollbar | string / number | — | — |
|
||||
| max-height | max height of scrollbar | string / number | — | — |
|
||||
| native | whether to use the native scrollbar style | boolean | — | false |
|
||||
| wrap-style | style of warp container | string | — | — |
|
||||
| wrap-class | class of warp container | string | — | — |
|
||||
| view-style | style of view | string | — | — |
|
||||
| view-class | class of view | string | — | — |
|
||||
| noresize | do not respond to container size changes, if the container size does not change, it is better to set it to optimize performance | boolean | — | false |
|
||||
| tag | element tag of the view | string | — | div |
|
||||
| always | always show scrollbar | boolean | — | false |
|
||||
| min-size | minimum size of scrollbar | number | — | 20 |
|
||||
### Attributes
|
||||
|
||||
## Scrollbar Events
|
||||
| Name | Description | Type | Default |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | ------- |
|
||||
| height | height of scrollbar | ^[string] \| ^[number] | — |
|
||||
| max-height | max height of scrollbar | ^[string] \| ^[number] | — |
|
||||
| native | whether to use the native scrollbar style | ^[boolean] | false |
|
||||
| wrap-style | style of wrap container | ^[string] \| ^[object]`CSSProperties \| CSSProperties[] \| string[]` | — |
|
||||
| wrap-class | class of wrap container | ^[string] | — |
|
||||
| view-style | style of view | ^[string] \| ^[object]`CSSProperties \| CSSProperties[] \| string[]` | — |
|
||||
| view-class | class of view | ^[string] | — |
|
||||
| noresize | do not respond to container size changes, if the container size does not change, it is better to set it to optimize performance | ^[boolean] | false |
|
||||
| tag | element tag of the view | ^[string] | div |
|
||||
| always | always show scrollbar | ^[boolean] | false |
|
||||
| min-size | minimum size of scrollbar | ^[number] | 20 |
|
||||
|
||||
| Name | Description | Parameters |
|
||||
| ------ | ----------------------- | ------------------------------------------------- |
|
||||
| scroll | triggers when scrolling | distance of scrolling `{ scrollLeft, scrollTop }` |
|
||||
### Events
|
||||
|
||||
## Scrollbar Methods
|
||||
| Name | Description | Type |
|
||||
| ------ | ----------------------------------------------------- | ---------------------------------------------------------------- |
|
||||
| scroll | triggers when scrolling, return distance of scrolling | ^[Function]`({ scrollLeft: number, scrollTop: number }) => void` |
|
||||
|
||||
| Method | Description | Parameters |
|
||||
| ------------- | ------------------------------------------ | ----------------------------------------------------- |
|
||||
| scrollTo | scrolls to a particular set of coordinates | (options: ScrollToOptions \| number, yCoord?: number) |
|
||||
| setScrollTop | Set distance to scroll top | (scrollTop: number) |
|
||||
| setScrollLeft | Set distance to scroll left | (scrollLeft: number) |
|
||||
| update | update scrollbar state manually | — |
|
||||
### Slots
|
||||
|
||||
## Scrollbar Slots
|
||||
| Name | Description |
|
||||
| ------- | ------------------------- |
|
||||
| default | customize default content |
|
||||
|
||||
| Name | Description |
|
||||
| ---- | ------------------------- |
|
||||
| — | customize default content |
|
||||
### Exposes
|
||||
|
||||
| Method | Description | Type |
|
||||
| ------------- | ------------------------------------------ | -------------------------------------------------------------------------- |
|
||||
| handleScroll | handle scroll event | ^[Function]`() => void` |
|
||||
| scrollTo | scrolls to a particular set of coordinates | ^[Function]`(options: ScrollToOptions \| number, yCoord?: number) => void` |
|
||||
| setScrollTop | Set distance to scroll top | ^[Function]`(scrollTop: number) => void` |
|
||||
| setScrollLeft | Set distance to scroll left | ^[Function]`(scrollLeft: number) => void` |
|
||||
| update | update scrollbar state manually | ^[Function]`() => void` |
|
||||
| wrapRef | scrollbar wrap ref | ^[Object]`Ref<HTMLDivElement>` |
|
||||
|
||||
@@ -3,37 +3,73 @@ import type { ExtractPropTypes, StyleValue } from 'vue'
|
||||
import type Scrollbar from './scrollbar.vue'
|
||||
|
||||
export const scrollbarProps = buildProps({
|
||||
/**
|
||||
* @description height of scrollbar
|
||||
*/
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description max height of scrollbar
|
||||
*/
|
||||
maxHeight: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
native: Boolean,
|
||||
/**
|
||||
* @description whether to use the native scrollbar
|
||||
*/
|
||||
native: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* @description style of wrap
|
||||
*/
|
||||
wrapStyle: {
|
||||
type: definePropType<StyleValue>([String, Object, Array]),
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description class of wrap
|
||||
*/
|
||||
wrapClass: {
|
||||
type: [String, Array],
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description class of view
|
||||
*/
|
||||
viewClass: {
|
||||
type: [String, Array],
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description style of view
|
||||
*/
|
||||
viewStyle: {
|
||||
type: [String, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description do not respond to container size changes, if the container size does not change, it is better to set it to optimize performance
|
||||
*/
|
||||
noresize: Boolean, // 如果 container 尺寸不会发生变化,最好设置它可以优化性能
|
||||
/**
|
||||
* @description element tag of the view
|
||||
*/
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'div',
|
||||
},
|
||||
/**
|
||||
* @description always show
|
||||
*/
|
||||
always: Boolean,
|
||||
/**
|
||||
* @description minimum size of scrollbar
|
||||
*/
|
||||
minSize: {
|
||||
type: Number,
|
||||
default: 20,
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
<template>
|
||||
<div ref="scrollbar$" :class="ns.b()">
|
||||
<div
|
||||
ref="wrap$"
|
||||
:class="[
|
||||
wrapClass,
|
||||
ns.e('wrap'),
|
||||
{ [ns.em('wrap', 'hidden-default')]: !native },
|
||||
]"
|
||||
:style="style"
|
||||
@scroll="handleScroll"
|
||||
>
|
||||
<div ref="scrollbarRef" :class="ns.b()">
|
||||
<div ref="wrapRef" :class="wrapKls" :style="style" @scroll="handleScroll">
|
||||
<component
|
||||
:is="tag"
|
||||
ref="resize$"
|
||||
:class="[ns.e('view'), viewClass]"
|
||||
ref="resizeRef"
|
||||
:class="resizeKls"
|
||||
:style="viewStyle"
|
||||
>
|
||||
<slot />
|
||||
@@ -52,8 +43,10 @@ import { scrollbarEmits, scrollbarProps } from './scrollbar'
|
||||
import type { BarInstance } from './bar'
|
||||
import type { CSSProperties, StyleValue } from 'vue'
|
||||
|
||||
const COMPONENT_NAME = 'ElScrollbar'
|
||||
|
||||
defineOptions({
|
||||
name: 'ElScrollbar',
|
||||
name: COMPONENT_NAME,
|
||||
})
|
||||
|
||||
const props = defineProps(scrollbarProps)
|
||||
@@ -64,16 +57,15 @@ const ns = useNamespace('scrollbar')
|
||||
let stopResizeObserver: (() => void) | undefined = undefined
|
||||
let stopResizeListener: (() => void) | undefined = undefined
|
||||
|
||||
const scrollbar$ = ref<HTMLDivElement>()
|
||||
const wrap$ = ref<HTMLDivElement>()
|
||||
const resize$ = ref<HTMLElement>()
|
||||
const scrollbarRef = ref<HTMLDivElement>()
|
||||
const wrapRef = ref<HTMLDivElement>()
|
||||
const resizeRef = ref<HTMLElement>()
|
||||
|
||||
const sizeWidth = ref('0')
|
||||
const sizeHeight = ref('0')
|
||||
const barRef = ref<BarInstance>()
|
||||
const ratioY = ref(1)
|
||||
const ratioX = ref(1)
|
||||
const SCOPE = 'ElScrollbar'
|
||||
|
||||
const style = computed<StyleValue>(() => {
|
||||
const style: CSSProperties = {}
|
||||
@@ -82,13 +74,25 @@ const style = computed<StyleValue>(() => {
|
||||
return [props.wrapStyle, style]
|
||||
})
|
||||
|
||||
const wrapKls = computed(() => {
|
||||
return [
|
||||
props.wrapClass,
|
||||
ns.e('wrap'),
|
||||
{ [ns.em('wrap', 'hidden-default')]: !props.native },
|
||||
]
|
||||
})
|
||||
|
||||
const resizeKls = computed(() => {
|
||||
return [ns.e('view'), props.viewClass]
|
||||
})
|
||||
|
||||
const handleScroll = () => {
|
||||
if (wrap$.value) {
|
||||
barRef.value?.handleScroll(wrap$.value)
|
||||
if (wrapRef.value) {
|
||||
barRef.value?.handleScroll(wrapRef.value)
|
||||
|
||||
emit('scroll', {
|
||||
scrollTop: wrap$.value.scrollTop,
|
||||
scrollLeft: wrap$.value.scrollLeft,
|
||||
scrollTop: wrapRef.value.scrollTop,
|
||||
scrollLeft: wrapRef.value.scrollLeft,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -99,35 +103,35 @@ function scrollTo(xCord: number, yCord?: number): void
|
||||
function scrollTo(options: ScrollToOptions): void
|
||||
function scrollTo(arg1: unknown, arg2?: number) {
|
||||
if (isObject(arg1)) {
|
||||
wrap$.value!.scrollTo(arg1)
|
||||
wrapRef.value!.scrollTo(arg1)
|
||||
} else if (isNumber(arg1) && isNumber(arg2)) {
|
||||
wrap$.value!.scrollTo(arg1, arg2)
|
||||
wrapRef.value!.scrollTo(arg1, arg2)
|
||||
}
|
||||
}
|
||||
|
||||
const setScrollTop = (value: number) => {
|
||||
if (!isNumber(value)) {
|
||||
debugWarn(SCOPE, 'value must be a number')
|
||||
debugWarn(COMPONENT_NAME, 'value must be a number')
|
||||
return
|
||||
}
|
||||
wrap$.value!.scrollTop = value
|
||||
wrapRef.value!.scrollTop = value
|
||||
}
|
||||
|
||||
const setScrollLeft = (value: number) => {
|
||||
if (!isNumber(value)) {
|
||||
debugWarn(SCOPE, 'value must be a number')
|
||||
debugWarn(COMPONENT_NAME, 'value must be a number')
|
||||
return
|
||||
}
|
||||
wrap$.value!.scrollLeft = value
|
||||
wrapRef.value!.scrollLeft = value
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
if (!wrap$.value) return
|
||||
const offsetHeight = wrap$.value.offsetHeight - GAP
|
||||
const offsetWidth = wrap$.value.offsetWidth - GAP
|
||||
if (!wrapRef.value) return
|
||||
const offsetHeight = wrapRef.value.offsetHeight - GAP
|
||||
const offsetWidth = wrapRef.value.offsetWidth - GAP
|
||||
|
||||
const originalHeight = offsetHeight ** 2 / wrap$.value.scrollHeight
|
||||
const originalWidth = offsetWidth ** 2 / wrap$.value.scrollWidth
|
||||
const originalHeight = offsetHeight ** 2 / wrapRef.value.scrollHeight
|
||||
const originalWidth = offsetWidth ** 2 / wrapRef.value.scrollWidth
|
||||
const height = Math.max(originalHeight, props.minSize)
|
||||
const width = Math.max(originalWidth, props.minSize)
|
||||
|
||||
@@ -151,7 +155,7 @@ watch(
|
||||
stopResizeObserver?.()
|
||||
stopResizeListener?.()
|
||||
} else {
|
||||
;({ stop: stopResizeObserver } = useResizeObserver(resize$, update))
|
||||
;({ stop: stopResizeObserver } = useResizeObserver(resizeRef, update))
|
||||
stopResizeListener = useEventListener('resize', update)
|
||||
}
|
||||
},
|
||||
@@ -164,8 +168,8 @@ watch(
|
||||
if (!props.native)
|
||||
nextTick(() => {
|
||||
update()
|
||||
if (wrap$.value) {
|
||||
barRef.value?.handleScroll(wrap$.value)
|
||||
if (wrapRef.value) {
|
||||
barRef.value?.handleScroll(wrapRef.value)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -174,8 +178,8 @@ watch(
|
||||
provide(
|
||||
scrollbarContextKey,
|
||||
reactive({
|
||||
scrollbarElement: scrollbar$,
|
||||
wrapElement: wrap$,
|
||||
scrollbarElement: scrollbarRef,
|
||||
wrapElement: wrapRef,
|
||||
})
|
||||
)
|
||||
|
||||
@@ -189,7 +193,7 @@ onUpdated(() => update())
|
||||
|
||||
defineExpose({
|
||||
/** @description scrollbar wrap ref */
|
||||
wrap$,
|
||||
wrapRef,
|
||||
/** @description update scrollbar state manually */
|
||||
update,
|
||||
/** @description scrolls to a particular set of coordinates */
|
||||
|
||||
@@ -71,7 +71,7 @@ class TableLayout<T> {
|
||||
let scrollY = true
|
||||
const prevScrollY = this.scrollY.value
|
||||
scrollY =
|
||||
scrollBarRef.wrap$.scrollHeight > scrollBarRef.wrap$.clientHeight
|
||||
scrollBarRef.wrapRef.scrollHeight > scrollBarRef.wrapRef.clientHeight
|
||||
this.scrollY.value = scrollY
|
||||
return prevScrollY !== scrollY
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ function useStyle<T>(
|
||||
}
|
||||
return
|
||||
}
|
||||
const scrollContainer = table.refs.scrollBarRef.wrap$
|
||||
const scrollContainer = table.refs.scrollBarRef.wrapRef
|
||||
if (!scrollContainer) return
|
||||
const { scrollLeft, offsetWidth, scrollWidth } = scrollContainer
|
||||
const { headerWrapper, footerWrapper } = table.refs
|
||||
@@ -190,10 +190,15 @@ function useStyle<T>(
|
||||
|
||||
const bindEvents = () => {
|
||||
if (!table.refs.scrollBarRef) return
|
||||
if (table.refs.scrollBarRef.wrap$) {
|
||||
useEventListener(table.refs.scrollBarRef.wrap$, 'scroll', syncPosition, {
|
||||
passive: true,
|
||||
})
|
||||
if (table.refs.scrollBarRef.wrapRef) {
|
||||
useEventListener(
|
||||
table.refs.scrollBarRef.wrapRef,
|
||||
'scroll',
|
||||
syncPosition,
|
||||
{
|
||||
passive: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
if (props.fit) {
|
||||
useResizeObserver(table.vnode.el as HTMLElement, resizeListener)
|
||||
|
||||
Reference in New Issue
Block a user