kingdot
Version:
A UI Components Library For Vue
1,196 lines (1,016 loc) • 37.6 kB
JavaScript
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/dist/";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 261);
/******/ })
/************************************************************************/
/******/ ({
/***/ 2:
/***/ (function(module, exports) {
module.exports = require("vue");
/***/ }),
/***/ 261:
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: external {"root":"Vue","commonjs":"vue","commonjs2":"vue","amd":"vue"}
var external_root_Vue_commonjs_vue_commonjs2_vue_amd_vue_ = __webpack_require__(2);
var external_root_Vue_commonjs_vue_commonjs2_vue_amd_vue_default = /*#__PURE__*/__webpack_require__.n(external_root_Vue_commonjs_vue_commonjs2_vue_amd_vue_);
// CONCATENATED MODULE: ./components/VirtualList/virtual.js
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* virtual list core calculating center
*/
var DIRECTION_TYPE = {
FRONT: 'FRONT', // scroll up or left
BEHIND: 'BEHIND' // scroll down or right
};
var CALC_TYPE = {
INIT: 'INIT',
FIXED: 'FIXED',
DYNAMIC: 'DYNAMIC'
};
var LEADING_BUFFER = 0;
var Virtual = function () {
function Virtual(param, callUpdate) {
_classCallCheck(this, Virtual);
this.init(param, callUpdate);
}
_createClass(Virtual, [{
key: 'init',
value: function init(param, callUpdate) {
// param data
this.param = param;
this.callUpdate = callUpdate;
// size data
this.sizes = new Map();
this.firstRangeTotalSize = 0;
this.firstRangeAverageSize = 0;
this.lastCalcIndex = 0;
this.fixedSizeValue = 0;
this.calcType = CALC_TYPE.INIT;
// scroll data
this.offset = 0;
this.direction = '';
// range data
this.range = Object.create(null);
if (param) {
this.checkRange(0, param.keeps - 1);
}
// benchmark test data
// this.__bsearchCalls = 0
// this.__getIndexOffsetCalls = 0
}
}, {
key: 'destroy',
value: function destroy() {
this.init(null, null);
}
// return current render range
}, {
key: 'getRange',
value: function getRange() {
var range = Object.create(null);
range.start = this.range.start;
range.end = this.range.end;
range.padFront = this.range.padFront;
range.padBehind = this.range.padBehind;
return range;
}
}, {
key: 'isBehind',
value: function isBehind() {
return this.direction === DIRECTION_TYPE.BEHIND;
}
}, {
key: 'isFront',
value: function isFront() {
return this.direction === DIRECTION_TYPE.FRONT;
}
// return start index offset
}, {
key: 'getOffset',
value: function getOffset(start) {
return (start < 1 ? 0 : this.getIndexOffset(start)) + this.param.slotHeaderSize;
}
}, {
key: 'updateParam',
value: function updateParam(key, value) {
var _this = this;
if (this.param && key in this.param) {
// if uniqueIds change, find out deleted id and remove from size map
if (key === 'uniqueIds') {
this.sizes.forEach(function (v, key) {
if (!value.includes(key)) {
_this.sizes.delete(key);
}
});
}
this.param[key] = value;
}
}
// save each size map by id
}, {
key: 'saveSize',
value: function saveSize(id, size) {
this.sizes.set(id, size);
// we assume size type is fixed at the beginning and remember first size value
// if there is no size value different from this at next comming saving
// we think it's a fixed size list, otherwise is dynamic size list
if (this.calcType === CALC_TYPE.INIT) {
this.fixedSizeValue = size;
this.calcType = CALC_TYPE.FIXED;
} else if (this.calcType === CALC_TYPE.FIXED && this.fixedSizeValue !== size) {
this.calcType = CALC_TYPE.DYNAMIC;
// it's no use at all
delete this.fixedSizeValue;
}
// calculate the average size only in the first range
if (this.calcType !== CALC_TYPE.FIXED && typeof this.firstRangeTotalSize !== 'undefined') {
if (this.sizes.size < Math.min(this.param.keeps, this.param.uniqueIds.length)) {
this.firstRangeTotalSize = [].concat(_toConsumableArray(this.sizes.values())).reduce(function (acc, val) {
return acc + val;
}, 0);
this.firstRangeAverageSize = Math.round(this.firstRangeTotalSize / this.sizes.size);
} else {
// it's done using
delete this.firstRangeTotalSize;
}
}
}
// in some special situation (e.g. length change) we need to update in a row
// try going to render next range by a leading buffer according to current direction
}, {
key: 'handleDataSourcesChange',
value: function handleDataSourcesChange() {
var start = this.range.start;
if (this.isFront()) {
start = start - LEADING_BUFFER;
} else if (this.isBehind()) {
start = start + LEADING_BUFFER;
}
start = Math.max(start, 0);
this.updateRange(this.range.start, this.getEndByStart(start));
}
// when slot size change, we also need force update
}, {
key: 'handleSlotSizeChange',
value: function handleSlotSizeChange() {
this.handleDataSourcesChange();
}
// calculating range on scroll
}, {
key: 'handleScroll',
value: function handleScroll(offset) {
this.direction = offset < this.offset ? DIRECTION_TYPE.FRONT : DIRECTION_TYPE.BEHIND;
this.offset = offset;
if (!this.param) {
return;
}
if (this.direction === DIRECTION_TYPE.FRONT) {
this.handleFront();
} else if (this.direction === DIRECTION_TYPE.BEHIND) {
this.handleBehind();
}
}
// ----------- public method end -----------
}, {
key: 'handleFront',
value: function handleFront() {
var overs = this.getScrollOvers();
// should not change range if start doesn't exceed overs
if (overs > this.range.start) {
return;
}
// move up start by a buffer length, and make sure its safety
var start = Math.max(overs - this.param.buffer, 0);
this.checkRange(start, this.getEndByStart(start));
}
}, {
key: 'handleBehind',
value: function handleBehind() {
var overs = this.getScrollOvers();
// range should not change if scroll overs within buffer
if (overs < this.range.start + this.param.buffer) {
return;
}
this.checkRange(overs, this.getEndByStart(overs));
}
// return the pass overs according to current scroll offset
}, {
key: 'getScrollOvers',
value: function getScrollOvers() {
// if slot header exist, we need subtract its size
var offset = this.offset - this.param.slotHeaderSize;
if (offset <= 0) {
return 0;
}
// if is fixed type, that can be easily
if (this.isFixedType()) {
return Math.floor(offset / this.fixedSizeValue);
}
var low = 0;
var middle = 0;
var middleOffset = 0;
var high = this.param.uniqueIds.length;
while (low <= high) {
// this.__bsearchCalls++
middle = low + Math.floor((high - low) / 2);
middleOffset = this.getIndexOffset(middle);
if (middleOffset === offset) {
return middle;
} else if (middleOffset < offset) {
low = middle + 1;
} else if (middleOffset > offset) {
high = middle - 1;
}
}
return low > 0 ? --low : 0;
}
// return a scroll offset from given index, can efficiency be improved more here?
// although the call frequency is very high, its only a superposition of numbers
}, {
key: 'getIndexOffset',
value: function getIndexOffset(givenIndex) {
if (!givenIndex) {
return 0;
}
var offset = 0;
var indexSize = 0;
for (var index = 0; index < givenIndex; index++) {
// this.__getIndexOffsetCalls++
indexSize = this.sizes.get(this.param.uniqueIds[index]);
offset = offset + (typeof indexSize === 'number' ? indexSize : this.getEstimateSize());
}
// remember last calculate index
this.lastCalcIndex = Math.max(this.lastCalcIndex, givenIndex - 1);
this.lastCalcIndex = Math.min(this.lastCalcIndex, this.getLastIndex());
return offset;
}
// is fixed size type
}, {
key: 'isFixedType',
value: function isFixedType() {
return this.calcType === CALC_TYPE.FIXED;
}
// return the real last index
}, {
key: 'getLastIndex',
value: function getLastIndex() {
return this.param.uniqueIds.length - 1;
}
// in some conditions range is broke, we need correct it
// and then decide whether need update to next range
}, {
key: 'checkRange',
value: function checkRange(start, end) {
var keeps = this.param.keeps;
var total = this.param.uniqueIds.length;
// datas less than keeps, render all
if (total <= keeps) {
start = 0;
end = this.getLastIndex();
} else if (end - start < keeps - 1) {
// if range length is less than keeps, corrent it base on end
start = end - keeps + 1;
}
if (this.range.start !== start) {
this.updateRange(start, end);
}
}
// setting to a new range and rerender
}, {
key: 'updateRange',
value: function updateRange(start, end) {
this.range.start = start;
this.range.end = end;
this.range.padFront = this.getPadFront();
this.range.padBehind = this.getPadBehind();
this.callUpdate(this.getRange());
}
// return end base on start
}, {
key: 'getEndByStart',
value: function getEndByStart(start) {
var theoryEnd = start + this.param.keeps - 1;
var truelyEnd = Math.min(theoryEnd, this.getLastIndex());
return truelyEnd;
}
// return total front offset
}, {
key: 'getPadFront',
value: function getPadFront() {
if (this.isFixedType()) {
return this.fixedSizeValue * this.range.start;
} else {
return this.getIndexOffset(this.range.start);
}
}
// return total behind offset
}, {
key: 'getPadBehind',
value: function getPadBehind() {
var end = this.range.end;
var lastIndex = this.getLastIndex();
if (this.isFixedType()) {
return (lastIndex - end) * this.fixedSizeValue;
}
// if it's all calculated, return the exactly offset
if (this.lastCalcIndex === lastIndex) {
return this.getIndexOffset(lastIndex) - this.getIndexOffset(end);
} else {
// if not, use a estimated value
return (lastIndex - end) * this.getEstimateSize();
}
}
// get the item estimate size
}, {
key: 'getEstimateSize',
value: function getEstimateSize() {
return this.isFixedType() ? this.fixedSizeValue : this.firstRangeAverageSize || this.param.estimateSize;
}
}]);
return Virtual;
}();
/* harmony default export */ var virtual = (Virtual);
// CONCATENATED MODULE: ./components/VirtualList/props.js
/**
* props declaration for default, item and slot component
*/
var VirtualProps = {
dataKey: {
type: [String, Function],
required: true
},
dataSources: {
type: Array,
required: true
},
dataComponent: {
type: [Object, Function]
// required: true
},
keeps: {
type: Number,
default: 30
},
extraProps: {
type: Object
},
estimateSize: {
type: Number,
default: 50
},
direction: {
type: String,
default: 'vertical' // the other value is horizontal
},
start: {
type: Number,
default: 0
},
offset: {
type: Number,
default: 0
},
topThreshold: {
type: Number,
default: 0
},
bottomThreshold: {
type: Number,
default: 0
},
pageMode: {
type: Boolean,
default: false
},
rootTag: {
type: String,
default: 'div'
},
wrapTag: {
type: String,
default: 'div'
},
wrapClass: {
type: String,
default: ''
},
wrapStyle: {
type: Object
},
itemTag: {
type: String,
default: 'div'
},
itemClass: {
type: String,
default: ''
},
itemClassAdd: {
type: Function
},
itemStyle: {
type: Object
},
headerTag: {
type: String,
default: 'div'
},
headerClass: {
type: String,
default: ''
},
headerStyle: {
type: Object
},
footerTag: {
type: String,
default: 'div'
},
footerClass: {
type: String,
default: ''
},
footerStyle: {
type: Object
},
itemScopedSlots: {
type: Object
}
};
var ItemProps = {
index: {
type: Number
},
event: {
type: String
},
tag: {
type: String
},
horizontal: {
type: Boolean
},
source: {
type: Object
},
component: {
type: [Object, Function]
},
slotComponent: {
type: Function
},
uniqueKey: {
type: [String, Number]
},
extraProps: {
type: Object
},
scopedSlots: {
type: Object
}
};
var SlotProps = {
event: {
type: String
},
uniqueKey: {
type: String
},
tag: {
type: String
},
horizontal: {
type: Boolean
}
};
// CONCATENATED MODULE: ./components/VirtualList/item.js
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
/**
* item and slot component both use similar wrapper
* we need to know their size change at any time
*/
var Wrapper = {
created: function created() {
this.shapeKey = this.horizontal ? 'offsetWidth' : 'offsetHeight';
},
mounted: function mounted() {
var _this = this;
if (typeof ResizeObserver !== 'undefined') {
this.resizeObserver = new ResizeObserver(function () {
_this.dispatchSizeChange();
});
this.resizeObserver.observe(this.$el);
}
},
// since componet will be reused, so disptach when updated
updated: function updated() {
this.dispatchSizeChange();
},
beforeDestroy: function beforeDestroy() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
},
methods: {
getCurrentSize: function getCurrentSize() {
return this.$el ? this.$el[this.shapeKey] : 0;
},
// tell parent current size identify by unqiue key
dispatchSizeChange: function dispatchSizeChange() {
this.$parent.$emit(this.event, this.uniqueKey, this.getCurrentSize(), this.hasInitial);
}
}
};
// wrapping for item
var Item = external_root_Vue_commonjs_vue_commonjs2_vue_amd_vue_default.a.component('virtual-list-item', {
mixins: [Wrapper],
props: ItemProps,
render: function render(h) {
var tag = this.tag,
component = this.component,
_extraProps = this.extraProps,
extraProps = _extraProps === undefined ? {} : _extraProps,
index = this.index,
source = this.source,
_scopedSlots = this.scopedSlots,
scopedSlots = _scopedSlots === undefined ? {} : _scopedSlots,
uniqueKey = this.uniqueKey,
slotComponent = this.slotComponent;
var props = _extends({}, extraProps, {
source: source,
index: index
});
return h(tag, {
key: uniqueKey,
attrs: {
role: 'listitem'
}
}, [slotComponent ? h('div', slotComponent({ item: source, index: index, scope: props })) : h(component, {
props: props,
scopedSlots: scopedSlots
})]);
}
});
// wrapping for slot
var Slot = external_root_Vue_commonjs_vue_commonjs2_vue_amd_vue_default.a.component('virtual-list-slot', {
mixins: [Wrapper],
props: SlotProps,
render: function render(h) {
var tag = this.tag,
uniqueKey = this.uniqueKey;
return h(tag, {
key: uniqueKey,
attrs: {
role: uniqueKey
}
}, this.$slots.default);
}
});
// CONCATENATED MODULE: ./components/VirtualList/list.js
/**
* virtual list default component
*/
var EVENT_TYPE = {
ITEM: 'item_resize',
SLOT: 'slot_resize'
};
var SLOT_TYPE = {
HEADER: 'thead', // string value also use for aria role attribute
FOOTER: 'tfoot'
};
var VirtualList = external_root_Vue_commonjs_vue_commonjs2_vue_amd_vue_default.a.component('kd-virtual-list', {
props: VirtualProps,
data: function data() {
return {
range: null
};
},
watch: {
'dataSources.length': function dataSourcesLength() {
this.virtual.updateParam('uniqueIds', this.getUniqueIdFromDataSources());
this.virtual.handleDataSourcesChange();
},
keeps: function keeps(newValue) {
this.virtual.updateParam('keeps', newValue);
this.virtual.handleSlotSizeChange();
},
start: function start(newValue) {
this.scrollToIndex(newValue);
},
offset: function offset(newValue) {
this.scrollToOffset(newValue);
}
},
created: function created() {
this.isHorizontal = this.direction === 'horizontal';
this.directionKey = this.isHorizontal ? 'scrollLeft' : 'scrollTop';
this.installVirtual();
// listen item size change
this.$on(EVENT_TYPE.ITEM, this.onItemResized);
// listen slot size change
if (this.$slots.header || this.$slots.footer) {
this.$on(EVENT_TYPE.SLOT, this.onSlotResized);
}
},
activated: function activated() {
// set back offset when awake from keep-alive
this.scrollToOffset(this.virtual.offset);
if (this.pageMode) {
document.addEventListener('scroll', this.onScroll, {
passive: false
});
}
},
deactivated: function deactivated() {
if (this.pageMode) {
document.removeEventListener('scroll', this.onScroll);
}
},
mounted: function mounted() {
// set position
if (this.start) {
this.scrollToIndex(this.start);
} else if (this.offset) {
this.scrollToOffset(this.offset);
}
// in page mode we bind scroll event to document
if (this.pageMode) {
this.updatePageModeFront();
document.addEventListener('scroll', this.onScroll, {
passive: false
});
}
},
beforeDestroy: function beforeDestroy() {
this.virtual.destroy();
if (this.pageMode) {
document.removeEventListener('scroll', this.onScroll);
}
},
methods: {
// get item size by id
getSize: function getSize(id) {
return this.virtual.sizes.get(id);
},
// get the total number of stored (rendered) items
getSizes: function getSizes() {
return this.virtual.sizes.size;
},
// return current scroll offset
getOffset: function getOffset() {
if (this.pageMode) {
return document.documentElement[this.directionKey] || document.body[this.directionKey];
} else {
var root = this.$refs.root;
return root ? Math.ceil(root[this.directionKey]) : 0;
}
},
// return client viewport size
getClientSize: function getClientSize() {
var key = this.isHorizontal ? 'clientWidth' : 'clientHeight';
if (this.pageMode) {
return document.documentElement[key] || document.body[key];
} else {
var root = this.$refs.root;
return root ? Math.ceil(root[key]) : 0;
}
},
// return all scroll size
getScrollSize: function getScrollSize() {
var key = this.isHorizontal ? 'scrollWidth' : 'scrollHeight';
if (this.pageMode) {
return document.documentElement[key] || document.body[key];
} else {
var root = this.$refs.root;
return root ? Math.ceil(root[key]) : 0;
}
},
// set current scroll position to a expectant offset
scrollToOffset: function scrollToOffset(offset) {
if (this.pageMode) {
document.body[this.directionKey] = offset;
document.documentElement[this.directionKey] = offset;
} else {
var root = this.$refs.root;
if (root) {
root[this.directionKey] = offset;
}
}
},
// set current scroll position to a expectant index
scrollToIndex: function scrollToIndex(index) {
// scroll to bottom
if (index >= this.dataSources.length - 1) {
this.scrollToBottom();
} else {
var offset = this.virtual.getOffset(index);
this.scrollToOffset(offset);
}
},
// set current scroll position to bottom
scrollToBottom: function scrollToBottom() {
var _this = this;
var shepherd = this.$refs.shepherd;
if (shepherd) {
var offset = shepherd[this.isHorizontal ? 'offsetLeft' : 'offsetTop'];
this.scrollToOffset(offset);
// check if it's really scrolled to the bottom
// maybe list doesn't render and calculate to last range
// so we need retry in next event loop until it really at bottom
setTimeout(function () {
if (_this.getOffset() + _this.getClientSize() < _this.getScrollSize()) {
_this.scrollToBottom();
}
}, 3);
}
},
// when using page mode we need update slot header size manually
// taking root offset relative to the browser as slot header size
updatePageModeFront: function updatePageModeFront() {
var root = this.$refs.root;
if (root) {
var rect = root.getBoundingClientRect();
var defaultView = root.ownerDocument.defaultView;
var offsetFront = this.isHorizontal ? rect.left + defaultView.pageXOffset : rect.top + defaultView.pageYOffset;
this.virtual.updateParam('slotHeaderSize', offsetFront);
}
},
// reset all state back to initial
reset: function reset() {
this.virtual.destroy();
this.scrollToOffset(0);
this.installVirtual();
},
// ----------- public method end -----------
installVirtual: function installVirtual() {
this.virtual = new virtual({
slotHeaderSize: 0,
slotFooterSize: 0,
keeps: this.keeps,
estimateSize: this.estimateSize,
buffer: Math.round(this.keeps / 3), // recommend for a third of keeps
uniqueIds: this.getUniqueIdFromDataSources()
}, this.onRangeChanged);
// sync initial range
this.range = this.virtual.getRange();
},
getUniqueIdFromDataSources: function getUniqueIdFromDataSources() {
var dataKey = this.dataKey;
return this.dataSources.map(function (dataSource) {
return typeof dataKey === 'function' ? dataKey(dataSource) : dataSource[dataKey];
});
},
// event called when each item mounted or size changed
onItemResized: function onItemResized(id, size) {
this.virtual.saveSize(id, size);
this.$emit('resized', id, size);
},
// event called when slot mounted or size changed
onSlotResized: function onSlotResized(type, size, hasInit) {
if (type === SLOT_TYPE.HEADER) {
this.virtual.updateParam('slotHeaderSize', size);
} else if (type === SLOT_TYPE.FOOTER) {
this.virtual.updateParam('slotFooterSize', size);
}
if (hasInit) {
this.virtual.handleSlotSizeChange();
}
},
// here is the rerendering entry
onRangeChanged: function onRangeChanged(range) {
this.range = range;
},
onScroll: function onScroll(evt) {
var offset = this.getOffset();
var clientSize = this.getClientSize();
var scrollSize = this.getScrollSize();
// iOS scroll-spring-back behavior will make direction mistake
if (offset < 0 || offset + clientSize > scrollSize + 1 || !scrollSize) {
return;
}
this.virtual.handleScroll(offset);
this.emitEvent(offset, clientSize, scrollSize, evt);
},
// emit event in special position
emitEvent: function emitEvent(offset, clientSize, scrollSize, evt) {
this.$emit('scroll', evt, this.virtual.getRange());
if (this.virtual.isFront() && !!this.dataSources.length && offset - this.topThreshold <= 0) {
this.$emit('totop');
} else if (this.virtual.isBehind() && offset + clientSize + this.bottomThreshold >= scrollSize) {
this.$emit('tobottom');
}
},
// get the real render slots based on range data
// in-place patch strategy will try to reuse components as possible
// so those components that are reused will not trigger lifecycle mounted
getRenderSlots: function getRenderSlots(h) {
var slots = [];
var _range = this.range,
start = _range.start,
end = _range.end;
var dataSources = this.dataSources,
dataKey = this.dataKey,
itemClass = this.itemClass,
itemTag = this.itemTag,
itemStyle = this.itemStyle,
isHorizontal = this.isHorizontal,
extraProps = this.extraProps,
dataComponent = this.dataComponent,
itemScopedSlots = this.itemScopedSlots;
var slotComponent = this.$scopedSlots && this.$scopedSlots.item;
for (var index = start; index <= end; index++) {
var dataSource = dataSources[index];
if (dataSource) {
var uniqueKey = typeof dataKey === 'function' ? dataKey(dataSource) : dataSource[dataKey];
if (typeof uniqueKey === 'string' || typeof uniqueKey === 'number') {
slots.push(h(Item, {
props: {
index: index,
tag: itemTag,
event: EVENT_TYPE.ITEM,
horizontal: isHorizontal,
uniqueKey: uniqueKey,
source: dataSource,
extraProps: extraProps,
component: dataComponent,
slotComponent: slotComponent,
scopedSlots: itemScopedSlots
},
style: itemStyle,
class: '' + itemClass + (this.itemClassAdd ? ' ' + this.itemClassAdd(index) : '')
}));
} else {
// eslint-disable-next-line no-console
console.warn('Cannot get the data-key \'' + dataKey + '\' from data-sources.');
}
} else {
// eslint-disable-next-line no-console
console.warn('Cannot get the index \'' + index + '\' from data-sources.');
}
}
return slots;
}
},
// render function, a closer-to-the-compiler alternative to templates
// https://vuejs.org/v2/guide/render-function.html#The-Data-Object-In-Depth
render: function render(h) {
var _$slots = this.$slots,
header = _$slots.header,
footer = _$slots.footer;
var _range2 = this.range,
padFront = _range2.padFront,
padBehind = _range2.padBehind;
var isHorizontal = this.isHorizontal,
pageMode = this.pageMode,
rootTag = this.rootTag,
wrapTag = this.wrapTag,
wrapClass = this.wrapClass,
wrapStyle = this.wrapStyle,
headerTag = this.headerTag,
headerClass = this.headerClass,
headerStyle = this.headerStyle,
footerTag = this.footerTag,
footerClass = this.footerClass,
footerStyle = this.footerStyle;
var paddingStyle = { padding: isHorizontal ? '0px ' + padBehind + 'px 0px ' + padFront + 'px' : padFront + 'px 0px ' + padBehind + 'px' };
var wrapperStyle = wrapStyle ? Object.assign({}, wrapStyle, paddingStyle) : paddingStyle;
return h(rootTag, {
ref: 'root',
on: {
'scroll': !pageMode && this.onScroll
}
}, [
// header slot
header ? h(Slot, {
class: headerClass,
style: headerStyle,
props: {
tag: headerTag,
event: EVENT_TYPE.SLOT,
uniqueKey: SLOT_TYPE.HEADER
}
}, header) : null,
// main list
h(wrapTag, {
class: wrapClass,
attrs: {
role: 'group'
},
style: wrapperStyle
}, this.getRenderSlots(h)),
// footer slot
footer ? h(Slot, {
class: footerClass,
style: footerStyle,
props: {
tag: footerTag,
event: EVENT_TYPE.SLOT,
uniqueKey: SLOT_TYPE.FOOTER
}
}, footer) : null,
// an empty element use to scroll to bottom
h('div', {
ref: 'shepherd',
style: {
width: isHorizontal ? '0px' : '100%',
height: isHorizontal ? '100%' : '0px'
}
})]);
}
});
/* harmony default export */ var list = (VirtualList);
// CONCATENATED MODULE: ./components/VirtualList/index.js
list.install = function (Vue) {
Vue.component(list.name, list);
};
/* harmony default export */ var components_VirtualList = __webpack_exports__["default"] = (list);
/***/ })
/******/ })["default"];