增加滚动条组件

master
chenjiajian 2023-03-20 17:12:18 +08:00
parent dd77738f6c
commit 480d22d60c
1 changed files with 224 additions and 0 deletions

224
src/scroll/index.js Normal file
View File

@ -0,0 +1,224 @@
/**
* {滚动条组件}
* @author chensbox <chensbox@foxmail.com>
* @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`
<div ref="scrollView" class="scroll">
<slot></slot>
</div>
<div ref="vertical" class="scroll-bar vertical"></div>
<div ref="horizon" class="scroll-bar horizon"></div>
`
}
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)