Vue自定义滚动条盒子

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

以上是 Vue自定义滚动条盒子 的全部内容, 来源链接: utcz.com/z/378760.html

回到顶部