近期有个项目,由于自带的滚动条太大而且样式不好看,但是需求比较特殊,所以自定义了一个滚动条组件,用于代替浏览器自带滚动条。 需要的朋友可以参考一下,有问题欢迎大佬指出
<template>
<div class="hd-scroll scrollbox" ref="box"
@mousewheel.stop.prevent="handleMouseWheel"
@DOMMouseScroll.stop.prevent="handleFirefoxMouseWheel"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave">
<transition name="fade">
<div :class="['scrollbar', { force: force }]" ref="bar"
v-show="show" :style="{ 'height': barHeight + 'px'}"
@mousedown="handleMouseDown"></div>
</transition>
<div ref="content">
<slot></slot>
</div>
</div>
</template>
<script>
/**
* @author linhonejie
* 共用上传文件组件
* 引入 import { HdScroll } from "@/components";
*
<HdScroll>
<div>content</div>
</HdScroll>
**/
export default {
name: "HdScroll",
props: {
showBar: {
type: Boolean,
default: false
}
},
data () {
return {
box: undefined, // 自定义滚动条盒子
bar: undefined, // 滚动条
barHeight: 50, // 滚动条高度
ratio: 1, // 滚动条偏移率
force: false, // 滚动条是否被鼠标光标按住
hover: false, // 鼠标光标是否悬停在盒子上
show: false // 是否显示滚动条
}
},
mounted () {
if (this.showBar) {
this.show = true;
}
this.box = this.$refs.box;
this.bar = this.$refs.bar;
this.content = this.$refs.content
// 滚动条全局可拖动
document.addEventListener("mouseup", this.handleMouseUp);
document.addEventListener("mousemove", this.handleMouseMove);
},
methods: {
/**
* 鼠标滚轮事件
* @param {object} e 事件
*/
handleMouseWheel (e) {
if (e.wheelDelta < 0) {
if (this.box.offsetHeight + this.box.scrollTop > this.content.offsetHeight) {
return
}
this.box.scrollTop -= e.wheelDelta / 4;
this.bar.style.transform = "translateY(" + (this.box.scrollTop + this.box.scrollTop / this.ratio) + "px)"
} else {
this.box.scrollTop -= e.wheelDelta / 4;
this.bar.style.transform = "translateY(" + (this.box.scrollTop + this.box.scrollTop / this.ratio) + "px)"
}
},
handleFirefoxMouseWheel (e) {
if (e.wheelDelta < 0) {
if (this.box.offsetHeight + this.box.scrollTop > this.content.offsetHeight) {
return
}
this.box.scrollTop -= -(e.detail * 8);
this.bar.style.transform = "translateY(" + (this.box.scrollTop + this.box.scrollTop / this.ratio) + "px)"
} else {
this.box.scrollTop -= -(e.detail * 8);
this.bar.style.transform = "translateY(" + (this.box.scrollTop + this.box.scrollTop / this.ratio) + "px)"
}
},
/**
* 鼠标按下
* @param {object} e 事件
*/
handleMouseDown (e) {
if (e.target === this.bar) {
this.box.prevY = e.pageY;
this.force = true;
}
},
/**
* 鼠标按键释放
*/
handleMouseUp () {
this.force = false;
this.box.prevY = null;
if (!this.hover) {
if (!this.showBar) {
this.show = false;
}
}
},
/**
* 鼠标移动
* @param {object} e 事件
*/
handleMouseMove (e) {
if (this.force) {
// 阻止默认选中事件(IE下无效)
e.preventDefault();
if (e.pageY - this.box.prevY > 0) {
if (this.box.offsetHeight + this.box.scrollTop > this.content.offsetHeight) {
return
}
this.box.scrollTop += (e.pageY - this.box.prevY) * this.ratio;
this.bar.style.transform = "translateY(" + (this.box.scrollTop + this.box.scrollTop / this.ratio) + "px)";
this.box.prevY = e.pageY;
} else {
this.box.scrollTop += (e.pageY - this.box.prevY) * this.ratio;
this.bar.style.transform = "translateY(" + (this.box.scrollTop + this.box.scrollTop / this.ratio) + "px)";
this.box.prevY = e.pageY;
}
}
},
/**
* 鼠标光标进入盒子范围
*/
handleMouseEnter () {
this.hover = true
if (this.box.scrollHeight > this.box.offsetHeight) {
// 修正进度条高度和位置(建议通过事件触发)
this.barHeight = this.box.offsetHeight ** 2 / this.box.scrollHeight;
this.ratio = (this.box.scrollHeight - this.box.offsetHeight) / (this.box.offsetHeight - this.barHeight);
this.bar.style.transform = "translateY(" + (this.box.scrollTop + this.box.scrollTop / this.ratio) + "px)";
// 显示滚动条
this.$nextTick(() => {
this.show = true;
})
}
},
/**
* 鼠标光标离开盒子范围
*/
handleMouseLeave () {
this.hover = false;
if (!this.force) {
if (!this.showBar) {
this.show = false;
}
}
},
/**
* 组件外触发修改scrolltop
*/
setBoxScrollTop (scrollTop) {
this.box.scrollTop = scrollTop;
}
}
}
</script>
<style lang="scss" scoped>
// 滚动条宽度
$scrollbar-width: 6px;
.scrollbox {
width: 100%;
height: 100%;
position: relative;
// padding-right: $scrollbar-width;
overflow-y: hidden;
}
.scrollbar {
width: $scrollbar-width;
// height: 100%;
background-color: rgba($color: #000, $alpha: 0.3);
position: absolute;
right: 0;
border-radius: $scrollbar-width / 2;
&:hover {
background-color: gray;
}
&.force {
background-color: gray;
}
z-index: 2;
}
// Vue进入离开动画
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>