参照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;

vue自定义滚动条的更多相关文章

  1. vue-gemini-scrollbar(vue组件-自定义滚动条)

    vue-gemini-scrollbar(vue组件-自定义滚动条) https://segmentfault.com/a/1190000013338560

  2. Vue.js 桌面端自定义滚动条组件|vue美化滚动条VScroll

    基于vue.js开发的小巧PC端自定义滚动条组件VScroll. 前段时间有给大家分享一个vue桌面端弹框组件,今天再分享最近开发的一个vue pc端自定义滚动条组件. vscroll 一款基于vue ...

  3. vue自定义可输入的选择框组件

    vue自定义可输入的选择框组件 props: 属性 说明 类型 默认值 selectDataList 下拉框中的内容 Array 空数组([]) value 输入框中的内容 String 空字符串(& ...

  4. uniapp以及微信小程序中scroll-view隐藏滚动条 自定义滚动条

    隐藏滚动条 1.全局隐藏滚动条,在app.vue中 ::-webkit-scrollbar{ display: none; } 2.局部隐藏藏滚动条 样式没有使用scoped属性时, 否则无效. .u ...

  5. CSS3自定义滚动条样式 -webkit-scrollbar(转)

    有没有觉得浏览器自带的原始滚动条很不美观,同时也有看到很多网站的自定义滚动条显得高端,就连chrome32.0开发板都抛弃了原始的滚动条,美观多了.那webkit浏览器是如何自定义滚动条的呢? 前言 ...

  6. vue自定义指令

    Vue自定义指令: Vue.directive('myDr', function (el, binding) { el.onclick =function(){ binding.value(); } ...

  7. jquery自定义滚动条 鼠标移入或滚轮时显示 鼠标离开或悬停超时时隐藏

    一.需求: 我需要做一个多媒体播放页面,左侧为播放列表,右侧为播放器.为了避免系统滚动条把列表和播放器隔断开,左侧列表的滚动条需要自定义,并且滚动停止和鼠标离开时要隐藏掉. 二.他山之石: 案例来自h ...

  8. 利用JS实现自定义滚动条

    一般默认的滚动条会比较丑,我们可以用简单的js实现自定义滚动条的功能: 代码如下: <!doctype html> <html> <head> <meta c ...

  9. javascript 学习之自定义滚动条加滚轮事件

    要自己写一个自定义滚动条加上滚轮事件,之前的没有滚轮事件不完整,今天整理了一个. 1.滚轮事件是不兼容的,firefox中是必需要用事件绑定的添加,用的DOMMouseScroll,当滚动鼠标的时候, ...

随机推荐

  1. VB VB 定义及区别

    VB是Visual Basic的简称,是由美国微软公司于1991年开发的一种可视化的.面向对象和采用事件驱动方式的结构化高级程序设计语言,可用于开发 Windows 环境下的各类应用程序.VC是Vis ...

  2. mysql表关联

    mysql的表关联: left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录 inner ...

  3. 关于Jupyter Notebook快捷操作

    Jupyter Notebook 的快捷键 Jupyter Notebook 有两种键盘输入模式.编辑模式,允许你往单元中键入代码或文本:这时的单元框线是绿色的.命令模式,键盘输入运行程序命令:这时的 ...

  4. Python unittest discover()方法与执行顺序补充

    一.discover更多测试用例 可以根据不同的功能创建不同的测试文件,甚至是不同的测试目录,测试文件中还可以将不同的小功能划分为不同的测试类,在类下编写测试用例,让整体结构更加清晰 但通过addTe ...

  5. 微信小程序报错:id 属性值格式错误。如不能以数字开头。

    出现这个报错时,相信很多人都排除过自己标签上写的id是否有以数字命名的,如果你排除了发现并没有,但是这个报错还是存在,那么我接下来分享的这个情况或者能报到你 这次我也遇到这个报错,最终找出问题所在 这 ...

  6. java基础回忆、复习(一)

    一:浅拷贝与深拷贝: 对于基本数据类型,直接进行拷贝,String类型,有两种拷贝方式: 1:直接将原对象中的name的引用值拷贝给新对象的name字段.<浅拷贝> 2:根据原对象中的na ...

  7. 基于bootstrap table配置的二次封装

    准备 jQuery js css 引用完毕 开始 如果对bootstrap table 的方法与事件不熟悉: Bootstrap table方法,Bootstrap table事件 <table ...

  8. lvs+keepalived+ipvsadm 完整搭建笔记

    原文:http://www.safecdn.cn/2018/12/lvs-keepalived-ipvsadm/ 1.环境介绍: 系统:centos 6.7 keepalived VIP1 :10.0 ...

  9. 在Airtest中如何使用无线模式控制手机

    在使用Airtest超快速开发App爬虫文章的最后,我们留了一个尾巴:如何启动Airtest的无线模式,不用USB线就能控制手机? 本文将会讲到具体的做法.做法分为两种:第一种是在Airtest的ID ...

  10. stm32 HAL库笔记(一)——串口的操作

    昨天分析了普通io口的使用,和初始化代码流程,回顾一下,首先定义一个配置io口功能的结构体,然后开启时钟,再去配置这个结构体里面的各个成员变量,每个成员变量都有很多种选择,可以看各个成员变量 后面的注 ...