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

本文介绍了一个使用Vue.js实现的自定义滚动条组件,该组件能够响应鼠标滚轮事件并调整滚动条的位置,同时支持全局拖动功能。文章详细解释了组件的工作原理,包括如何通过监听不同的鼠标事件来控制滚动条的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

<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>
  export default {
    props: {
      scrollbar:{
        type:Boolean,
        default:false,
      }
    },
    data() {
      return {
        btn: undefined,
        box: undefined, // 自定义滚动条盒子
        bar: undefined, // 滚动条
        barHeight: 100, // 滚动条高度
        ratio: 1, // 滚动条偏移率
        force: false, // 滚动条是否被鼠标光标按住
        hover: false, // 鼠标光标是否悬停在盒子上
        show: false // 是否显示滚动条
      }
    },
    mounted() {
      this.box = this.$refs.box
      this.bar = this.$refs.bar
      this.show=this.scrollbar
      // 滚动条全局可拖动
      document.addEventListener('mouseup', this.handleMouseUp)
      document.addEventListener('mousemove', this.handleMouseMove)
    },
    methods: {


      /**
       * 鼠标滚轮事件
       * @param {object} e 事件
       */
      handleMouseWheel(e) {
        this.box.scrollTop -= e.wheelDelta / 4
        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) {
          this.show = false
        }
      },
      /**
       * 鼠标移动
       * @param {object} e 事件
       */
      handleMouseMove(e) {
        if (this.force) {
          // 阻止默认选中事件(IE下无效)
          e.preventDefault()
          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) {
          this.show = 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: .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 .5s;
  }

  .fade-enter,
  .fade-leave-to {
    opacity: 0;
  }
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值