Merge branch 'master' of github.com:9th-js/wcui
commit
7fd978eb57
|
@ -0,0 +1,229 @@
|
|||
/**
|
||||
* {滚动条组件}
|
||||
* @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
|
||||
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`
|
||||
<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.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)
|
Loading…
Reference in New Issue