zoukankan      html  css  js  c++  java
  • Vue自定义滚动条盒子

    应用开发过程中当web页面的内容过多时则会出现滚动条,而原生的滚动条的样式除了谷歌浏览器外其他的浏览器都不好修改,于是打算自己写一个容器组件,当内容过多时隐藏默认的滚动条显示自定义滚动条(只做了垂直滚动条,懒~)

    先来看看如何引用这个滚动盒子(hd-scroll,注:"hd"是与我相关某个名字的简称)组件,先在app里面填充100个div:

    1 <template>
    2     <div class="container">
    3         <div v-for="i in 100" :key="i">{{ i }}</div>
    4     </div>
    5 </template>

    然后在把container容器的大小限制一下:

    1 <style lang="scss" scoped>
    2     .container {
    3         background-color: whitesmoke;
    4         width: 200px;
    5         height: 400px;
    6     }
    7 </style>

    打开页面,可以看到浏览器右边出现了默认的滚动条,而且我们添加的div元素也超出了container范围。

    解决这个问题的一般方式是在样式里面添加“overflow:auto”属性,再来看一下效果:

    改善了许多,但是滚动条的样式却不好改变,于是现在引入hd-scroll组件:

     1 <template>
     2     <div class="container">
     3         <hd-scroll>
     4             <div v-for="i in 100" :key="i">{{ i }}</div>
     5         </hd-scroll>
     6     </div>
     7 </template>
     8 
     9 <script>
    10 import hdScroll from './components/hdScroll'
    11 
    12 export default {
    13     components: {
    14         hdScroll
    15     }    
    16 }
    17 </script>
    18 
    19 <style lang="scss" scoped>
    20     .container {
    21         background-color: whitesmoke;
    22         width: 200px;
    23         height: 400px;
    24     }
    25 </style>

    在这里需要注意的是用<hd-scroll>标签来包裹住大量的要渲染的元素,同时删除overflow属性,添加了滚动盒子组件后的页面看起来或许是这个样子的:

    ps:鼠标的小黄点是录频工具的,不是页面自带的。。。

    滚动盒子(hd-scroll)的实现方式如下:

      1 <template>
      2     <div class="hd-scroll scrollbox" ref="box" 
      3     @mousewheel.stop.prevent="handleMouseWheel" 
      4     @mouseenter="handleMouseEnter" 
      5     @mouseleave="handleMouseLeave">
      6         <transition name="fade">
      7             <div :class="['scrollbar', { force: force }]" ref="bar" 
      8             v-show="show" :style="{ 'height': barHeight + 'px'}" 
      9             @mousedown="handleMouseDown"></div>
     10         </transition>
     11         <slot></slot>
     12     </div>
     13 </template>
     14 
     15 <script>
     16 export default {
     17     name: 'hdScroll',
     18     data() {
     19         return {
     20             box: undefined, // 自定义滚动条盒子
     21             bar: undefined, // 滚动条
     22             barHeight: 100, // 滚动条高度
     23             ratio: 1,       // 滚动条偏移率
     24             force: false,   // 滚动条是否被鼠标光标按住
     25             hover: false,   // 鼠标光标是否悬停在盒子上
     26             show: false     // 是否显示滚动条
     27         }
     28     },
     29     mounted() {
     30         this.box = this.$refs.box
     31         this.bar = this.$refs.bar
     32         // 滚动条全局可拖动
     33         document.addEventListener('mouseup', this.handleMouseUp)
     34         document.addEventListener('mousemove', this.handleMouseMove)
     35     },
     36     methods: {
     37         /**
     38          * 鼠标滚轮事件
     39          * @param {object} e 事件
     40          */
     41         handleMouseWheel(e) {
     42             this.box.scrollTop -= e.wheelDelta / 4
     43             this.bar.style.transform = 'translateY(' + (this.box.scrollTop + this.box.scrollTop / this.ratio) + 'px)'
     44         },
     45         /**
     46          * 鼠标按下
     47          * @param {object} e 事件
     48          */
     49         handleMouseDown(e) {
     50             if (e.target === this.bar) {
     51                 this.box.prevY = e.pageY
     52                 this.force = true
     53             }
     54         },
     55         /**
     56          * 鼠标按键释放
     57          */
     58         handleMouseUp() {
     59             this.force = false
     60             this.box.prevY = null
     61             if (!this.hover) {
     62                 this.show = false
     63             }
     64         },
     65         /**
     66          * 鼠标移动
     67          * @param {object} e 事件
     68          */
     69         handleMouseMove(e) {
     70             if (this.force) {
     71                 // 阻止默认选中事件(IE下无效)
     72                 e.preventDefault()
     73                 this.box.scrollTop += (e.pageY - this.box.prevY) * this.ratio
     74                 this.bar.style.transform = 'translateY(' + (this.box.scrollTop + this.box.scrollTop / this.ratio) + 'px)'
     75                 this.box.prevY = e.pageY
     76             }
     77         },
     78         /**
     79          * 鼠标光标进入盒子范围
     80          */
     81         handleMouseEnter() {
     82             this.hover = true
     83             if (this.box.scrollHeight > this.box.offsetHeight) {
     84                 // 修正进度条高度和位置(建议通过事件触发)
     85                 this.barHeight = this.box.offsetHeight ** 2 / this.box.scrollHeight
     86                 this.ratio = (this.box.scrollHeight - this.box.offsetHeight) / (this.box.offsetHeight - this.barHeight)
     87                 this.bar.style.transform = 'translateY(' + (this.box.scrollTop + this.box.scrollTop / this.ratio) + 'px)'
     88                 // 显示滚动条
     89                 this.$nextTick(() => this.show = true)
     90             }
     91         },
     92         /**
     93          * 鼠标光标离开盒子范围
     94          */
     95         handleMouseLeave() {
     96             this.hover = false
     97             if (!this.force) {
     98                 this.show = false
     99             }
    100         }
    101     }
    102 }
    103 </script>
    104 
    105 <style lang="scss" scoped>
    106     // 滚动条宽度
    107     $scrollbar- 8px;
    108 
    109     .scrollbox {
    110         width: 100%;
    111         height: 100%;
    112         position: relative;
    113         padding-right: $scrollbar-width;
    114         overflow-y: hidden;
    115     }
    116     .scrollbar {
    117         width: $scrollbar-width;
    118         height: 100%;
    119         background-color: darkgray;
    120         position: absolute;
    121         right: 0;
    122         border-radius: $scrollbar-width / 2;
    123         &:hover {
    124             background-color: gray;
    125         }
    126         &.force {
    127             background-color: gray;
    128         }
    129     }
    130 
    131     // Vue进入离开动画
    132     .fade-enter-active, .fade-leave-active {
    133         transition: opacity .5s;
    134     }
    135     .fade-enter, .fade-leave-to {
    136         opacity: 0;
    137     }
    138 </style>

    在谷歌里鼠标滚轮事件可使用deltaY来控制滚动,不过为了兼容ie,选择了使用wheelDelta来代替,它们之间的关系大约是wheelDelta == -4 * deltaY。在设置滚动条移动的过程中是通过CSS3属性transform,在低版本ie浏览器中可能无法运行,可以考虑使用style.top来代替,不过看网上大神们都是通过两个div容器来隐藏主默认的滚动条,实现方法如下:

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="UTF-8">
     5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     6     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     7     <title>Document</title>
     8     <style>
     9         #app {
    10             width: 200px;
    11             height: 400px;
    12         }
    13     </style>
    14 </head>
    15 <body>
    16     <div id="app">
    17         <div class="out-box">
    18             <div class="inner-box">
    19                 <div class="container">
    20                     <div v-for="i in 100" :key="i">{{ i }}</div>
    21                 </div>
    22             </div>
    23         </div>
    24     </div>
    25     <script src="./vue.min.js"></script>
    26     <script>
    27         new Vue({
    28             el: '#app'
    29         })
    30     </script>
    31 </body>
    32 </html>

    先设置好页面结构,在这里#app是宽度200px, 高度400px的容器,我们需要使内容不溢出的同时隐藏滚动条:

     1 .out-box {
     2     width: 100%;
     3     height: 100%;
     4     position: relative;
     5     overflow: hidden;
     6 }
     7 
     8 .inner-box {
     9     width: 100%;
    10     height: 100%;
    11     position: absolute;
    12     padding-right: 17px;
    13     padding-bottom: 17px;
    14     overflow: auto;
    15 }

    只需要添加两个盒子属性就完成了,很简单吧

    源码下载(需要自己装包):https://files.cnblogs.com/files/viewts/hd-scroll.zip

  • 相关阅读:
    MongoDB,无模式文档型数据库简介
    数据说话:怎样的程序员最抢手?
    猛醒:也许我们一生追求的都错了!
    中国风电生产监控平台界面
    如何跟着趋势去赚钱
    2015年最好的员工心态培养 -- 我们需要把简单的事情做到极致
    什么是程序员的核心竞争力?
    第一篇 技术选型
    .net core 读取配置文件
    .net core nlog记录日志
  • 原文地址:https://www.cnblogs.com/viewts/p/11170517.html
Copyright © 2011-2022 走看看