diff --git a/packages/scrollbar/src/bar.ts b/packages/scrollbar/src/bar.ts index c326688aa8..6c54abfb26 100644 --- a/packages/scrollbar/src/bar.ts +++ b/packages/scrollbar/src/bar.ts @@ -1,6 +1,6 @@ import { on, off } from '@element-plus/utils/dom' import { renderThumbStyle, BAR_MAP } from './util' -import { h } from 'vue' +import { h, computed, ref, getCurrentInstance, onUnmounted, inject, Ref } from 'vue' export default { name: 'Bar', @@ -11,83 +11,76 @@ export default { move: Number, }, - computed: { - bar() { - return BAR_MAP[this.vertical ? 'vertical' : 'horizontal'] - }, - - wrap() { - return this.$parent.wrap - }, - }, - - render() { - const { size, move, bar } = this - - return h('div', { - class: ['el-scrollbar__bar', 'is-' + bar.key], - onMousedown: this.clickTrackHandler, - }, h('div', { - ref: 'thumb', - class: 'el-scrollbar__thumb', - onMousedown: this.clickThumbHandler, - style: renderThumbStyle({ - size, - move, - bar, - }), - })) - }, - - methods: { - clickThumbHandler(e) { + setup(props) { + const instance = getCurrentInstance() + const thumb = ref(null) + const wrap = inject('scroll-bar-wrap', {}) as Ref + const bar = computed(() => { + return BAR_MAP[props.vertical ? 'vertical' : 'horizontal'] + }) + const barStore = ref({}) + const cursorDown = ref(null) + const clickThumbHandler= (e) => { // prevent click event of right button if (e.ctrlKey || e.button === 2) { return } - this.startDrag(e) - this[this.bar.axis] = (e.currentTarget[this.bar.offset] - (e[this.bar.client] - e.currentTarget.getBoundingClientRect()[this.bar.direction])) - }, + startDrag(e) + barStore.value[bar.value.axis] = (e.currentTarget[bar.value.offset] - (e[bar.value.client] - e.currentTarget.getBoundingClientRect()[bar.value.direction])) + } - clickTrackHandler(e) { - const offset = Math.abs(e.target.getBoundingClientRect()[this.bar.direction] - e[this.bar.client]) - const thumbHalf = (this.$refs.thumb[this.bar.offset] / 2) - const thumbPositionPercentage = ((offset - thumbHalf) * 100 / this.$el[this.bar.offset]) + const clickTrackHandler = (e) => { + const offset = Math.abs(e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) + const thumbHalf = (thumb.value[bar.value.offset] / 2) + const thumbPositionPercentage = ((offset - thumbHalf) * 100 / instance.vnode.el[bar.value.offset]) - this.wrap[this.bar.scroll] = (thumbPositionPercentage * this.wrap[this.bar.scrollSize] / 100) - }, - - startDrag(e) { + wrap.value[bar.value.scroll] = (thumbPositionPercentage * wrap.value[bar.value.scrollSize] / 100) + } + const startDrag = (e) =>{ e.stopImmediatePropagation() - this.cursorDown = true - - on(document, 'mousemove', this.mouseMoveDocumentHandler) - on(document, 'mouseup', this.mouseUpDocumentHandler) + cursorDown.value = true + on(document, 'mousemove', mouseMoveDocumentHandler) + on(document, 'mouseup', mouseUpDocumentHandler) document.onselectstart = () => false - }, + } - mouseMoveDocumentHandler(e) { - if (this.cursorDown === false) return - const prevPage = this[this.bar.axis] + const mouseMoveDocumentHandler = (e) => { + if (cursorDown.value === false) return + const prevPage = barStore.value[bar.value.axis] if (!prevPage) return - const offset = ((this.$el.getBoundingClientRect()[this.bar.direction] - e[this.bar.client]) * -1) - const thumbClickPosition = (this.$refs.thumb[this.bar.offset] - prevPage) - const thumbPositionPercentage = ((offset - thumbClickPosition) * 100 / this.$el[this.bar.offset]) + const offset = ((instance.vnode.el.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) * -1) + const thumbClickPosition = (thumb.value[bar.value.offset] - prevPage) + const thumbPositionPercentage = ((offset - thumbClickPosition) * 100 / instance.vnode.el[bar.value.offset]) + wrap.value[bar.value.scroll] = (thumbPositionPercentage * wrap.value[bar.value.scrollSize] / 100) + } - this.wrap[this.bar.scroll] = (thumbPositionPercentage * this.wrap[this.bar.scrollSize] / 100) - }, - - mouseUpDocumentHandler() { - this.cursorDown = false - this[this.bar.axis] = 0 - off(document, 'mousemove', this.mouseMoveDocumentHandler) + function mouseUpDocumentHandler(e) { + cursorDown.value = false + barStore.value[bar.value.axis] = 0 + off(document, 'mousemove', mouseMoveDocumentHandler) document.onselectstart = null - }, - }, + } - destroyed() { - off(document, 'mouseup', this.mouseUpDocumentHandler) + onUnmounted(() => { + off(document, 'mouseup', mouseUpDocumentHandler) + }) + + return () => h('div', { + class: ['el-scrollbar__bar', 'is-' + bar.value.key], + onMousedown: clickTrackHandler, + }, + h('div', { + ref: thumb, + class: 'el-scrollbar__thumb', + onMousedown: clickThumbHandler, + style: renderThumbStyle({ + size: props.size, + move: props.move, + bar: bar.value, + }), + }), + ) }, } diff --git a/packages/scrollbar/src/index.ts b/packages/scrollbar/src/index.ts index ef06f1d66c..2ab1dc7a22 100644 --- a/packages/scrollbar/src/index.ts +++ b/packages/scrollbar/src/index.ts @@ -2,7 +2,7 @@ import { addResizeListener, removeResizeListener } from '@element-plus/utils/resize-event' import scrollbarWidth from '@element-plus/utils/scrollbar-width' import { toObject } from '@element-plus/utils/util' -import { h } from 'vue' +import { h, ref, onMounted, onBeforeUnmount, nextTick, provide } from 'vue' import Bar from './bar' export default { @@ -23,98 +23,93 @@ export default { }, }, - data() { - return { - sizeWidth: '0', - sizeHeight: '0', - moveX: 0, - moveY: 0, + setup(props, ctx) { + const sizeWidth = ref('0') + const sizeHeight = ref('0') + const moveX = ref(0) + const moveY = ref(0) + const wrap = ref(null) + const resize = ref(null) + + provide('scroll-bar-wrap', wrap) + + const handleScroll = () => { + moveY.value = ((wrap.value.scrollTop * 100) / wrap.value.clientHeight) + moveX.value = ((wrap.value.scrollLeft * 100) / wrap.value.clientWidth) } - }, - computed: { - wrap() { - return this.$refs.wrap - }, - }, + const update = () => { + if (!wrap.value) return - render() { - const gutter = scrollbarWidth() - let style = this.wrapStyle + const heightPercentage = (wrap.value.clientHeight * 100 / wrap.value.scrollHeight) + const widthPercentage = (wrap.value.clientWidth * 100 / wrap.value.scrollWidth) - if (gutter) { - const gutterWith = `-${gutter}px` - const gutterStyle = `margin-bottom: ${gutterWith}; margin-right: ${gutterWith};` + sizeHeight.value = (heightPercentage < 100) ? (heightPercentage + '%') : '' + sizeWidth.value = (widthPercentage < 100) ? (widthPercentage + '%') : '' + } - if (Array.isArray(this.wrapStyle)) { - style = toObject(this.wrapStyle) - style.marginRight = style.marginBottom = gutterWith - } else if (typeof this.wrapStyle === 'string') { - style += gutterStyle - } else { - style = gutterStyle + onMounted(() => { + if (props.native) return + nextTick(update) + !props.noresize && addResizeListener(resize.value, update) + }) + + onBeforeUnmount(() => { + if (props.native) return + !props.noresize && removeResizeListener(resize.value, update) + }) + + return () => { + const gutter = scrollbarWidth() + let style = props.wrapStyle + if (gutter) { + const gutterWith = `-${gutter}px` + const gutterStyle = `margin-bottom: ${gutterWith}; margin-right: ${gutterWith};` + + if (Array.isArray(props.wrapStyle)) { + style = toObject(props.wrapStyle) + style.marginRight = style.marginBottom = gutterWith + } else if (typeof props.wrapStyle === 'string') { + style += gutterStyle + } else { + style = gutterStyle + } } - } - const view = h(this.tag, { - class: ['el-scrollbar__view', this.viewClass], - style: this.viewStyle, - ref: 'resize', - }, this.$slots.default()) - const wrap = h('div', { - ref: 'wrap', - style: style, - onScroll: this.handleScroll, - class: [this.wrapClass, 'el-scrollbar__wrap', gutter ? '' : 'el-scrollbar__wrap--hidden-default'], - }, [view]) - let nodes - - if (!this.native) { - nodes = [wrap, h(Bar, { - move: this.moveX, - size: this.sizeWidth, - }), h(Bar, { - vertical: true, - move: this.moveY, - size: this.sizeHeight, - })] - } else { - nodes = h('div', { - ref: 'wrap', - class: [this.wrapClass, 'el-scrollbar__wrap'], - style: style, + const view = h(props.tag, { + class: ['el-scrollbar__view', props.viewClass], + style: props.viewStyle, + ref: resize, + }, ctx.slots.default()) + const _wrap = h('div', { + ref: wrap, + style, + onScroll: handleScroll, + class: [props.wrapClass, 'el-scrollbar__wrap', gutter ? '' : 'el-scrollbar__wrap--hidden-default'], }, [view]) + + let nodes + + if (!props.native) { + nodes = [_wrap,h(Bar,{ + move: moveX.value, + size: sizeWidth.value, + }),h(Bar,{ + vertical: true, + move: moveY.value, + size: sizeHeight.value, + }), + ] + } else { + nodes = [ + h('div',{ + ref: wrap, + class: [props.wrapClass, 'el-scrollbar__wrap'], + style, + }, [view]), + ] + } + + return h('div', { class: 'el-scrollbar' }, nodes) } - return h('div', { class: 'el-scrollbar' }, nodes) - }, - - methods: { - handleScroll() { - const wrap = this.wrap - - this.moveY = ((wrap.scrollTop * 100) / wrap.clientHeight) - this.moveX = ((wrap.scrollLeft * 100) / wrap.clientWidth) - }, - - update() { - const wrap = this.wrap - if (!wrap) return - - const heightPercentage = (wrap.clientHeight * 100 / wrap.scrollHeight) - const widthPercentage = (wrap.clientWidth * 100 / wrap.scrollWidth) - - this.sizeHeight = (heightPercentage < 100) ? (heightPercentage + '%') : '' - this.sizeWidth = (widthPercentage < 100) ? (widthPercentage + '%') : '' - }, - }, - - mounted() { - if (this.native) return - this.$nextTick(this.update) - !this.noresize && addResizeListener(this.$refs.resize, this.update) - }, - - beforeDestroy() { - if (this.native) return - !this.noresize && removeResizeListener(this.$refs.resize, this.update) }, }