增加滚动条组件
parent
dd77738f6c
commit
480d22d60c
|
@ -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)
|
Loading…
Reference in New Issue