vue-scrollbar-live
Version:
A vue scrollbar component, support SSR.
627 lines (544 loc) • 17.9 kB
JavaScript
/**
* Bundle of vue-scrollbar-live
* Generated: 2020-05-19
* Version: 5.7.1
* License: MIT
* Author: 2631541504@qq.com
*/
import { DragMove, Utils } from '@livelybone/mouse-events';
import { getNativeScrollbarWidth } from '@livelybone/scroll-get';
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(source, true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(source).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
var scrollbarType = {
x: {
posPropName: 'left',
parentScrollPos: 'scrollLeft',
deltaName: 'deltaX',
sizeName: 'width'
},
y: {
posPropName: 'top',
parentScrollPos: 'scrollTop',
deltaName: 'deltaY',
sizeName: 'height'
}
};
var showStyle = {
opacity: 1,
pointerEvents: 'initial'
};
var script = {
name: 'Bar',
props: {
type: String,
parentScroll: Number,
marginToWrap: {
type: Number,
default: 5
},
clientSize: Number,
scrollSize: Number
},
data: function data() {
return {
sPosition: 0,
showBar: false,
unbind: null,
startPosition: 0
};
},
computed: {
$_show: function $_show() {
return this.scrollSize > this.clientSize;
},
$_scrollbarType: function $_scrollbarType() {
return scrollbarType[this.type];
},
size: function size() {
return this.clientSize / this.scrollSize * this.clientSize - this.marginToWrap * 2;
},
positionRange: function positionRange() {
return {
min: this.marginToWrap,
max: this.clientSize - this.marginToWrap - this.size
};
},
$_barStyle: function $_barStyle() {
var _objectSpread2$1;
return _objectSpread2({}, this.showBar ? showStyle : {}, (_objectSpread2$1 = {}, _defineProperty(_objectSpread2$1, this.$_scrollbarType.posPropName, "".concat(this.sPosition, "px !important")), _defineProperty(_objectSpread2$1, this.$_scrollbarType.sizeName, "".concat(this.size, "px !important")), _defineProperty(_objectSpread2$1, "userSelect", 'none'), _objectSpread2$1));
}
},
watch: {
$_show: {
handler: function handler(val) {
var _this = this;
this.$nextTick(function () {
if (_this.unbind) _this.unbind();
if (val && typeof window !== 'undefined' && _this.$el) {
_this.unbind = DragMove.bind(_this.$el, _this.drag);
}
});
},
immediate: true
},
parentScroll: {
handler: function handler(val) {
this.sPosition = (this.positionRange.max - this.positionRange.min) / (this.scrollSize - this.clientSize) * val + this.positionRange.min;
},
immediate: true
}
},
methods: {
drag: function drag(ev) {
ev.originalEvent.preventDefault();
if (ev.type === 'dragMoveStart') this.startPosition = this.sPosition;
var position = Math.min(this.positionRange.max, Math.max(this.positionRange.min, this.startPosition + ev[this.$_scrollbarType.deltaName]));
this.$emit('scrollTo', _defineProperty({}, this.$_scrollbarType.parentScrollPos, (position - this.marginToWrap) / (this.positionRange.max - this.marginToWrap) * (this.scrollSize - this.clientSize)));
this.showBar = ev.type !== 'dragMoveEnd';
}
},
beforeDestroy: function beforeDestroy() {
if (this.unbind) this.unbind();
}
};
function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier
/* server only */
, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
if (typeof shadowMode !== 'boolean') {
createInjectorSSR = createInjector;
createInjector = shadowMode;
shadowMode = false;
} // Vue.extend constructor export interop.
var options = typeof script === 'function' ? script.options : script; // render functions
if (template && template.render) {
options.render = template.render;
options.staticRenderFns = template.staticRenderFns;
options._compiled = true; // functional template
if (isFunctionalTemplate) {
options.functional = true;
}
} // scopedId
if (scopeId) {
options._scopeId = scopeId;
}
var hook;
if (moduleIdentifier) {
// server build
hook = function hook(context) {
// 2.3 injection
context = context || // cached call
this.$vnode && this.$vnode.ssrContext || // stateful
this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; // functional
// 2.2 with runInNewContext: true
if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
context = __VUE_SSR_CONTEXT__;
} // inject component styles
if (style) {
style.call(this, createInjectorSSR(context));
} // register component module identifier for async chunk inference
if (context && context._registeredComponents) {
context._registeredComponents.add(moduleIdentifier);
}
}; // used by ssr in case component is cached and beforeCreate
// never gets called
options._ssrRegister = hook;
} else if (style) {
hook = shadowMode ? function () {
style.call(this, createInjectorShadow(this.$root.$options.shadowRoot));
} : function (context) {
style.call(this, createInjector(context));
};
}
if (hook) {
if (options.functional) {
// register for functional component in vue file
var originalRender = options.render;
options.render = function renderWithStyleInjection(h, context) {
hook.call(context);
return originalRender(h, context);
};
} else {
// inject component registration as beforeCreate hook
var existing = options.beforeCreate;
options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
}
}
return script;
}
var normalizeComponent_1 = normalizeComponent;
/* script */
var __vue_script__ = script;
/* template */
var __vue_render__ = function __vue_render__() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _c('div', {
directives: [{
name: "show",
rawName: "v-show",
value: _vm.$_show,
expression: "$_show"
}],
staticClass: "scrollbar",
class: 'scrollbar-' + _vm.type,
style: _vm.$_barStyle,
attrs: {
"draggable": false
}
});
};
var __vue_staticRenderFns__ = [];
/* style */
var __vue_inject_styles__ = undefined;
/* scoped */
var __vue_scope_id__ = undefined;
/* module identifier */
var __vue_module_identifier__ = undefined;
/* functional template */
var __vue_is_functional_template__ = false;
/* style inject */
/* style inject SSR */
var Bar = normalizeComponent_1({
render: __vue_render__,
staticRenderFns: __vue_staticRenderFns__
}, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, undefined, undefined);
// eslint-disable-next-line import/no-extraneous-dependencies
function listenDomChange(comp, cb) {
if ('MutationObserver' in window) {
var observer = new MutationObserver(function (records) {
var childrenChangeExceptScrollbar = records.some(function (r) {
var target = r.target;
if (comp.$el.contains(target)) {
if (!(target instanceof Element)) return true;
var className = target.className;
return !/^scrollbar\s/.test(className);
}
return target.contains(comp.$el);
});
if (childrenChangeExceptScrollbar) cb();
});
observer.observe(document.body, {
attributes: true,
childList: true,
subtree: true
});
return function () {
observer.disconnect();
};
} // If MutationObserver is not available, use updated lifecycle of Vue to call the cb
// This will bring up a problem that the width/height data cannot be calculated at the right time in a async render scene
comp.$on('hook:updated', cb);
return function () {};
}
function insertStyle() {
var id = 'vue-scrollbar-live-module-style';
var styleExist = document.getElementById(id);
if (!styleExist) {
var style = document.createElement('style');
style.id = id;
style.innerText = '.scrollbar-wrap .scrollbar-content::-webkit-scrollbar{width:0;height:0;}' + '.scrollbar-wrap .scrollbar-content{-ms-overflow-style:none;scrollbar-width:none;}' + '.scrollbar-wrap .scrollbar{position:absolute;border-radius:.25em;background:#eee;box-shadow:0 0 2px rgba(0,0,0,0.1);opacity:0;pointer-events:none}' + '.scrollbar-wrap .scrollbar-y{right:0.25em;width:.5em}' + '.scrollbar-wrap .scrollbar-x{bottom:0.25em;height:.5em}' + '.scrollbar-wrap:hover .scrollbar{opacity:1;pointer-events:initial}';
document.head.appendChild(style);
}
}
//
var script$1 = {
name: 'Scrollbar',
components: {
Bar: Bar
},
props: {
isMobile: Boolean,
maxHeight: [Number, String],
scrollTo: [Number, Object],
marginToWrap: {
default: 5,
type: Number
}
},
data: function data() {
return {
width: {
parent: 0,
content: 0,
contentInner: 0
},
height: {
parent: 0,
content: 0,
contentInner: 0
},
scrollPos: {
scrollLeft: 0,
scrollTop: 0
},
isTop: true,
isBottom: true,
isLeft: true,
isRight: true,
nativeScrollbarWidth: {
x: 0,
y: 0
}
};
},
computed: {
scrollbars: function scrollbars() {
return {
x: {
scrollPropName: 'scrollLeft',
size: this.width
},
y: {
scrollPropName: 'scrollTop',
size: this.height
}
};
},
$_maxHeight: function $_maxHeight() {
var _this = this;
if (typeof this.maxHeight === 'number') return "".concat(this.maxHeight, "px");
if (/%/.test(this.maxHeight)) {
return this.maxHeight.replace(/(\d+)%/g, function (m, percent) {
return "".concat(_this.height.parent * percent / 100, "px");
});
}
return this.maxHeight;
},
$_wrapStyle: function $_wrapStyle() {
return {
position: 'relative',
height: this.isMobile ? 'auto !important' : "".concat(this.height.content, "px !important"),
maxHeight: "".concat(this.$_maxHeight, " !important"),
padding: '0 !important',
overflow: 'hidden !important'
};
},
$_contentStyle: function $_contentStyle() {
if (this.isMobile) {
return {
maxHeight: this.$_maxHeight,
overflow: 'scroll'
};
}
var _this$nativeScrollbar = this.nativeScrollbarWidth,
x = _this$nativeScrollbar.x,
y = _this$nativeScrollbar.y;
return {
width: "calc(100% + ".concat(y, "px) !important"),
maxHeight: "calc(".concat(this.$_maxHeight.replace(/(^calc\()|(\)$)/g, ''), " + ").concat(x, "px) !important"),
overflow: 'scroll'
};
},
maxScroll: function maxScroll() {
return {
scrollLeft: this.width.contentInner - this.width.content,
scrollTop: this.height.contentInner - this.height.content
};
}
},
watch: {
scrollTo: {
handler: function handler(val) {
this.$scrollTo(val);
},
immediate: true
},
isBottom: function isBottom(val) {
if (val) this.$emit('reachBottom');
},
isTop: function isTop(val) {
if (val) this.$emit('reachTop');
},
isLeft: function isLeft(val) {
if (val) this.$emit('reachLeft');
},
isRight: function isRight(val) {
if (val) this.$emit('reachRight');
}
},
methods: {
updateScrollbarWidth: function updateScrollbarWidth() {
this.nativeScrollbarWidth = getNativeScrollbarWidth(this.$refs.content);
},
updateHeight: function updateHeight() {
if (!this.$refs.content || typeof window === 'undefined') return;
var _this$$refs$content = this.$refs.content,
scrollHeight = _this$$refs$content.scrollHeight,
clientHeight = _this$$refs$content.clientHeight,
scrollWidth = _this$$refs$content.scrollWidth,
clientWidth = _this$$refs$content.clientWidth;
this.height.content = clientHeight;
this.height.contentInner = scrollHeight;
this.height.parent = this.$refs.wrap.parentElement.clientHeight;
this.width.content = clientWidth;
this.width.contentInner = scrollWidth;
this.width.parent = this.$refs.wrap.parentElement.clientWidth;
},
getHeight: function getHeight() {
this.updateHeight();
},
$scrollTo: function $scrollTo(val) {
var _this2 = this;
this.$nextTick(function () {
if (val !== undefined && val !== null) {
var pos = {
scrollLeft: 0,
scrollTop: 0
};
if (val.x || val.y) {
pos.scrollLeft = +val.x * _this2.maxScroll.scrollLeft;
pos.scrollTop = +val.y * _this2.maxScroll.scrollTop;
} else {
pos.scrollLeft = +val * _this2.maxScroll.scrollLeft;
pos.scrollTop = +val * _this2.maxScroll.scrollTop;
}
_this2.setScroll(pos, 'drag');
}
});
},
scroll: function scroll(e) {
var _this$$refs$content2 = this.$refs.content,
scrollTop = _this$$refs$content2.scrollTop,
scrollLeft = _this$$refs$content2.scrollLeft;
this.setScroll({
scrollTop: scrollTop,
scrollLeft: scrollLeft
});
this.$emit('scroll', e);
},
setScroll: function setScroll(_ref) {
var scrollTop = _ref.scrollTop,
scrollLeft = _ref.scrollLeft;
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'scroll';
var needScroll = type !== 'scroll';
if (scrollTop !== undefined) {
this.setPos(scrollTop, 'scrollTop', needScroll);
}
if (scrollLeft !== undefined) {
this.setPos(scrollLeft, 'scrollLeft', needScroll);
}
this.judgeOnBoundary();
},
setPos: function setPos(val, type, needScroll) {
this.scrollPos[type] = val;
if (needScroll) this.$refs.content[type] = val;
},
judgeOnBoundary: function judgeOnBoundary() {
this.isTop = this.scrollPos.scrollTop === 0;
this.isBottom = this.scrollPos.scrollTop === this.maxScroll.scrollTop;
this.isLeft = this.scrollPos.scrollLeft === 0;
this.isRight = this.scrollPos.scrollLeft === this.maxScroll.scrollLeft;
}
},
created: function created() {
var _this3 = this;
var inPcBrowser = !this.isMobile && typeof window !== 'undefined';
if (inPcBrowser) insertStyle();
this.$once('hook:mounted', function () {
if (inPcBrowser) {
_this3.updateScrollbarWidth();
_this3.$once('hook:beforeDestroy', Utils.$addListener(_this3.$refs.content, 'scroll', _this3.scroll));
}
_this3.updateHeight();
_this3.$on('hook:beforeDestroy', listenDomChange(_this3, function () {
_this3.$emit('domChange');
_this3.updateScrollbarWidth();
_this3.updateHeight();
}));
});
}
};
/* script */
var __vue_script__$1 = script$1;
/* template */
var __vue_render__$1 = function __vue_render__() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _c('div', {
ref: "wrap",
staticClass: "scrollbar-wrap",
style: _vm.$_wrapStyle,
on: {
"click": function click($event) {
return _vm.$emit('wrapClick', $event);
}
}
}, [_c('div', {
ref: "content",
staticClass: "scrollbar-content",
style: _vm.$_contentStyle
}, [_vm._t("default")], 2), _vm._v(" "), !_vm.isMobile && _vm.width.content && _vm.height.content ? _vm._l(_vm.scrollbars, function (barInfo, type) {
return _c('Bar', {
key: type,
attrs: {
"type": type,
"marginToWrap": _vm.marginToWrap,
"parentScroll": _vm.scrollPos[barInfo.scrollPropName],
"clientSize": barInfo.size.content,
"scrollSize": barInfo.size.contentInner
},
on: {
"scrollTo": function scrollTo($event) {
return _vm.setScroll($event, 'drag');
}
}
});
}) : _vm._e()], 2);
};
var __vue_staticRenderFns__$1 = [];
/* style */
var __vue_inject_styles__$1 = undefined;
/* scoped */
var __vue_scope_id__$1 = undefined;
/* module identifier */
var __vue_module_identifier__$1 = undefined;
/* functional template */
var __vue_is_functional_template__$1 = false;
/* style inject */
/* style inject SSR */
var VueScrollbar = normalizeComponent_1({
render: __vue_render__$1,
staticRenderFns: __vue_staticRenderFns__$1
}, __vue_inject_styles__$1, __vue_script__$1, __vue_scope_id__$1, __vue_is_functional_template__$1, __vue_module_identifier__$1, undefined, undefined);
export default VueScrollbar;