feat(scrollbar): add always show props and control scrollbar methods (#2428)

* feat(scrollbar): add always show props and control scrollbar methods

re #1751 #2004

* feat: update for review
This commit is contained in:
kooriookami 2021-07-05 09:10:50 +08:00 committed by GitHub
parent 36f2d0964b
commit e61d08ed29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 355 additions and 10 deletions

View File

@ -1,3 +1,4 @@
import { nextTick } from 'vue'
import { mount } from '@vue/test-utils'
import { defineGetter, makeScroll } from '@element-plus/test-utils'
import Scrollbar from '../src/index.vue'
@ -110,4 +111,49 @@ describe('ScrollBar', () => {
expect(wrapper.find('.el-scrollbar__wrap').attributes('style')).toContain('max-height: 200px;')
})
test('should render always props', async () => {
const outerHeight = 200
const innerHeight = 500
const wrapper = _mount(`
<el-scrollbar height="${outerHeight}px" always>
<div style="height: ${innerHeight}px;"></div>
</el-scrollbar>
`)
expect(wrapper.find('.el-scrollbar__bar').attributes('style')).toBeFalsy()
})
test('set scrollTop & scrollLeft', async () => {
const outerHeight = 200
const innerHeight = 500
const outerWidth = 200
const innerWidth = 500
const wrapper = _mount(`
<el-scrollbar ref="scrollbar" style="height: ${outerHeight}px; width: ${outerWidth}px;">
<div style="height: ${innerHeight}px; width: ${innerWidth}px;"></div>
</el-scrollbar>
`)
const scrollbar = wrapper.vm.$refs.scrollbar as any
const scrollDom = wrapper.find('.el-scrollbar__wrap').element
const clientHeightRestore = defineGetter(scrollDom, 'clientHeight', outerHeight)
const scrollHeightRestore = defineGetter(scrollDom, 'scrollHeight', innerHeight)
const clientWidthRestore = defineGetter(scrollDom, 'clientWidth', outerWidth)
const scrollWidthRestore = defineGetter(scrollDom, 'scrollWidth', innerWidth)
scrollbar.setScrollTop(100)
await nextTick()
scrollbar.setScrollLeft(100)
await nextTick()
expect(wrapper.find('.is-vertical div').attributes('style')).toContain('height: 40%; transform: translateY(0%); webkit-transform: translateY(0%);')
expect(wrapper.find('.is-horizontal div').attributes('style')).toContain('width: 40%; transform: translateX(0%); webkit-transform: translateX(0%);')
clientHeightRestore()
scrollHeightRestore()
clientWidthRestore()
scrollWidthRestore()
})
})

View File

@ -1,7 +1,7 @@
<template>
<transition name="el-scrollbar-fade">
<div
v-show="visible"
v-show="always || visible"
ref="instance"
:class="['el-scrollbar__bar', 'is-' + bar.key]"
@mousedown="clickTrackHandler"
@ -27,6 +27,7 @@ export default defineComponent({
vertical: Boolean,
size: String,
move: Number,
always: Boolean,
},
setup(props) {
const instance = ref(null)

View File

@ -20,17 +20,23 @@
</component>
</div>
<template v-if="!native">
<bar :move="moveX" :size="sizeWidth" />
<bar vertical :move="moveY" :size="sizeHeight" />
<bar :move="moveX" :size="sizeWidth" :always="always" />
<bar
:move="moveY"
:size="sizeHeight"
vertical
:always="always"
/>
</template>
</div>
</template>
<script lang="ts">
import { addResizeListener, removeResizeListener } from '@element-plus/utils/resize-event'
import { addUnit, isArray, isString, toObject } from '@element-plus/utils/util'
import { addUnit, isArray, isNumber, isString, toObject } from '@element-plus/utils/util'
import { computed, defineComponent, nextTick, onBeforeUnmount, onMounted, provide, ref } from 'vue'
import Bar from './bar.vue'
import type { CSSProperties, PropType } from 'vue'
import { warn } from '@element-plus/utils/error'
export default defineComponent({
name: 'ElScrollbar',
@ -69,6 +75,10 @@ export default defineComponent({
type: String,
default: 'div',
},
always: {
type: Boolean,
default: false,
},
},
emits: ['scroll'],
setup(props, { emit }) {
@ -80,6 +90,8 @@ export default defineComponent({
const wrap = ref(null)
const resize = ref(null)
const SCOPE = 'ElScrollbar'
provide('scrollbar', scrollbar)
provide('scrollbar-wrap', wrap)
@ -94,6 +106,26 @@ export default defineComponent({
}
}
const setScrollTop = (value: string) => {
if (!isNumber(value)) {
if (process.env.NODE_ENV !== 'production') {
warn(SCOPE, 'value must be a number')
}
return
}
wrap.value.scrollTop = value
}
const setScrollLeft = (value: string) => {
if (!isNumber(value)) {
if (process.env.NODE_ENV !== 'production') {
warn(SCOPE, 'value must be a number')
}
return
}
wrap.value.scrollLeft = value
}
const update = () => {
if (!wrap.value) return
@ -145,6 +177,8 @@ export default defineComponent({
resize,
update,
handleScroll,
setScrollTop,
setScrollLeft,
}
},
})

View File

@ -29,7 +29,11 @@
}
}
.el-button{
.el-button {
margin-bottom: 20px;
}
.el-slider {
margin-top: 20px;
}
}

View File

@ -7,6 +7,7 @@ Used to replace the browser's native scrollbar.
:::demo Use `height` property to set the height of the scrollbar, or if not set, it adapts according to the parent container height.
```html
<el-scrollbar height="400px">
<p class="item" v-for="item in 20">{{ item }}</p>
</el-scrollbar>
@ -19,6 +20,7 @@ Used to replace the browser's native scrollbar.
:::demo When the element width is greater than the scrollbar width, the horizontal scrollbar is displayed.
```html
<el-scrollbar>
<div class="flex-content">
<p class="item" v-for="item in 50">{{ item }}</p>
@ -33,6 +35,7 @@ Used to replace the browser's native scrollbar.
:::demo The scrollbar is displayed only when the element height exceeds the max height.
```html
<template>
<el-button @click="add">Add Item</el-button>
<el-button @click="delete">Delete Item</el-button>
@ -64,6 +67,47 @@ Used to replace the browser's native scrollbar.
:::
### Manual scroll
:::demo Use `setScrollTop` and `setScrollLeft` methods can control scrollbar manually.
```html
<template>
<el-scrollbar ref="scrollbar" height="400px" always>
<div ref="inner">
<p class="item" v-for="item in 20">{{ item }}</p>
</div>
</el-scrollbar>
<el-slider v-model="value" @input="inputSlider" :max="max" :format-tooltip="formatTooltip"></el-slider>
</template>
<script>
export default {
data() {
return {
max: 0,
value: 0
}
},
mounted() {
this.max = this.$refs.inner.clientHeight - 380
},
methods: {
inputSlider(value) {
this.$refs.scrollbar.setScrollTop(value)
},
formatTooltip(value) {
return `${value} px`
}
}
}
</script>
```
:::
### Scrollbar Attributes
| Attribute | Description | Type | Accepted Values | Default |
@ -77,9 +121,17 @@ Used to replace the browser's native scrollbar.
| 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 |
### Events
### Scrollbar Events
| Event Name | Description | Parameters |
|---------- |-------- |---------- |
| scroll | triggers when scrolling | distance of scrolling { scrollLeft, scrollTop }|
### Scrollbar Methods
| Method | Description | Parameters |
| ---- | ---- | ---- |
| setScrollTop | Set distance to scroll top | (scrollTop: number)
| setScrollLeft | Set distance to scroll left | (scrollLeft: number)

View File

@ -7,6 +7,7 @@ Used to replace the browser's native scrollbar.
:::demo Use `height` property to set the height of the scrollbar, or if not set, it adapts according to the parent container height.
```html
<el-scrollbar height="400px">
<p class="item" v-for="item in 20">{{ item }}</p>
</el-scrollbar>
@ -19,6 +20,7 @@ Used to replace the browser's native scrollbar.
:::demo When the element width is greater than the scrollbar width, the horizontal scrollbar is displayed.
```html
<el-scrollbar>
<div class="flex-content">
<p class="item" v-for="item in 50">{{ item }}</p>
@ -33,6 +35,7 @@ Used to replace the browser's native scrollbar.
:::demo The scrollbar is displayed only when the element height exceeds the max height.
```html
<template>
<el-button @click="add">Add Item</el-button>
<el-button @click="delete">Delete Item</el-button>
@ -64,6 +67,47 @@ Used to replace the browser's native scrollbar.
:::
### Manual scroll
:::demo Use `setScrollTop` and `setScrollLeft` methods can control scrollbar manually.
```html
<template>
<el-scrollbar ref="scrollbar" height="400px" always>
<div ref="inner">
<p class="item" v-for="item in 20">{{ item }}</p>
</div>
</el-scrollbar>
<el-slider v-model="value" @input="inputSlider" :max="max" :format-tooltip="formatTooltip"></el-slider>
</template>
<script>
export default {
data() {
return {
max: 0,
value: 0
}
},
mounted() {
this.max = this.$refs.inner.clientHeight - 380
},
methods: {
inputSlider(value) {
this.$refs.scrollbar.setScrollTop(value)
},
formatTooltip(value) {
return `${value} px`
}
}
}
</script>
```
:::
### Scrollbar Attributes
| Attribute | Description | Type | Accepted Values | Default |
@ -77,9 +121,17 @@ Used to replace the browser's native scrollbar.
| 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 |
### Events
### Scrollbar Events
| Event Name | Description | Parameters |
|---------- |-------- |---------- |
| scroll | triggers when scrolling | distance of scrolling { scrollLeft, scrollTop }|
### Scrollbar Methods
| Method | Description | Parameters |
| ---- | ---- | ---- |
| setScrollTop | Set distance to scroll top | (scrollTop: number)
| setScrollLeft | Set distance to scroll left | (scrollLeft: number)

View File

@ -7,6 +7,7 @@ Used to replace the browser's native scrollbar.
:::demo Use `height` property to set the height of the scrollbar, or if not set, it adapts according to the parent container height.
```html
<el-scrollbar height="400px">
<p class="item" v-for="item in 20">{{ item }}</p>
</el-scrollbar>
@ -19,6 +20,7 @@ Used to replace the browser's native scrollbar.
:::demo When the element width is greater than the scrollbar width, the horizontal scrollbar is displayed.
```html
<el-scrollbar>
<div class="flex-content">
<p class="item" v-for="item in 50">{{ item }}</p>
@ -33,6 +35,7 @@ Used to replace the browser's native scrollbar.
:::demo The scrollbar is displayed only when the element height exceeds the max height.
```html
<template>
<el-button @click="add">Add Item</el-button>
<el-button @click="delete">Delete Item</el-button>
@ -64,6 +67,47 @@ Used to replace the browser's native scrollbar.
:::
### Manual scroll
:::demo Use `setScrollTop` and `setScrollLeft` methods can control scrollbar manually.
```html
<template>
<el-scrollbar ref="scrollbar" height="400px" always>
<div ref="inner">
<p class="item" v-for="item in 20">{{ item }}</p>
</div>
</el-scrollbar>
<el-slider v-model="value" @input="inputSlider" :max="max" :format-tooltip="formatTooltip"></el-slider>
</template>
<script>
export default {
data() {
return {
max: 0,
value: 0
}
},
mounted() {
this.max = this.$refs.inner.clientHeight - 380
},
methods: {
inputSlider(value) {
this.$refs.scrollbar.setScrollTop(value)
},
formatTooltip(value) {
return `${value} px`
}
}
}
</script>
```
:::
### Scrollbar Attributes
| Attribute | Description | Type | Accepted Values | Default |
@ -77,9 +121,17 @@ Used to replace the browser's native scrollbar.
| 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 |
### Events
### Scrollbar Events
| Event Name | Description | Parameters |
|---------- |-------- |---------- |
| scroll | triggers when scrolling | distance of scrolling { scrollLeft, scrollTop }|
### Scrollbar Methods
| Method | Description | Parameters |
| ---- | ---- | ---- |
| setScrollTop | Set distance to scroll top | (scrollTop: number)
| setScrollLeft | Set distance to scroll left | (scrollLeft: number)

View File

@ -7,6 +7,7 @@ Used to replace the browser's native scrollbar.
:::demo Use `height` property to set the height of the scrollbar, or if not set, it adapts according to the parent container height.
```html
<el-scrollbar height="400px">
<p class="item" v-for="item in 20">{{ item }}</p>
</el-scrollbar>
@ -19,6 +20,7 @@ Used to replace the browser's native scrollbar.
:::demo When the element width is greater than the scrollbar width, the horizontal scrollbar is displayed.
```html
<el-scrollbar>
<div class="flex-content">
<p class="item" v-for="item in 50">{{ item }}</p>
@ -33,6 +35,7 @@ Used to replace the browser's native scrollbar.
:::demo The scrollbar is displayed only when the element height exceeds the max height.
```html
<template>
<el-button @click="add">Add Item</el-button>
<el-button @click="delete">Delete Item</el-button>
@ -64,6 +67,47 @@ Used to replace the browser's native scrollbar.
:::
### Manual scroll
:::demo Use `setScrollTop` and `setScrollLeft` methods can control scrollbar manually.
```html
<template>
<el-scrollbar ref="scrollbar" height="400px" always>
<div ref="inner">
<p class="item" v-for="item in 20">{{ item }}</p>
</div>
</el-scrollbar>
<el-slider v-model="value" @input="inputSlider" :max="max" :format-tooltip="formatTooltip"></el-slider>
</template>
<script>
export default {
data() {
return {
max: 0,
value: 0
}
},
mounted() {
this.max = this.$refs.inner.clientHeight - 380
},
methods: {
inputSlider(value) {
this.$refs.scrollbar.setScrollTop(value)
},
formatTooltip(value) {
return `${value} px`
}
}
}
</script>
```
:::
### Scrollbar Attributes
| Attribute | Description | Type | Accepted Values | Default |
@ -77,9 +121,17 @@ Used to replace the browser's native scrollbar.
| 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 |
### Events
### Scrollbar Events
| Event Name | Description | Parameters |
|---------- |-------- |---------- |
| scroll | triggers when scrolling | distance of scrolling { scrollLeft, scrollTop }|
### Scrollbar Methods
| Method | Description | Parameters |
| ---- | ---- | ---- |
| setScrollTop | Set distance to scroll top | (scrollTop: number)
| setScrollLeft | Set distance to scroll left | (scrollLeft: number)

View File

@ -7,6 +7,7 @@
:::demo 通过 `height` 属性设置滚动条高度,若不设置则根据父容器高度自适应。
```html
<el-scrollbar height="400px">
<p class="item" v-for="item in 20">{{ item }}</p>
</el-scrollbar>
@ -19,6 +20,7 @@
:::demo 当元素宽度大于滚动条宽度时,会显示横向滚动条。
```html
<el-scrollbar>
<div class="flex-content">
<p class="item" v-for="item in 50">{{ item }}</p>
@ -33,6 +35,7 @@
:::demo 当元素高度超过最大高度,才会显示滚动条。
```html
<template>
<el-button @click="add">添加元素</el-button>
<el-button @click="delete">删除元素</el-button>
@ -64,6 +67,47 @@
:::
### 手动滚动
:::demo 通过使用 `setScrollTop``setScrollLeft` 方法,可以手动控制滚动条滚动。
```html
<template>
<el-scrollbar ref="scrollbar" height="400px" always>
<div ref="inner">
<p class="item" v-for="item in 20">{{ item }}</p>
</div>
</el-scrollbar>
<el-slider v-model="value" @input="inputSlider" :max="max" :format-tooltip="formatTooltip"></el-slider>
</template>
<script>
export default {
data() {
return {
max: 0,
value: 0
}
},
mounted() {
this.max = this.$refs.inner.clientHeight - 380
},
methods: {
inputSlider(value) {
this.$refs.scrollbar.setScrollTop(value)
},
formatTooltip(value) {
return `${value} px`
}
}
}
</script>
```
:::
### Scrollbar Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
@ -77,9 +121,17 @@
| view-class | 视图的自定义类名 | string | — | — |
| noresize | 不响应容器尺寸变化,如果容器尺寸不会发生变化,最好设置它可以优化性能 | boolean | — | false |
| tag | 视图的元素标签 | string | — | div |
| always | 滚动条总是显示 | boolean | — | false |
### Events
### Scrollbar Events
| 事件名称 | 说明 | 回调参数 |
|---------- |-------- |---------- |
| scroll | 滚动时触发的事件 | 滚动距离 { scrollLeft, scrollTop }|
### Scrollbar Methods
| 方法名 | 说明 | 参数
|---------- |-------------- | --------------
| setScrollTop | 设置滚动条到顶部的距离 | (scrollTop: number)
| setScrollLeft | 设置滚动条到左边的距离 | (scrollLeft: number)