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