代码拉取完成,页面将自动刷新
同步操作将从 清晨de阳光/x-scrollbar 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
/*!
* x-scrollbar 自定义滚动条插件
* 版本: v2.4.1
* 作者: 清晨的阳光(QQ:765550360)
* 许可: MIT
* https://gitee.com/null_720_0252/x-scrollbar
*/
if (typeof exports === 'object' && typeof module !== 'undefined') {
module.exports = XScrollbar;
} else {
window.XScrollbar = XScrollbar;
}
/**
* @param {*} dom DOM元素
* @param {*} options 选项
*/
function XScrollbar(dom, options) {
this.$container = dom;
if (this.$container.classList.contains('x-scrollbar-container')) return;
// 移动端检测
this.isMobile = window.navigator.userAgent.toLowerCase().indexOf('mobile') != -1;
if (this.isMobile) return;
// 合并配置
var defaultOptions = {
// 禁用Y轴滚动(拨动鼠标滚轮时将作用于X轴)
disabledScrollY: false,
// 响应容器和内容大小改变(自动更新滚动条)
autoUpdate: true,
// 自动隐藏
autoHide: true,
// 阻止向上传递滚动事件
preventDefault: true,
// 平滑滚动
smooth: true
};
this.assign(defaultOptions, options);
this.assign(this, defaultOptions);
// 构造dom
this.$content = this.html2dom('<div class="x-scrollbar__content"></div>');
this.$railX = this.html2dom('<div class="x-scrollbar__rail-x"></div>');
this.$railY = this.html2dom('<div class="x-scrollbar__rail-y"></div>');
this.$thumbX = this.html2dom('<div class="x-scrollbar__thumb-x"></div>');
this.$thumbY = this.html2dom('<div class="x-scrollbar__thumb-y"></div>');
this.$railX.appendChild(this.$thumbX);
this.$railY.appendChild(this.$thumbY);
var childNodes = [];
Array.prototype.forEach.call(this.$container.childNodes, function (node) { childNodes.push(node) });
childNodes.forEach((function (node) { this.$content.appendChild(node); }).bind(this));
this.$container.appendChild(this.$content);
this.$container.appendChild(this.$railX);
this.$container.appendChild(this.$railY);
// 自动隐藏
this.$container.classList.add('x-scrollbar-container');
if (!this.autoHide) this.$container.classList.add('x-scrollbar-keep');
// 绑定事件
this.bindDrag();
this.bindWheel();
this.bindScroll();
// 自动更新
if (this.autoUpdate) {
// 首次自动触发
this.resizeObserver();
} else {
this.update();
}
}
/**
* 设置滑块大小
*/
XScrollbar.prototype.setThumbSize = function () {
// (clientWidth / scrollWidth) = (滑块大小 / clientWidth)
// 最大滑动距离 = clientWidth - 滑块大小
// 最大滚动距离 = scrollWidth - clientWidth
// (滑动距离 / 最大滑动距离) = (滚动距离 / 最大滚动距离)
// 容器大小
this.clientWidth = this.$container.clientWidth;
this.clientHeight = this.$container.clientHeight;
// 内容大小
this.scrollWidth = this.$container.scrollWidth;
this.scrollHeight = this.$container.scrollHeight;
//是否存在滚动条
this.hasXScrollbar = this.scrollWidth > this.clientWidth;
this.hasYScrollbar = this.scrollHeight > this.clientHeight;
//滑块大小
this.thumbXWidth = Math.max((this.clientWidth / this.scrollWidth) * this.clientWidth, 30);
this.thumbYHeight = Math.max((this.clientHeight / this.scrollHeight) * this.clientHeight, 30);
//最大滑动距离
this.thumbXMaxLeft = this.clientWidth - this.thumbXWidth;
this.thumbYMaxTop = this.clientHeight - this.thumbYHeight;
//最大滚动距离
this.maxScrollLeft = this.scrollWidth - this.clientWidth;
this.maxScrollTop = this.scrollHeight - this.clientHeight;
this.$railX.style.display = this.hasXScrollbar ? 'block' : 'none';
this.$railY.style.display = this.hasYScrollbar ? 'block' : 'none';
this.$thumbX.style.width = this.thumbXWidth + 'px';
this.$thumbY.style.height = this.thumbYHeight + 'px';
};
/**
* 拖动
*/
XScrollbar.prototype.bindDrag = function () {
// 是否被拖动选定
var thumbXActive = false;
var thumbYActive = false;
// 上一次的拖动位置
var screenX = null;
var screenY = null;
this.$thumbX.addEventListener('mousedown', (function (e) {
this.$railX.classList.add('x-scrollbar__rail-draging');
thumbXActive = true;
screenX = e.screenX;
}).bind(this));
this.$thumbY.addEventListener('mousedown', (function (e) {
this.$railY.classList.add('x-scrollbar__rail-draging');
thumbYActive = true;
screenY = e.screenY;
}).bind(this));
this.scrollDocumentMouseup = (function (e) {
this.$railX.classList.remove('x-scrollbar__rail-draging');
this.$railY.classList.remove('x-scrollbar__rail-draging');
thumbXActive = false;
thumbYActive = false;
}).bind(this);
document.addEventListener('mouseup', this.scrollDocumentMouseup);
this.scrollDocumentMousemove = (function (e) {
if (!(thumbXActive || thumbYActive)) return;
e.preventDefault();
var axis = null;
var positionValue = null;
var scrollValue = null;
if (thumbXActive) {
var offset = e.screenX - screenX;
screenX = e.screenX;
axis = 'x';
positionValue = Math.max(Math.min((this.left || 0) + offset, this.thumbXMaxLeft), 0);
scrollValue = Number(positionValue / this.thumbXMaxLeft * this.maxScrollLeft);
} else {
var offset = e.screenY - screenY;
screenY = e.screenY;
axis = 'y';
positionValue = Math.max(Math.min((this.top || 0) + offset, this.thumbYMaxTop), 0);
scrollValue = Number(positionValue / this.thumbYMaxTop * this.maxScrollTop);
}
this.scroll(axis, positionValue, scrollValue);
}).bind(this);
document.addEventListener('mousemove', this.scrollDocumentMousemove);
};
/**
* 滚动
*/
XScrollbar.prototype.bindWheel = function () {
var onWheel = (function (e, axis, delta) {
// 将滚动量转为像数值(https://developer.mozilla.org/zh-CN/docs/Web/API/Element/wheel_event)
if (e.deltaMode != 0) {
// 一行默认为40px
delta = delta * 40;
}
delta = parseInt(delta);
var positionValue = null;
var scrollValue = null;
if (axis == 'x') {
scrollValue = Math.max(Math.min((this.scrollLeft || 0) + delta, this.maxScrollLeft), 0);
positionValue = Number(scrollValue / this.maxScrollLeft * this.thumbXMaxLeft);
} else {
scrollValue = Math.max(Math.min((this.scrollTop || 0) + delta, this.maxScrollTop), 0);
positionValue = Number(scrollValue / this.maxScrollTop * this.thumbYMaxTop);
}
// 阻止向上传递 || !(终点)
var over = scrollValue == (axis == 'x' ? this.scrollLeft : this.scrollTop);
if (this.preventDefault || !over) {
e.preventDefault();
e.stopPropagation();
}
// 终点
if(over) return;
if (this.mouseType == null) {
if (Math.abs(delta) < 50) {
// 初始滚动量小于90定义为触控板
this.mouseType = 'touchpad';
} else {
this.mouseType = 'wheel';
}
}
this.scroll(axis, positionValue, scrollValue, (this.smooth && this.mouseType == 'wheel'));
}).bind(this);
this.onWheel = (function (e) {
// e.deltaX 正值向下, 负值向上
if (e.deltaX != 0 && this.hasXScrollbar) {
onWheel(e, 'x', e.deltaX);
}
if (e.deltaY != 0) {
// (shift键被按下 或 禁用Y轴滚动), 作用于x轴
if ((e.deltaX == 0) && (e.shiftKey || this.disabledScrollY) && this.hasXScrollbar) {
onWheel(e, 'x', e.deltaY);
} else if (this.hasYScrollbar) {
onWheel(e, 'y', e.deltaY);
}
}
}).bind(this);
this.$container.addEventListener('wheel', this.onWheel);
};
/**
* 监听滚动事件
* 用于响应从外部设置 scrollLeft/scrollTop 修正滚动条
*/
XScrollbar.prototype.bindScroll = function () {
this.onScroll = (function (e) {
if (this.innerScroll) return;
this.update();
}).bind(this);
this.$container.addEventListener('scroll', this.onScroll);
};
/**
* 滚动、修正滑块
* @param {*} axis
* @param {*} positionValue
* @param {*} scrollValue
* @param {*} smooth = false
*/
XScrollbar.prototype.scroll = function (axis, positionValue, scrollValue, smooth) {
// 起始值
var left = this.left;
var scrollLeft = this.scrollLeft;
var top = this.top;
var scrollTop = this.scrollTop;
// 结束值
if (axis == 'x') {
this.left = positionValue;
this.scrollLeft = scrollValue;
} else {
this.top = positionValue;
this.scrollTop = scrollValue;
}
if (axis == 'x') {
if (this.xRefId) return;
} else {
if (this.yRefId) return;
}
var end = (function () {
if (!(this.xRefId || this.yRefId)) {
requestAnimationFrame((function () { this.innerScroll = false }).bind(this));
}
}).bind(this);
var animate = (function () {
// 从组件内部触发的滚动事件
this.innerScroll = true;
if (axis == 'x') {
left = this.easeout(left, this.left, smooth);
scrollLeft = this.easeout(scrollLeft, this.scrollLeft, smooth);
// 滑块
this.$thumbX.style.left = left + 'px';
// 滚动
this.$container.scrollLeft = scrollLeft;
// 轨道
this.$railX.style.left = scrollLeft + 'px';
this.$railY.style.right = (-scrollLeft) + 'px';
if (Math.abs(scrollLeft - this.scrollLeft) >= 1) {
this.xRefId = requestAnimationFrame(animate);
} else {
this.xRefId = null;
end();
}
} else {
top = this.easeout(top, this.top, smooth);
scrollTop = this.easeout(scrollTop, this.scrollTop, smooth);
this.$thumbY.style.top = top + 'px';
this.$container.scrollTop = scrollTop;
this.$railX.style.bottom = (-scrollTop) + 'px';
this.$railY.style.top = scrollTop + 'px';
if (Math.abs(scrollTop - this.scrollTop) >= 1) {
this.yRefId = requestAnimationFrame(animate);
} else {
this.yRefId = null;
end();
}
}
}).bind(this);
requestAnimationFrame(animate);
};
/**
* 缓动效果
* @param {*} start
* @param {*} end
* @param {*} smooth
* @returns
*/
XScrollbar.prototype.easeout = function (start, end, smooth) {
var v = null;
if (!smooth || (Math.abs(end - start) <= 1)) {
v = end;
} else {
v = start + (end - start) / 4;
}
if ((end - start) > 0) {
return Math.ceil(v);
} else {
return Math.floor(v);
}
};
/**
* 使用滚动值修正滑块
* 在 容器大小 或 内容大小 发生改变时调用
*/
XScrollbar.prototype.update = function () {
if (this.isMobile) return;
// 先重置以更新滚动条的位置
this.$railX.style.display = 'none';
this.$railY.style.display = 'none';
var scrollLeft = this.$container.scrollLeft;
var scrollTop = this.$container.scrollTop;
this.setThumbSize();
var positionLeft = Number(scrollLeft / this.maxScrollLeft * this.thumbXMaxLeft) || 0;
this.scroll('x', positionLeft, scrollLeft);
var positionTop = Number(scrollTop / this.maxScrollTop * this.thumbYMaxTop) || 0;
this.scroll('y', positionTop, scrollTop);
};
/**
* 响应容器和内容大小改变, 自动更新滚动条
*/
XScrollbar.prototype.resizeObserver = function () {
if (typeof ResizeObserver != 'undefined') {
this.$resizeObserver = new ResizeObserver((function (entries) {
var contentRect = entries[0].contentRect;
if (!(contentRect.width || contentRect.height)) return;
this.update();
}).bind(this));
this.$resizeObserver.observe(this.$container);
this.$resizeObserver.observe(this.$content);
return;
}
var containerRect = this.$container.getBoundingClientRect();
var contentRect = this.$content.getBoundingClientRect();
var resizeObserver = (function () {
var _containerRect = this.$container.getBoundingClientRect();
var _contentRect = this.$content.getBoundingClientRect();
if ((containerRect.width != _containerRect.width) || (containerRect.height != _containerRect.height) || (contentRect.width != _contentRect.width) || (contentRect.height != _contentRect.height)) {
this.update();
}
containerRect = _containerRect;
contentRect = _contentRect;
this.resizeObserverReqId = requestAnimationFrame(resizeObserver);
}).bind(this);
requestAnimationFrame(resizeObserver);
this.update();
};
/**
* 销毁
*/
XScrollbar.prototype.destroy = function () {
if (!this.$container.classList.contains('x-scrollbar-container')) return;
if (this.isMobile) return;
if (this.$resizeObserver) {
this.$resizeObserver.disconnect();
}
if (this.resizeObserverReqId) {
cancelAnimationFrame(this.resizeObserverReqId);
}
this.$container.classList.remove('x-scrollbar-container');
this.$container.classList.remove('x-scrollbar-keep');
var childNodes = [];
Array.prototype.forEach.call(this.$content.childNodes, function (node) { childNodes.push(node) });
childNodes.forEach((function (node) { this.$container.appendChild(node) }).bind(this));
this.$container.removeChild(this.$content);
this.$container.removeChild(this.$railX);
this.$container.removeChild(this.$railY);
document.removeEventListener('mouseup', this.scrollDocumentMouseup);
document.removeEventListener('mousemove', this.scrollDocumentMousemove);
this.$container.removeEventListener('wheel', this.onWheel);
this.$container.removeEventListener('scroll', this.onScroll);
};
/**
* html 转 dom
* @param {*} html
* @returns
*/
XScrollbar.prototype.html2dom = function (html) {
var element = document.createElement('div');
element.innerHTML = html;
var children = element.children;
if (children.length <= 1) {
return children[0];
} else {
return children;
}
};
/**
* 合并配置
* @param {*} target
* @param {*} source
* @returns
*/
XScrollbar.prototype.assign = function (target, source) {
target = target || {};
source = source || {};
for (key in source) {
target[key] = source[key];
}
return target;
};
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。