From 480d22d60c050b63d5568df830f72bc78214e49f Mon Sep 17 00:00:00 2001 From: chenjiajian <770230504@qq.com> Date: Mon, 20 Mar 2023 17:12:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=BB=9A=E5=8A=A8=E6=9D=A1?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scroll/index.js | 224 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 src/scroll/index.js diff --git a/src/scroll/index.js b/src/scroll/index.js new file mode 100644 index 0000000..23928e1 --- /dev/null +++ b/src/scroll/index.js @@ -0,0 +1,224 @@ +/** + * {滚动条组件} + * @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 + 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.$refs.vertical.style.opacity = 0.3 + this.$refs.horizon.style.opacity = 0.3 + } + onmouseleave() { + 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 + 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)