|
|
|
@ -4,258 +4,414 @@
|
|
|
|
|
* @date 2023/03/20 15:17:25
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { css, bind, html, unbind, Component } from '@bd/core'
|
|
|
|
|
import { css, html, bind, unbind, Component } from '@bd/core'
|
|
|
|
|
|
|
|
|
|
class Scroll extends Component {
|
|
|
|
|
static props = {
|
|
|
|
|
axis: 'xy',
|
|
|
|
|
distance: 0
|
|
|
|
|
axis: 'xy', // 滚动方向, 默认x轴和y轴都可以滚动
|
|
|
|
|
delay: 1000, // 节流防抖延迟
|
|
|
|
|
distance: 1 // 触发距离阀值, 单位像素
|
|
|
|
|
}
|
|
|
|
|
dragging = false
|
|
|
|
|
hovering = false
|
|
|
|
|
|
|
|
|
|
static styles = [
|
|
|
|
|
css`
|
|
|
|
|
:host {
|
|
|
|
|
position: relative;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
display: block;
|
|
|
|
|
}
|
|
|
|
|
.scroller {
|
|
|
|
|
position: relative;
|
|
|
|
|
height: 100%;
|
|
|
|
|
width: 100%;
|
|
|
|
|
overflow: auto;
|
|
|
|
|
&::-webkit-scrollbar {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
scrollbar-width: none; //火狐专属
|
|
|
|
|
}
|
|
|
|
|
.scroll-bar {
|
|
|
|
|
position: absolute;
|
|
|
|
|
background: #909399;
|
|
|
|
|
width: 0;
|
|
|
|
|
height: 0;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: opacity ease-in-out 0.2s;
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
&.vertical {
|
|
|
|
|
width: 8px;
|
|
|
|
|
top: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
.container {
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
position: relative;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
&.horizon {
|
|
|
|
|
height: 8px;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
|
|
|
|
|
.wrapper {
|
|
|
|
|
overflow: auto;
|
|
|
|
|
scrollbar-width: none;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
scrollbar-width: 0;
|
|
|
|
|
|
|
|
|
|
&::-webkit-scrollbar {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
&:hover {
|
|
|
|
|
opacity: 0.5 !important;
|
|
|
|
|
.content {
|
|
|
|
|
width: fit-content;
|
|
|
|
|
height: fit-content;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
:host([disabled]) {
|
|
|
|
|
overflow: hidden !important;
|
|
|
|
|
.scroll-bar {
|
|
|
|
|
visibility: hidden;
|
|
|
|
|
`,
|
|
|
|
|
css`
|
|
|
|
|
/* 横向 */
|
|
|
|
|
|
|
|
|
|
.is-horizontal,
|
|
|
|
|
.is-vertical {
|
|
|
|
|
visibility: hidden;
|
|
|
|
|
position: absolute;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
z-index: 10240;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
user-select: none;
|
|
|
|
|
transition: opacity 0.3s linear, visibility 0.3s linear;
|
|
|
|
|
|
|
|
|
|
.thumb {
|
|
|
|
|
display: block;
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
background: rgba(44, 47, 53, 0.25);
|
|
|
|
|
cursor: default;
|
|
|
|
|
transition: width 0.1s linear, height 0.1s linear;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
background: rgba(44, 47, 53, 0.5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.is-horizontal {
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
left: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 10px;
|
|
|
|
|
|
|
|
|
|
.thumb {
|
|
|
|
|
width: 0;
|
|
|
|
|
height: 6px;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
height: 10px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* 纵向 */
|
|
|
|
|
.is-vertical {
|
|
|
|
|
top: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
width: 10px;
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
.thumb {
|
|
|
|
|
width: 6px;
|
|
|
|
|
height: 0;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
width: 10px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
css`
|
|
|
|
|
:host(:hover) {
|
|
|
|
|
.is-horizontal,
|
|
|
|
|
.is-vertical {
|
|
|
|
|
visibility: visible;
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:host([axis='x']) {
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
overflow-y: hidden;
|
|
|
|
|
.vertical {
|
|
|
|
|
.wrapper {
|
|
|
|
|
overflow-y: hidden;
|
|
|
|
|
}
|
|
|
|
|
.is-vertical {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
:host([axis='y']) {
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
overflow-x: hidden;
|
|
|
|
|
.horizon {
|
|
|
|
|
.wrapper {
|
|
|
|
|
overflow-x: hidden;
|
|
|
|
|
}
|
|
|
|
|
.is-horizontal {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
:host([disabled]) {
|
|
|
|
|
.wrapper {
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
.is-vertical,
|
|
|
|
|
.is-horizontal {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
stamp = 0
|
|
|
|
|
|
|
|
|
|
cache = {
|
|
|
|
|
xBar: 0, // 横轴长度
|
|
|
|
|
yBar: 0, // 纵轴长度
|
|
|
|
|
thumbX: 0, //横向条滚动距离
|
|
|
|
|
thumbY: 0 // 纵向条滚动距离
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get scrollTop() {
|
|
|
|
|
return this.$refs.scroller.scrollTop
|
|
|
|
|
return this.$refs.box?.scrollTop || 0
|
|
|
|
|
}
|
|
|
|
|
set scrollTop(val) {
|
|
|
|
|
this.$refs.scroller.scrollTop = val
|
|
|
|
|
}
|
|
|
|
|
get scrollHeight() {
|
|
|
|
|
return this.$refs.scroller.scrollHeight
|
|
|
|
|
}
|
|
|
|
|
set scrollHeight(val) {
|
|
|
|
|
this.$refs.scroller.scrollHeight = val
|
|
|
|
|
|
|
|
|
|
set scrollTop(n) {
|
|
|
|
|
n = +n
|
|
|
|
|
if (n === n) {
|
|
|
|
|
this.$refs.box.scrollTop = n
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get scrollLeft() {
|
|
|
|
|
return this.$refs.scroller.scrollLeft
|
|
|
|
|
return this.$refs.box?.scrollLeft || 0
|
|
|
|
|
}
|
|
|
|
|
set scrollLeft(val) {
|
|
|
|
|
this.$refs.scroller.scrollLeft = val
|
|
|
|
|
|
|
|
|
|
set scrollLeft(n) {
|
|
|
|
|
n = +n
|
|
|
|
|
if (n === n) {
|
|
|
|
|
this.$refs.box.scrollLeft = n
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get scrollHeight() {
|
|
|
|
|
return this.$refs.box?.scrollHeight
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get scrollWidth() {
|
|
|
|
|
return this.$refs.scroller.scrollWidth
|
|
|
|
|
}
|
|
|
|
|
set scrollWidth(val) {
|
|
|
|
|
this.$refs.scroller.scrollWidth = val
|
|
|
|
|
}
|
|
|
|
|
render() {
|
|
|
|
|
return html`
|
|
|
|
|
<div ref="scroller" class="scroller">
|
|
|
|
|
<slot ref="slot"></slot>
|
|
|
|
|
</div>
|
|
|
|
|
<div ref="vertical" class="scroll-bar vertical"></div>
|
|
|
|
|
<div ref="horizon" class="scroll-bar horizon"></div>
|
|
|
|
|
`
|
|
|
|
|
return this.$refs.box?.scrollWidth
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
__init__(ev) {
|
|
|
|
|
//
|
|
|
|
|
let width = this.offsetWidth
|
|
|
|
|
let height = this.offsetHeight
|
|
|
|
|
let scrollWidth = this.scrollWidth
|
|
|
|
|
let scrollHeight = this.scrollHeight
|
|
|
|
|
|
|
|
|
|
let yBar = 50 // 滚动条的高度
|
|
|
|
|
let xBar = 50 // 滚动条的宽度
|
|
|
|
|
|
|
|
|
|
this.scrollLeft = 0
|
|
|
|
|
this.scrollTop = 0
|
|
|
|
|
|
|
|
|
|
// 修正由于未知原因,导致父容器产生滚动距离
|
|
|
|
|
// 导致的内容被遮挡的bug
|
|
|
|
|
// 重构后待观察, 暂时注释掉这行(2023/3/23)
|
|
|
|
|
// this.$refs.box.parentNode.scrollTop = 0
|
|
|
|
|
|
|
|
|
|
yBar = (height * (height / scrollHeight)) >> 0
|
|
|
|
|
xBar = (width * (width / scrollWidth)) >> 0
|
|
|
|
|
|
|
|
|
|
if (yBar < 50) {
|
|
|
|
|
yBar = 50
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
if (xBar < 50) {
|
|
|
|
|
xBar = 50
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
// 100%或主体高度比滚动条还短时不显示
|
|
|
|
|
if (xBar >= width) {
|
|
|
|
|
xBar = 0
|
|
|
|
|
}
|
|
|
|
|
if (yBar >= height) {
|
|
|
|
|
yBar = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.transform = `translateY(${
|
|
|
|
|
(clientHeight - verticalHeight) * verticalProgress
|
|
|
|
|
}px)`
|
|
|
|
|
horizon.style.transform = `translateX(${
|
|
|
|
|
(clientWidth - horizonWidth) * horizonProgress
|
|
|
|
|
}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
|
|
|
|
|
this.cache.yBar = yBar
|
|
|
|
|
this.cache.xBar = xBar
|
|
|
|
|
|
|
|
|
|
if (xBar > 0) {
|
|
|
|
|
this.$refs.x.parentNode.style.display = 'flex'
|
|
|
|
|
this.$refs.x.style.width = xBar + 'px'
|
|
|
|
|
} else {
|
|
|
|
|
this.verticalHeight = 0
|
|
|
|
|
this.$refs.x.parentNode.style.display = 'none'
|
|
|
|
|
}
|
|
|
|
|
if (clientWidth !== scrollWidth) {
|
|
|
|
|
this.horizonWidth = (clientWidth / scrollWidth) * clientWidth
|
|
|
|
|
if (yBar > 0) {
|
|
|
|
|
this.$refs.y.parentNode.style.display = 'flex'
|
|
|
|
|
this.$refs.y.style.height = yBar + 'px'
|
|
|
|
|
} else {
|
|
|
|
|
this.horizonWidth = 0
|
|
|
|
|
}
|
|
|
|
|
if (axis.includes('x')) {
|
|
|
|
|
horizon.style.width = this.horizonWidth + 'px'
|
|
|
|
|
bind(horizon, 'mousedown', this.onmousedown.bind(this))
|
|
|
|
|
}
|
|
|
|
|
if (axis.includes('y')) {
|
|
|
|
|
vertical.style.height = this.verticalHeight + 'px'
|
|
|
|
|
bind(vertical, 'mousedown', this.onmousedown.bind(this))
|
|
|
|
|
this.$refs.y.parentNode.style.display = 'none'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#watchResize() {
|
|
|
|
|
const slotList = this.$refs.slot.assignedNodes()
|
|
|
|
|
if (slotList) {
|
|
|
|
|
slotList.forEach(element => {
|
|
|
|
|
if (element.nodeType === 1) {
|
|
|
|
|
this.resizeObserver.observe(element)
|
|
|
|
|
|
|
|
|
|
_fetchScrollX(moveX) {
|
|
|
|
|
let { xBar } = this.cache
|
|
|
|
|
let { scrollWidth, offsetWidth: width } = this
|
|
|
|
|
|
|
|
|
|
if (moveX < 0) {
|
|
|
|
|
moveX = 0
|
|
|
|
|
} else if (moveX > width - xBar) {
|
|
|
|
|
moveX = width - xBar
|
|
|
|
|
}
|
|
|
|
|
this.scrollLeft = (scrollWidth - width) * (moveX / (width - xBar))
|
|
|
|
|
this.$refs.x.style.transform = `translateX(${moveX}px)`
|
|
|
|
|
|
|
|
|
|
return moveX
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_fetchScrollY(moveY) {
|
|
|
|
|
let { yBar } = this.cache
|
|
|
|
|
let { scrollHeight, offsetHeight: height } = this
|
|
|
|
|
|
|
|
|
|
if (moveY < 0) {
|
|
|
|
|
moveY = 0
|
|
|
|
|
} else if (moveY > height - yBar) {
|
|
|
|
|
moveY = height - yBar
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.scrollTop = (scrollHeight - height) * (moveY / (height - yBar))
|
|
|
|
|
this.$refs.y.style.transform = `translateY(${moveY}px)`
|
|
|
|
|
return moveY
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_fireReachEnd(action = 'reach-bottom') {
|
|
|
|
|
let delay = this.delay
|
|
|
|
|
let { scrollHeight, offsetHeight: height } = this
|
|
|
|
|
let top = this.scrollTop
|
|
|
|
|
let now = Date.now()
|
|
|
|
|
|
|
|
|
|
if (now - this.stamp > delay) {
|
|
|
|
|
if (action === 'reach-bottom') {
|
|
|
|
|
if (height + top < scrollHeight) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
if (top > 0) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.stamp = now
|
|
|
|
|
this.$emit(action)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
|
this.$on('mouseenter', this.onmouseenter)
|
|
|
|
|
this.$on('mouseleave', this.onmouseleave)
|
|
|
|
|
this.onscroll = bind(
|
|
|
|
|
this.$refs.scroller,
|
|
|
|
|
'scroll',
|
|
|
|
|
this.onscroll.bind(this)
|
|
|
|
|
)
|
|
|
|
|
this.resizeObserver = new ResizeObserver(() => {
|
|
|
|
|
this.initScrollBar()
|
|
|
|
|
this.onscroll()
|
|
|
|
|
let startX,
|
|
|
|
|
startY,
|
|
|
|
|
moveX,
|
|
|
|
|
moveY,
|
|
|
|
|
mousemoveFn = ev => {
|
|
|
|
|
let { thumbY, thumbX } = this.cache
|
|
|
|
|
if (startX !== undefined) {
|
|
|
|
|
moveX = this._fetchScrollX(thumbX + ev.pageX - startX)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (startY !== undefined) {
|
|
|
|
|
moveY = this._fetchScrollY(thumbY + ev.pageY - startY)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
mouseupFn = ev => {
|
|
|
|
|
if (Math.abs(ev.pageY - startY) > this.distance) {
|
|
|
|
|
this._fireReachEnd(ev.pageY > startY ? 'reach-bottom' : 'reach-top')
|
|
|
|
|
}
|
|
|
|
|
startX = undefined
|
|
|
|
|
startY = undefined
|
|
|
|
|
this.cache.thumbX = moveX || 0
|
|
|
|
|
this.cache.thumbY = moveY || 0
|
|
|
|
|
delete this._active
|
|
|
|
|
unbind(document, 'mousemove', mousemoveFn)
|
|
|
|
|
unbind(document, 'mouseup', mouseupFn)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 鼠标滚动事件
|
|
|
|
|
this._scrollFn = bind(this.$refs.box, 'scroll', ev => {
|
|
|
|
|
ev.stopPropagation()
|
|
|
|
|
// 拖拽时忽略滚动事件
|
|
|
|
|
if (this._active) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
let { xBar, yBar, thumbX, thumbY } = this.cache
|
|
|
|
|
let {
|
|
|
|
|
axis,
|
|
|
|
|
scrollHeight,
|
|
|
|
|
scrollWidth,
|
|
|
|
|
offsetHeight: height,
|
|
|
|
|
offsetWidth: width,
|
|
|
|
|
scrollTop,
|
|
|
|
|
scrollLeft
|
|
|
|
|
} = this
|
|
|
|
|
|
|
|
|
|
// x轴 y轴 都为0时, 不作任何处理
|
|
|
|
|
if (xBar === 0 && yBar === 0) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
if (axis === 'y' || axis === 'xy') {
|
|
|
|
|
if (yBar) {
|
|
|
|
|
// 修正滚动条的位置
|
|
|
|
|
// 滚动比例 y 滚动条的可移动距离
|
|
|
|
|
let fixedY = ~~(
|
|
|
|
|
(scrollTop / (scrollHeight - height)) *
|
|
|
|
|
(height - yBar)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (fixedY !== thumbY) {
|
|
|
|
|
this.cache.thumbY = fixedY
|
|
|
|
|
this.$refs.y.style.transform = `translateY(${fixedY}px)`
|
|
|
|
|
|
|
|
|
|
if (Math.abs(fixedY - thumbY) > this.distance) {
|
|
|
|
|
this._fireReachEnd(fixedY > thumbY ? 'reach-bottom' : 'reach-top')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (axis === 'x' || axis === 'xy') {
|
|
|
|
|
if (xBar) {
|
|
|
|
|
// 修正滚动条的位置
|
|
|
|
|
// 滚动比例 x 滚动条的可移动距离
|
|
|
|
|
let fixedX = ~~((scrollLeft / (scrollWidth - width)) * (width - xBar))
|
|
|
|
|
|
|
|
|
|
if (fixedX !== thumbX) {
|
|
|
|
|
this.cache.thumbX = fixedX
|
|
|
|
|
this.$refs.x.style.transform = `translateX(${fixedX}px)`
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.$emit('scroll')
|
|
|
|
|
})
|
|
|
|
|
this.#watchResize()
|
|
|
|
|
this.$refs.slot.addEventListener('slotchange', () => this.#watchResize())
|
|
|
|
|
|
|
|
|
|
this._yBarFn = bind(this.$refs.y, 'mousedown', ev => {
|
|
|
|
|
startY = ev.pageY
|
|
|
|
|
|
|
|
|
|
this._active = true
|
|
|
|
|
|
|
|
|
|
bind(document, 'mousemove', mousemoveFn)
|
|
|
|
|
bind(document, 'mouseup', mouseupFn)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
this._xBarFn = bind(this.$refs.x, 'mousedown', ev => {
|
|
|
|
|
startX = ev.pageX
|
|
|
|
|
this._active = true
|
|
|
|
|
|
|
|
|
|
bind(document, 'mousemove', mousemoveFn)
|
|
|
|
|
bind(document, 'mouseup', mouseupFn)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
this.__observer = new ResizeObserver(this.__init__.bind(this))
|
|
|
|
|
this.__observer.observe(this.$refs.cont)
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
this.__observer.disconnect()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
return html`
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div class="wrapper" ref="box">
|
|
|
|
|
<div class="content" ref="cont"><slot></slot></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="is-horizontal">
|
|
|
|
|
<span ref="x" class="thumb"></span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="is-vertical">
|
|
|
|
|
<span ref="y" class="thumb"></span>
|
|
|
|
|
</div>
|
|
|
|
|
`
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|