<template>
<div
class="ui-scroll scrollbox"
ref="box"
@mousewheel.stop.prevent="handleMouseWheel"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
:style="$store.state.app.device == 'mobile' ? 'overflow:hidden scroll' : ''"
>
<transition name="fade">
<div
:class="['scrollbar', { force: force }]"
ref="bar"
v-show="show"
:style="{ height: barHeight + 'px', width: '5px' }"
@mousedown="handleMouseDown"
></div>
</transition>
<slot></slot>
</div>
</template>
<script setup>
import { nextTick, onMounted, defineEmits } from "vue";
const { proxy } = getCurrentInstance();
const props = defineProps({
scrollbar: {
type: Boolean,
default: false,
},
});
let btn = ref(undefined);
let box = ref(undefined); // 自定义滚动条盒子
let bar = ref(undefined); // 滚动条
let barHeight = ref(100); // 滚动条高度
let ratio = ref(1); // 滚动条偏移率
let force = ref(false); // 滚动条是否被鼠标光标按住
let hover = ref(false); // 鼠标光标是否悬停在盒子上
let show = ref(false); // 是否显示滚动条
const { scrollbar } = toRefs(props);
onMounted(() => {
nextTick(() => {
box = proxy.$refs["box"];
bar = proxy.$refs["bar"];
// show = proxy.$refs["scrollbar"];
show.value = scrollbar.value;
// 滚动条全局可拖动
document.addEventListener("mouseup", handleMouseUp);
document.addEventListener("mousemove", handleMouseMove);
});
});
/**
* 鼠标滚轮事件
* @param {object} e 事件
*/
function handleMouseWheel(e) {
box.scrollTop -= e.wheelDelta / 4;
bar.style.transform =
"translateY(" + (box.scrollTop + box.scrollTop / ratio.value) + "px)";
}
/**
* 鼠标按下
* @param {object} e 事件
*/
function handleMouseDown(e) {
if (e.target === bar) {
box.prevY = e.pageY;
force.value = true;
}
}
/**
* 鼠标按键释放
*/
function handleMouseUp() {
force.value = false;
box.prevY = null;
if (!hover.value) {
show.value = false;
}
}
/**
* 鼠标移动
* @param {object} e 事件
*/
function handleMouseMove(e) {
if (force.value) {
// 阻止默认选中事件(IE下无效)
e.preventDefault();
box.scrollTop += (e.pageY - box.prevY) * ratio.value;
bar.style.transform =
"translateY(" + (box.scrollTop + box.scrollTop / ratio.value) + "px)";
box.prevY = e.pageY;
}
}
/**
* 鼠标光标进入盒子范围
*/
function handleMouseEnter() {
hover.value = true;
if (box.scrollHeight > box.offsetHeight) {
// 修正进度条高度和位置(建议通过事件触发)
barHeight.value = box.offsetHeight ** 2 / box.scrollHeight;
ratio.value =
(box.scrollHeight - box.offsetHeight) / (box.offsetHeight - barHeight.value);
bar.style.transform =
"translateY(" + (box.scrollTop + box.scrollTop / ratio.value) + "px)";
// 显示滚动条
nextTick(() => (show.value = true));
}
}
/**
* 鼠标光标离开盒子范围
*/
function handleMouseLeave() {
hover.value = false;
if (!force.value) {
show.value = false;
}
}
</script>
<style>
.ui-scroll.scrollbox {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.ui-scroll.scrollbox .scrollbar {
width: var(--scrollbar-width);
height: 100%;
background-color: var(--gray);
position: absolute;
right: 0;
border-radius: var(--scrollbar-width) / 2;
transition: transform 0s !important;
border-radius: 8px;
opacity: 0.6;
z-index: 100;
}
.ui-scroll.scrollbox .scrollbar:hover {
background-color: gray;
}
.ui-scroll.scrollbox .scrollbar.force {
background-color: gray;
}
/* // Vue进入离开动画 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
Vue3 滚动盒子组件,scroll,overflow-y:scroll
最新推荐文章于 2024-06-25 10:00:04 发布