/** * {滚动条组件} * @author chensbox * @date 2023/03/20 15:17:25 */ import { css, bind, html, unbind, Component } from '@bd/core' class Scroll extends Component { static props = { axis: { type: String, default: 'xy', observer(val) { this.onAxisChange(val) } }, distance: 0 } dragging = false hovering = false static styles = [ css` :host { position: relative; overflow: hidden; display: block; &::-webkit-scrollbar { display: none; } scrollbar-width: none; //火狐专属 } .scroll { position: relative; } .scroll-bar { display: none; position: absolute; background: #909399; width: 0; height: 0; opacity: 0; border-radius: 4px; cursor: pointer; transition: opacity ease-in-out 0.2s; &.vertical { width: 8px; top: 0; right: 0; } &.horizon { height: 8px; bottom: 0; left: 0; } &:hover { opacity: 0.5 !important; } } :host([disabled]) { overflow: hidden !important; .scroll-bar { visibility: hidden; } } ` ] onAxisChange(val) { this.style.overflow = 'hidden' if (val === 'xy') { this.style.overflow = 'auto' } else { this.style[`overflow-${val}`] = 'auto' } } render() { return html`
` } onmouseenter() { this.hovering = true this.$refs.vertical.style.opacity = 0.3 this.$refs.horizon.style.opacity = 0.3 } onmouseleave() { this.hovering = false if (!this.dragging) { this.$refs.vertical.style.opacity = 0 this.$refs.horizon.style.opacity = 0 } } onmousedown(e) { this.dragging = true const { clientHeight, scrollHeight, clientWidth, scrollWidth, verticalHeight, horizonWidth } = this let start, cur const isVerticalScroll = e.target === this.$refs.vertical if (isVerticalScroll) { start = e.clientY cur = this.scrollTop } else { start = e.clientX cur = this.scrollLeft } const onmousemove = bind(document, 'mousemove', e => { let dif, rang, progress if (isVerticalScroll) { dif = e.clientY - start rang = clientHeight - verticalHeight progress = dif / rang this.scrollTop = cur + progress * (scrollHeight - clientHeight) } else { dif = e.clientX - start rang = clientWidth - horizonWidth progress = dif / rang this.scrollLeft = cur + progress * (scrollWidth - clientWidth) } }) this.onmouseup = bind(document, 'mouseup', () => { this.dragging = false if (!this.hovering) { this.$refs.vertical.style.opacity = 0 this.$refs.horizon.style.opacity = 0 } unbind(document, 'mousemove', onmousemove) }) } onscroll(ev) { const { distance, scrollTop, scrollLeft, clientHeight, scrollHeight, clientWidth, scrollWidth, verticalHeight, horizonWidth } = this const { vertical, horizon } = this.$refs const verticalProgress = scrollTop / (scrollHeight - clientHeight) || 0 const horizonProgress = scrollLeft / (scrollWidth - clientWidth) || 0 vertical.style.top = `${ scrollTop + (clientHeight - verticalHeight) * verticalProgress }px` vertical.style.left = scrollLeft + clientWidth - 8 + 'px' horizon.style.left = `${ scrollLeft + (clientWidth - horizonWidth) * horizonProgress }px` horizon.style.top = scrollTop + clientHeight - 8 + 'px' if (!ev) { //事件对象不存在,则是手动调用的 不触发事件。 return } if (this.verticalHeight) { if (scrollHeight - scrollTop - clientHeight <= distance) { this.$emit('reach-bottom') } if (scrollTop === 0) { this.$emit('reach-top') } } } initScrollBar() { const { axis, clientHeight, scrollHeight, clientWidth, scrollWidth } = this const { vertical, horizon } = this.$refs // console.log(this.$refs) if (clientHeight !== scrollHeight) { this.verticalHeight = (clientHeight / scrollHeight) * clientHeight } else { this.verticalHeight = 0 } if (clientWidth !== scrollWidth) { this.horizonWidth = (clientWidth / scrollWidth) * clientWidth } else { this.horizonWidth = 0 } if (axis.includes('x')) { horizon.style.display = 'block' horizon.style.width = this.horizonWidth + 'px' bind(horizon, 'mousedown', this.onmousedown.bind(this)) } if (axis.includes('y')) { vertical.style.display = 'block' vertical.style.height = this.verticalHeight + 'px' bind(vertical, 'mousedown', this.onmousedown.bind(this)) } } mounted() { this.initScrollBar() this.$on('mouseenter', this.onmouseenter) this.$on('mouseleave', this.onmouseleave) this.$on('scroll', this.onscroll) this.resizeObserver = new ResizeObserver(() => { this.initScrollBar() this.onscroll() }) this.resizeObserver.observe(this.$refs.scrollView) } unmounted() { this.resizeObserver.disconnect() unbind(document, 'mouseup', this.onmouseup) this.$of('mouseenter', this.onmouseenter) this.$of('mouseleave', this.onmouseleave) this.$of('scroll', this.onscroll) unbind(this.$refs.vertical, 'mousedown', this.onmousedown) unbind(this.$refs.horizon, 'mousedown', this.onmousedown) } } customElements.define('wc-scroll', Scroll)