Vue3 滚动盒子组件,scroll,overflow-y:scroll

在这里插入图片描述

<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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值