应用开发过程中当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范围。

vue2 ios滚动条样式修改 vue 自定义滚动条_vue2 ios滚动条样式修改

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

vue2 ios滚动条样式修改 vue 自定义滚动条_ci_02

改善了许多,但是滚动条的样式却不好改变,于是现在引入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属性,添加了滚动盒子组件后的页面看起来或许是这个样子的:

vue2 ios滚动条样式修改 vue 自定义滚动条_ci_03

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 }

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

vue2 ios滚动条样式修改 vue 自定义滚动条_Vue_04

源码下载(需要自己装包):