parent
226a2145c4
commit
7c79afd0d1
@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<transition name="fade">
|
||||||
|
<div
|
||||||
|
v-show="show"
|
||||||
|
id="scrollbar"
|
||||||
|
:class="{ 'on-drag': isOnDrag }"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
id="thumbContainer"
|
||||||
|
:class="{ active }"
|
||||||
|
:style="thumbStyle"
|
||||||
|
@mouseenter="handleMouseenter"
|
||||||
|
@mouseleave="handleMouseleave"
|
||||||
|
@mousedown="handleDragStart"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Scrollbar',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
top: 0,
|
||||||
|
thumbHeight: 0,
|
||||||
|
active: false,
|
||||||
|
show: false,
|
||||||
|
hideTimer: null,
|
||||||
|
isOnDrag: false,
|
||||||
|
onDragClientY: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
thumbStyle() {
|
||||||
|
return {
|
||||||
|
transform: `translateY(${this.top}px)`,
|
||||||
|
height: `${this.thumbHeight}px`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
main() {
|
||||||
|
return this.$parent.$refs.main;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.$router.beforeEach((to, from, next) => {
|
||||||
|
this.show = false;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleScroll() {
|
||||||
|
const clintHeight = this.main.clientHeight - 128;
|
||||||
|
const scrollHeight = this.main.scrollHeight - 128;
|
||||||
|
const scrollTop = this.main.scrollTop;
|
||||||
|
let top = ~~((scrollTop / scrollHeight) * clintHeight);
|
||||||
|
let thumbHeight = ~~((clintHeight / scrollHeight) * clintHeight);
|
||||||
|
|
||||||
|
if (thumbHeight < 24) thumbHeight = 24;
|
||||||
|
if (top > clintHeight - thumbHeight) {
|
||||||
|
top = clintHeight - thumbHeight;
|
||||||
|
}
|
||||||
|
this.top = top;
|
||||||
|
this.thumbHeight = thumbHeight;
|
||||||
|
|
||||||
|
if (!this.show && clintHeight !== thumbHeight) this.show = true;
|
||||||
|
this.setScrollbarHideTimeout();
|
||||||
|
},
|
||||||
|
handleMouseenter() {
|
||||||
|
this.active = true;
|
||||||
|
},
|
||||||
|
handleMouseleave() {
|
||||||
|
this.active = false;
|
||||||
|
this.setScrollbarHideTimeout();
|
||||||
|
},
|
||||||
|
handleDragStart(e) {
|
||||||
|
this.onDragClientY = e.clientY;
|
||||||
|
this.isOnDrag = true;
|
||||||
|
this.$parent.userSelectNone = true;
|
||||||
|
document.addEventListener('mousemove', this.handleDragMove);
|
||||||
|
document.addEventListener('mouseup', this.handleDragEnd);
|
||||||
|
},
|
||||||
|
handleDragMove(e) {
|
||||||
|
if (!this.isOnDrag) return;
|
||||||
|
const clintHeight = this.main.clientHeight - 128;
|
||||||
|
const scrollHeight = this.main.scrollHeight - 128;
|
||||||
|
const clientY = e.clientY;
|
||||||
|
const scrollTop = this.main.scrollTop;
|
||||||
|
const offset = ~~(
|
||||||
|
((clientY - this.onDragClientY) / clintHeight) *
|
||||||
|
scrollHeight
|
||||||
|
);
|
||||||
|
this.top = ~~((scrollTop / scrollHeight) * clintHeight);
|
||||||
|
this.main.scrollBy(0, offset);
|
||||||
|
this.onDragClientY = clientY;
|
||||||
|
},
|
||||||
|
handleDragEnd() {
|
||||||
|
this.isOnDrag = false;
|
||||||
|
this.$parent.userSelectNone = false;
|
||||||
|
document.removeEventListener('mousemove', this.handleDragMove);
|
||||||
|
document.removeEventListener('mouseup', this.handleDragEnd);
|
||||||
|
},
|
||||||
|
handleClick() {
|
||||||
|
this.main.scrollBy({
|
||||||
|
top: 256,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setScrollbarHideTimeout() {
|
||||||
|
if (this.hideTimer !== null) clearTimeout(this.hideTimer);
|
||||||
|
this.hideTimer = setTimeout(() => {
|
||||||
|
if (!this.active) this.show = false;
|
||||||
|
this.hideTimer = null;
|
||||||
|
}, 4000);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#scrollbar {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 16px;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
#thumbContainer {
|
||||||
|
margin-top: 64px;
|
||||||
|
div {
|
||||||
|
transition: background 0.4s;
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
width: 8px;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(128, 128, 128, 0.38);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#thumbContainer.active div {
|
||||||
|
background: rgba(128, 128, 128, 0.58);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] {
|
||||||
|
#thumbContainer div {
|
||||||
|
background: var(--color-secondary-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#scrollbar.on-drag {
|
||||||
|
left: 0;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
.fade-enter,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in new issue