参照element-ui的el-scroll自己实现了一个自定义组件,代码如下:
<template> <div class="c-scroll-box" ref="scrollBox" unselectable="on" onselectstart="return false;" style="-moz-user-select:none;"> <div class="c-scroll-container" @scroll="containerScroll" ref="scrollContainer"> <div class="c-scroll-view" ref="scrollViewBox"> <slot></slot> </div> </div> <!-- 右侧滚动条 --> <div class="c-scroll-vertical-box c-scroll-bar" :style="verticalStyle" ref="verticalBox" @mousedown="vBoxDown"></div> <!-- 下方滚动条 --> <!-- <div class="c-scroll-horizontal-box c-scroll-bar" :style="horizontalStyle" ref="horizontalBox"></div> --> </div> </template> <script> import { domResize } from "./domResize.js"; export default { data() { return { verticalStyle: { height: "60px", top: 0, transform: 'translateY(0)' }, horizontalStyle: { width: "10px", left: 0 }, viewHeight: 0, viewWidth: 0, vBarPageY: 0, vBarTranslateY: 0, hBarPageX: 0, vMouseFlag: false }; }, watch: {}, mounted() { this.domResizeListener(); }, methods: { /** * @name vBoxDown * @description 竖直滚动条鼠标按下 * @author cjs1992 * @date 2018-10-25 13:57 */ vBoxDown(event) { document.removeEventListener("mousemove", this.vBoxMove); document.removeEventListener("mouseup", this.vBoxUp); this.vBarPageY = event.pageY; this.vMouseFlag = true; document.addEventListener("mousemove", this.vBoxMove); document.addEventListener("mouseup", this.vBoxUp); }, /** * @name vBoxUp * @description 竖直滚动条鼠标放开 * @author cjs1992 * @date 2018-10-25 13:57 */ vBoxUp(event) { event.preventDefault(); event.stopPropagation() this.vMouseFlag = false; }, /** * @name vBoxMove * @description 竖直滚动条鼠标移动 * @author cjs1992 * @date 2018-10-25 13:57 */ vBoxMove(event) { if (!this.vMouseFlag) { return; } let scrollBox = this.$refs.scrollBox; let verticalBox = this.$refs.verticalBox; let scrollContainer = this.$refs.scrollContainer; let scrollViewBox = this.$refs.scrollViewBox; let num = event.pageY - this.vBarPageY; this.vBarPageY = event.pageY; // let t_top = parseFloat(this.verticalStyle.top) + num; /**>>>> */ let t_top = parseFloat(this.vBarTranslateY) + num; let max_top = scrollBox.clientHeight - parseFloat(this.verticalStyle.height); // 判断是否超出滚动范围 if (t_top <= 0) { t_top = 0; } else if (max_top <= t_top) { t_top = max_top; } // this.verticalStyle.top = t_top + "px"; /**>>>>>> */ this.verticalStyle.transform = "translateY(" + t_top + "px)"; this.vBarTranslateY = t_top; if (scrollContainer.scrollTo) { scrollContainer.scrollTo( this.horizontalStyle.left, (t_top * scrollViewBox.clientHeight) / scrollBox.clientHeight ); } else { scrollContainer.scrollTop = (t_top * scrollViewBox.clientHeight) / scrollBox.clientHeight; } }, /** * @name containerScroll * @description scroll */ containerScroll() { let scrollContainer = this.$refs.scrollContainer; let scrollBox = this.$refs.scrollBox; let scrollViewBox = this.$refs.scrollViewBox; // this.verticalStyle.top = // (scrollBox.clientHeight * scrollContainer.scrollTop) / // scrollViewBox.clientHeight + // "px"; /**>>>>>> */ this.verticalStyle.transform = "translateY(" + (scrollBox.clientHeight * scrollContainer.scrollTop) / scrollViewBox.clientHeight + "px)"; this.vBarTranslateY = (scrollBox.clientHeight * scrollContainer.scrollTop) / scrollViewBox.clientHeight; }, /** * @name setBarHeight * @description 获取滚动条高度 * @author cjs1992 * @date 2018-10-25 10:56 */ setBarHeight() { let scrollBox = this.$refs.scrollBox; let scrollViewBox = this.$refs.scrollViewBox; let scrollContainer = this.$refs.scrollContainer; // 滚动条的高度 let rate = scrollBox.clientHeight / scrollViewBox.clientHeight; if (rate >= 1) { this.verticalStyle.height = 0; } else { this.verticalStyle.height = scrollBox.clientHeight * rate + "px"; // 计算滚动条的位置 // this.verticalStyle.top = // (scrollBox.clientHeight * scrollContainer.scrollTop) / // scrollViewBox.clientHeight + // "px"; /**>>>>>> */ this.verticalStyle.transform = "translateY(" + (scrollBox.clientHeight * scrollContainer.scrollTop) / scrollViewBox.clientHeight + "px)"; this.vBarTranslateY = (scrollBox.clientHeight * scrollContainer.scrollTop) / scrollViewBox.clientHeight; } }, /** * @name domResizeListener * @description dom元素的resize方法 * @author cjs1992 * @date 2018-10-25 11:34 * */ domResizeListener() { domResize(this.$refs.scrollViewBox, ele => { if (ele) { let { contentRect: cont } = ele; if (cont.height !== this.viewHeight) { this.viewHeight = cont.height; this.verticalBarChange(); } else if (cont.width !== this.viewWidth) { } } }); }, /** * @name verticalVBarChange * @description 右侧滚动条变化事件 */ verticalBarChange() { this.setBarHeight(); }, /** * @name horizontalBarChange * @description 底部滚动条变化事件 */ horizontalBarChange() { console.log(this.viewWidth); } } }; </script> <style scoped> .c-scroll-box { /* width: 100%; */ height: 100%; overflow: hidden; box-sizing: border-box; position: relative; } .c-scroll-container { /* width: 100%; */ /*请注意,这里不能width: 100%;如果需要设置margin-right: -17px的话*/ height: 100%; margin-right: -17px; margin-bottom: -17px; margin-top: 0; overflow: scroll; overflow-x: hidden; } .c-scroll-view { width: 100%; } .c-scroll-bar { position: absolute; border-radius: 5px; z-index: 1; background: #70ad47; } /* 竖直滚动条 */ div.c-scroll-vertical-box { width: 10px; right: 2px; } div.c-scroll-horizontal-box { height: 10px; } </style>
domResize.js 如下:
import ResizeObserver from 'resize-observer-polyfill'; const listeners = (entries) => { for (let item of entries) { if (item.target && item.target.resizeListeners && item.target.resizeListeners.length) { for (let func of item.target.resizeListeners) { func(item); } } } } export const domResize = (ele, func) => { if (!ele.resizeListeners) { ele.resizeListeners = []; const myObserver = new ResizeObserver(listeners); myObserver.observe(ele); } ele.resizeListeners.push(func); }
这里的domResize.js是element官方实现的,目的是为了监测一个容器大小发生变化,其实还在网上找到了另一种实现思路(也可以实现监听容器尺寸发生变化),代码如下:
/** * Created by taozh on 2017/5/6. * taozh1982@gmail.com */ var EleResize = { _handleResize: function (e) { var ele = e.target || e.srcElement; var trigger = ele.__resizeTrigger__; if (trigger) { var handlers = trigger.__z_resizeListeners; if (handlers) { var size = handlers.length; for (var i = 0; i < size; i++) { var h = handlers[i]; var handler = h.handler; var context = h.context; handler.apply(context, [e]); } } } }, _removeHandler: function (ele, handler, context) { var handlers = ele.__z_resizeListeners; if (handlers) { var size = handlers.length; for (var i = 0; i < size; i++) { var h = handlers[i]; if (h.handler === handler && h.context === context) { handlers.splice(i, 1); return; } } } }, _createResizeTrigger: function (ele) { var obj = document.createElement('object'); obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;'); obj.onload = EleResize._handleObjectLoad; obj.type = 'text/html'; ele.appendChild(obj); obj.data = 'about:blank'; return obj; }, _handleObjectLoad: function (evt) { this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; this.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize); } }; if (document.attachEvent) {//ie9-10 EleResize.on = function (ele, handler, context) { var handlers = ele.__z_resizeListeners; if (!handlers) { handlers = []; ele.__z_resizeListeners = handlers; ele.__resizeTrigger__ = ele; ele.attachEvent('onresize', EleResize._handleResize); } handlers.push({ handler: handler, context: context }); }; EleResize.off = function (ele, handler, context) { var handlers = ele.__z_resizeListeners; if (handlers) { EleResize._removeHandler(ele, handler, context); if (handlers.length === 0) { ele.detachEvent('onresize', EleResize._handleResize); delete ele.__z_resizeListeners; } } } } else { EleResize.on = function (ele, handler, context) { var handlers = ele.__z_resizeListeners; if (!handlers) { handlers = []; ele.__z_resizeListeners = handlers; if (getComputedStyle(ele, null).position === 'static') { ele.style.position = 'relative'; } var obj = EleResize._createResizeTrigger(ele); ele.__resizeTrigger__ = obj; obj.__resizeElement__ = ele; } handlers.push({ handler: handler, context: context }); }; EleResize.off = function (ele, handler, context) { var handlers = ele.__z_resizeListeners; if (handlers) { EleResize._removeHandler(ele, handler, context); if (handlers.length === 0) { var trigger = ele.__resizeTrigger__; if (trigger) { trigger.contentDocument.defaultView.removeEventListener('resize', EleResize._handleResize); ele.removeChild(trigger); delete ele.__resizeTrigger__; } delete ele.__z_resizeListeners; } } } } export default EleResize;