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-width: 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM