el-table-virtual-scroll
Version:
The virtual scrolling component developed based on the Table component of Element-UI supports dynamic height and solves the problem of scrolling stuck when the amount of data is large.
1,616 lines (1,520 loc) • 124 kB
JavaScript
import normalizeWheel from 'normalize-wheel';
import { getValueByPath } from 'element-ui/src/utils/util';
import { Checkbox, Radio, TableColumn } from 'element-ui';
function _iterableToArrayLimit(r, l) {
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (null != t) {
var e,
n,
i,
u,
a = [],
f = !0,
o = !1;
try {
if (i = (t = t.call(r)).next, 0 === l) {
if (Object(t) !== t) return;
f = !1;
} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
} catch (r) {
o = !0, n = r;
} finally {
try {
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
} finally {
if (o) throw n;
}
}
return a;
}
}
function _regeneratorRuntime() {
_regeneratorRuntime = function () {
return e;
};
var t,
e = {},
r = Object.prototype,
n = r.hasOwnProperty,
o = Object.defineProperty || function (t, e, r) {
t[e] = r.value;
},
i = "function" == typeof Symbol ? Symbol : {},
a = i.iterator || "@@iterator",
c = i.asyncIterator || "@@asyncIterator",
u = i.toStringTag || "@@toStringTag";
function define(t, e, r) {
return Object.defineProperty(t, e, {
value: r,
enumerable: !0,
configurable: !0,
writable: !0
}), t[e];
}
try {
define({}, "");
} catch (t) {
define = function (t, e, r) {
return t[e] = r;
};
}
function wrap(t, e, r, n) {
var i = e && e.prototype instanceof Generator ? e : Generator,
a = Object.create(i.prototype),
c = new Context(n || []);
return o(a, "_invoke", {
value: makeInvokeMethod(t, r, c)
}), a;
}
function tryCatch(t, e, r) {
try {
return {
type: "normal",
arg: t.call(e, r)
};
} catch (t) {
return {
type: "throw",
arg: t
};
}
}
e.wrap = wrap;
var h = "suspendedStart",
l = "suspendedYield",
f = "executing",
s = "completed",
y = {};
function Generator() {}
function GeneratorFunction() {}
function GeneratorFunctionPrototype() {}
var p = {};
define(p, a, function () {
return this;
});
var d = Object.getPrototypeOf,
v = d && d(d(values([])));
v && v !== r && n.call(v, a) && (p = v);
var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p);
function defineIteratorMethods(t) {
["next", "throw", "return"].forEach(function (e) {
define(t, e, function (t) {
return this._invoke(e, t);
});
});
}
function AsyncIterator(t, e) {
function invoke(r, o, i, a) {
var c = tryCatch(t[r], t, o);
if ("throw" !== c.type) {
var u = c.arg,
h = u.value;
return h && "object" == typeof h && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) {
invoke("next", t, i, a);
}, function (t) {
invoke("throw", t, i, a);
}) : e.resolve(h).then(function (t) {
u.value = t, i(u);
}, function (t) {
return invoke("throw", t, i, a);
});
}
a(c.arg);
}
var r;
o(this, "_invoke", {
value: function (t, n) {
function callInvokeWithMethodAndArg() {
return new e(function (e, r) {
invoke(t, n, e, r);
});
}
return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
}
});
}
function makeInvokeMethod(e, r, n) {
var o = h;
return function (i, a) {
if (o === f) throw new Error("Generator is already running");
if (o === s) {
if ("throw" === i) throw a;
return {
value: t,
done: !0
};
}
for (n.method = i, n.arg = a;;) {
var c = n.delegate;
if (c) {
var u = maybeInvokeDelegate(c, n);
if (u) {
if (u === y) continue;
return u;
}
}
if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
if (o === h) throw o = s, n.arg;
n.dispatchException(n.arg);
} else "return" === n.method && n.abrupt("return", n.arg);
o = f;
var p = tryCatch(e, r, n);
if ("normal" === p.type) {
if (o = n.done ? s : l, p.arg === y) continue;
return {
value: p.arg,
done: n.done
};
}
"throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg);
}
};
}
function maybeInvokeDelegate(e, r) {
var n = r.method,
o = e.iterator[n];
if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y;
var i = tryCatch(o, e.iterator, r.arg);
if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y;
var a = i.arg;
return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y);
}
function pushTryEntry(t) {
var e = {
tryLoc: t[0]
};
1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e);
}
function resetTryEntry(t) {
var e = t.completion || {};
e.type = "normal", delete e.arg, t.completion = e;
}
function Context(t) {
this.tryEntries = [{
tryLoc: "root"
}], t.forEach(pushTryEntry, this), this.reset(!0);
}
function values(e) {
if (e || "" === e) {
var r = e[a];
if (r) return r.call(e);
if ("function" == typeof e.next) return e;
if (!isNaN(e.length)) {
var o = -1,
i = function next() {
for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next;
return next.value = t, next.done = !0, next;
};
return i.next = i;
}
}
throw new TypeError(typeof e + " is not iterable");
}
return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", {
value: GeneratorFunctionPrototype,
configurable: !0
}), o(GeneratorFunctionPrototype, "constructor", {
value: GeneratorFunction,
configurable: !0
}), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) {
var e = "function" == typeof t && t.constructor;
return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name));
}, e.mark = function (t) {
return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t;
}, e.awrap = function (t) {
return {
__await: t
};
}, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () {
return this;
}), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) {
void 0 === i && (i = Promise);
var a = new AsyncIterator(wrap(t, r, n, o), i);
return e.isGeneratorFunction(r) ? a : a.next().then(function (t) {
return t.done ? t.value : a.next();
});
}, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () {
return this;
}), define(g, "toString", function () {
return "[object Generator]";
}), e.keys = function (t) {
var e = Object(t),
r = [];
for (var n in e) r.push(n);
return r.reverse(), function next() {
for (; r.length;) {
var t = r.pop();
if (t in e) return next.value = t, next.done = !1, next;
}
return next.done = !0, next;
};
}, e.values = values, Context.prototype = {
constructor: Context,
reset: function (e) {
if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t);
},
stop: function () {
this.done = !0;
var t = this.tryEntries[0].completion;
if ("throw" === t.type) throw t.arg;
return this.rval;
},
dispatchException: function (e) {
if (this.done) throw e;
var r = this;
function handle(n, o) {
return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o;
}
for (var o = this.tryEntries.length - 1; o >= 0; --o) {
var i = this.tryEntries[o],
a = i.completion;
if ("root" === i.tryLoc) return handle("end");
if (i.tryLoc <= this.prev) {
var c = n.call(i, "catchLoc"),
u = n.call(i, "finallyLoc");
if (c && u) {
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
} else if (c) {
if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
} else {
if (!u) throw new Error("try statement without catch or finally");
if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
}
}
}
},
abrupt: function (t, e) {
for (var r = this.tryEntries.length - 1; r >= 0; --r) {
var o = this.tryEntries[r];
if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) {
var i = o;
break;
}
}
i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null);
var a = i ? i.completion : {};
return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a);
},
complete: function (t, e) {
if ("throw" === t.type) throw t.arg;
return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y;
},
finish: function (t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var r = this.tryEntries[e];
if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y;
}
},
catch: function (t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var r = this.tryEntries[e];
if (r.tryLoc === t) {
var n = r.completion;
if ("throw" === n.type) {
var o = n.arg;
resetTryEntry(r);
}
return o;
}
}
throw new Error("illegal catch attempt");
},
delegateYield: function (e, r, n) {
return this.delegate = {
iterator: values(e),
resultName: r,
nextLoc: n
}, "next" === this.method && (this.arg = t), y;
}
}, e;
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject$1(value) {
var type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
var isObject_1 = isObject$1;
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
var _freeGlobal = freeGlobal;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = _freeGlobal || freeSelf || Function('return this')();
var _root = root;
/**
* Gets the timestamp of the number of milliseconds that have elapsed since
* the Unix epoch (1 January 1970 00:00:00 UTC).
*
* @static
* @memberOf _
* @since 2.4.0
* @category Date
* @returns {number} Returns the timestamp.
* @example
*
* _.defer(function(stamp) {
* console.log(_.now() - stamp);
* }, _.now());
* // => Logs the number of milliseconds it took for the deferred invocation.
*/
var now = function() {
return _root.Date.now();
};
var now_1 = now;
/** Used to match a single whitespace character. */
var reWhitespace = /\s/;
/**
* Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
* character of `string`.
*
* @private
* @param {string} string The string to inspect.
* @returns {number} Returns the index of the last non-whitespace character.
*/
function trimmedEndIndex(string) {
var index = string.length;
while (index-- && reWhitespace.test(string.charAt(index))) {}
return index;
}
var _trimmedEndIndex = trimmedEndIndex;
/** Used to match leading whitespace. */
var reTrimStart = /^\s+/;
/**
* The base implementation of `_.trim`.
*
* @private
* @param {string} string The string to trim.
* @returns {string} Returns the trimmed string.
*/
function baseTrim(string) {
return string
? string.slice(0, _trimmedEndIndex(string) + 1).replace(reTrimStart, '')
: string;
}
var _baseTrim = baseTrim;
/** Built-in value references. */
var Symbol$1 = _root.Symbol;
var _Symbol = Symbol$1;
/** Used for built-in method references. */
var objectProto$1 = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto$1.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString$1 = objectProto$1.toString;
/** Built-in value references. */
var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
/**
* A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the raw `toStringTag`.
*/
function getRawTag(value) {
var isOwn = hasOwnProperty.call(value, symToStringTag$1),
tag = value[symToStringTag$1];
try {
value[symToStringTag$1] = undefined;
var unmasked = true;
} catch (e) {}
var result = nativeObjectToString$1.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag$1] = tag;
} else {
delete value[symToStringTag$1];
}
}
return result;
}
var _getRawTag = getRawTag;
/** Used for built-in method references. */
var objectProto = Object.prototype;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
/**
* Converts `value` to a string using `Object.prototype.toString`.
*
* @private
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
*/
function objectToString(value) {
return nativeObjectToString.call(value);
}
var _objectToString = objectToString;
/** `Object#toString` result references. */
var nullTag = '[object Null]',
undefinedTag = '[object Undefined]';
/** Built-in value references. */
var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function baseGetTag(value) {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return (symToStringTag && symToStringTag in Object(value))
? _getRawTag(value)
: _objectToString(value);
}
var _baseGetTag = baseGetTag;
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return value != null && typeof value == 'object';
}
var isObjectLike_1 = isObjectLike;
/** `Object#toString` result references. */
var symbolTag = '[object Symbol]';
/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* _.isSymbol(Symbol.iterator);
* // => true
*
* _.isSymbol('abc');
* // => false
*/
function isSymbol(value) {
return typeof value == 'symbol' ||
(isObjectLike_1(value) && _baseGetTag(value) == symbolTag);
}
var isSymbol_1 = isSymbol;
/** Used as references for various `Number` constants. */
var NAN = 0 / 0;
/** Used to detect bad signed hexadecimal string values. */
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
/** Used to detect binary string values. */
var reIsBinary = /^0b[01]+$/i;
/** Used to detect octal string values. */
var reIsOctal = /^0o[0-7]+$/i;
/** Built-in method references without a dependency on `root`. */
var freeParseInt = parseInt;
/**
* Converts `value` to a number.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {number} Returns the number.
* @example
*
* _.toNumber(3.2);
* // => 3.2
*
* _.toNumber(Number.MIN_VALUE);
* // => 5e-324
*
* _.toNumber(Infinity);
* // => Infinity
*
* _.toNumber('3.2');
* // => 3.2
*/
function toNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol_1(value)) {
return NAN;
}
if (isObject_1(value)) {
var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
value = isObject_1(other) ? (other + '') : other;
}
if (typeof value != 'string') {
return value === 0 ? value : +value;
}
value = _baseTrim(value);
var isBinary = reIsBinary.test(value);
return (isBinary || reIsOctal.test(value))
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
: (reIsBadHex.test(value) ? NAN : +value);
}
var toNumber_1 = toNumber;
/** Error message constants. */
var FUNC_ERROR_TEXT$1 = 'Expected a function';
/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max,
nativeMin = Math.min;
/**
* Creates a debounced function that delays invoking `func` until after `wait`
* milliseconds have elapsed since the last time the debounced function was
* invoked. The debounced function comes with a `cancel` method to cancel
* delayed `func` invocations and a `flush` method to immediately invoke them.
* Provide `options` to indicate whether `func` should be invoked on the
* leading and/or trailing edge of the `wait` timeout. The `func` is invoked
* with the last arguments provided to the debounced function. Subsequent
* calls to the debounced function return the result of the last `func`
* invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the debounced function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.debounce` and `_.throttle`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to debounce.
* @param {number} [wait=0] The number of milliseconds to delay.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.
* @example
*
* // Avoid costly calculations while the window size is in flux.
* jQuery(window).on('resize', _.debounce(calculateLayout, 150));
*
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
* jQuery(element).on('click', _.debounce(sendMail, 300, {
* 'leading': true,
* 'trailing': false
* }));
*
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
* var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
* var source = new EventSource('/stream');
* jQuery(source).on('message', debounced);
*
* // Cancel the trailing debounced invocation.
* jQuery(window).on('popstate', debounced.cancel);
*/
function debounce(func, wait, options) {
var lastArgs,
lastThis,
maxWait,
result,
timerId,
lastCallTime,
lastInvokeTime = 0,
leading = false,
maxing = false,
trailing = true;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT$1);
}
wait = toNumber_1(wait) || 0;
if (isObject_1(options)) {
leading = !!options.leading;
maxing = 'maxWait' in options;
maxWait = maxing ? nativeMax(toNumber_1(options.maxWait) || 0, wait) : maxWait;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
function invokeFunc(time) {
var args = lastArgs,
thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time;
// Start the timer for the trailing edge.
timerId = setTimeout(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime,
timeWaiting = wait - timeSinceLastCall;
return maxing
? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
: timeWaiting;
}
function shouldInvoke(time) {
var timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
}
function timerExpired() {
var time = now_1();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// Restart the timer.
timerId = setTimeout(timerExpired, remainingWait(time));
}
function trailingEdge(time) {
timerId = undefined;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
clearTimeout(timerId);
}
lastInvokeTime = 0;
lastArgs = lastCallTime = lastThis = timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(now_1());
}
function debounced() {
var time = now_1(),
isInvoking = shouldInvoke(time);
lastArgs = arguments;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime);
}
if (maxing) {
// Handle invocations in a tight loop.
clearTimeout(timerId);
timerId = setTimeout(timerExpired, wait);
return invokeFunc(lastCallTime);
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, wait);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
var debounce_1 = debounce;
/** Error message constants. */
var FUNC_ERROR_TEXT = 'Expected a function';
/**
* Creates a throttled function that only invokes `func` at most once per
* every `wait` milliseconds. The throttled function comes with a `cancel`
* method to cancel delayed `func` invocations and a `flush` method to
* immediately invoke them. Provide `options` to indicate whether `func`
* should be invoked on the leading and/or trailing edge of the `wait`
* timeout. The `func` is invoked with the last arguments provided to the
* throttled function. Subsequent calls to the throttled function return the
* result of the last `func` invocation.
*
* **Note:** If `leading` and `trailing` options are `true`, `func` is
* invoked on the trailing edge of the timeout only if the throttled function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.throttle` and `_.debounce`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to throttle.
* @param {number} [wait=0] The number of milliseconds to throttle invocations to.
* @param {Object} [options={}] The options object.
* @param {boolean} [options.leading=true]
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new throttled function.
* @example
*
* // Avoid excessively updating the position while scrolling.
* jQuery(window).on('scroll', _.throttle(updatePosition, 100));
*
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
* var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
* jQuery(element).on('click', throttled);
*
* // Cancel the trailing throttled invocation.
* jQuery(window).on('popstate', throttled.cancel);
*/
function throttle(func, wait, options) {
var leading = true,
trailing = true;
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
if (isObject_1(options)) {
leading = 'leading' in options ? !!options.leading : leading;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
return debounce_1(func, wait, {
'leading': leading,
'maxWait': wait,
'trailing': trailing
});
}
var throttle_1 = throttle;
// 判断是否是滚动容器
function isScroller(el) {
var style = window.getComputedStyle(el, null);
var scrollValues = ['auto', 'scroll'];
return scrollValues.includes(style.overflow) || scrollValues.includes(style['overflow-y']);
}
// 获取父层滚动容器
function getParentScroller(el) {
var parent = el;
while (parent) {
if ([window, document, document.documentElement].includes(parent)) {
return window;
}
if (isScroller(parent)) {
return parent;
}
parent = parent.parentNode;
}
return parent || window;
}
// 获取容器滚动位置
function getScrollTop(el) {
return el === window ? window.pageYOffset : el.scrollTop;
}
// 获取容器高度
function getOffsetHeight(el) {
return el === window ? window.innerHeight : el.offsetHeight;
}
// 滚动到某个位置
function scrollToY(el, y) {
if (el === window) {
window.scroll(0, y);
} else {
el.scrollTop = y;
}
}
// 是否为空 undefine or null
function isEmpty(val) {
return typeof val === 'undefined' || val === null;
}
var isFirefox = typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
// 设置滚轮速度(完全参考 element-ui > table > handleFixedMousewheel方法)
function setMousewheelSlow(scroller, slow) {
function handler(event) {
var data = normalizeWheel(event);
if (Math.abs(data.spinY) > 0) {
var currentScrollTop = scroller.scrollTop;
if (data.pixelY < 0 && currentScrollTop !== 0) {
event.preventDefault();
}
if (data.pixelY > 0 && scroller.scrollHeight - scroller.clientHeight > currentScrollTop) {
event.preventDefault();
}
scroller.scrollTop += Math.ceil(data.pixelY / slow);
}
}
var throttleHandler = throttle_1(handler, 0);
scroller.addEventListener(isFirefox ? 'DOMMouseScroll' : 'mousewheel', throttleHandler, {
passive: false
});
return function destory() {
scroller.removeEventListener(isFirefox ? 'DOMMouseScroll' : 'mousewheel', throttleHandler);
};
}
var isObject = function isObject(obj) {
return obj !== null && _typeof(obj) === 'object';
};
// 排序(来源:element-ui/table/util的orderBy方法)
var orderBy = function orderBy(array, sortKey, reverse, sortMethod, sortBy) {
// eslint-disable-next-line no-mixed-operators
if (!sortKey && !sortMethod && (!sortBy || Array.isArray(sortBy) && !sortBy.length)) {
return array;
}
if (typeof reverse === 'string') {
reverse = reverse === 'descending' ? -1 : 1;
} else {
reverse = reverse && reverse < 0 ? -1 : 1;
}
var getKey = sortMethod ? null : function (value, index) {
if (sortBy) {
if (!Array.isArray(sortBy)) {
sortBy = [sortBy];
}
return sortBy.map(function (by) {
if (typeof by === 'string') {
return getValueByPath(value, by);
} else {
return by(value, index, array);
}
});
}
if (sortKey !== '$key') {
if (isObject(value) && '$value' in value) value = value.$value;
}
return [isObject(value) ? getValueByPath(value, sortKey) : value];
};
var compare = function compare(a, b) {
if (sortMethod) {
return sortMethod(a.value, b.value);
}
for (var i = 0, len = a.key.length; i < len; i++) {
if (a.key[i] < b.key[i]) {
return -1;
}
if (a.key[i] > b.key[i]) {
return 1;
}
}
return 0;
};
return array.map(function (value, index) {
return {
value: value,
index: index,
key: getKey ? getKey(value, index) : null
};
}).sort(function (a, b) {
var order = compare(a, b);
if (!order) {
// make stable https://en.wikipedia.org/wiki/Sorting_algorithm#Stability
order = a.index - b.index;
}
return order * reverse;
}).map(function (item) {
return item.value;
});
};
var getColumnById = function getColumnById(table, columnId) {
var column = null;
table.columns.forEach(function (item) {
if (item.id === columnId) {
column = item;
}
});
return column;
};
// 表格body class名称
var TableBodyClassNames = ['.el-table__body-wrapper',
// 主表格容器
'.el-table__fixed-right .el-table__fixed-body-wrapper',
// 右固定表格容器
'.el-table__fixed .el-table__fixed-body-wrapper' // 左固定表格容器
];
var script$2 = {
name: 'el-table-virtual-scroll',
props: {
// 总数据
data: {
type: Array,
required: true
},
// 每一行的预估高度
itemSize: {
type: Number,
"default": 60
},
// 指定滚动容器
scrollBox: {
type: String
},
// 顶部和底部缓冲区域,值越大显示表格的行数越多
buffer: {
type: Number,
"default": 200
},
// key值,data数据中的唯一id
keyProp: {
type: String,
"default": 'id'
},
// 滚动事件的节流时间
throttleTime: {
type: Number,
"default": 16
},
// 是否获取表格行动态高度
dynamic: {
type: Boolean,
"default": true
},
// 是否开启虚拟滚动
virtualized: {
type: Boolean,
"default": true
},
// 表格行合并时,合并在一起的行返回相同的key值
rowSpanKey: {
type: Function
},
warn: {
type: Boolean,
"default": true
},
// 禁用虚拟滚动
disabled: {
type: Boolean,
"default": false
},
// 支持自定义选中数据的排序规则,传入false则可保留列表的排序规则,默认是按照选中顺序排序
selectionSort: {
type: [Function, Boolean],
"default": true
},
// 获取el-table组件,默认 virtual-scroll 组件的第一个子组件
getElTable: {
type: Function,
"default": function _default() {
return this.$children[0];
}
},
keepScroll: {
type: Boolean,
"default": true
}
},
provide: function provide() {
return {
virtualScroll: this
};
},
data: function data() {
return {
sizes: {},
// 尺寸映射(依赖响应式)
start: 0,
// 渲染列表开始索引
end: undefined,
// 渲染列表结束索引
curRow: null,
// 表格单选:选中的行
oldSelection: [],
// 表格多选:选中的行
isExpanding: false,
// 列是否正在展开
columnVms: [],
// virtual-column 组件实例
isHideAppend: false,
// 是否隐藏append
scrollPosition: '',
// x轴滚动位置(左、中、右)
hasFixedRight: false,
// 是否有固定右边的列
listData: [],
// 未筛选为data源数据,筛选后则为筛选后的数据
isTree: false // 是否自定义树形表格
};
},
computed: {
// 计算出每个item(的key值)到滚动容器顶部的距离
offsetMap: function offsetMap(_ref) {
var keyProp = _ref.keyProp,
itemSize = _ref.itemSize,
sizes = _ref.sizes,
listData = _ref.listData;
if (!this.dynamic) return {};
var res = {};
var total = 0;
for (var i = 0; i < listData.length; i++) {
var key = listData[i][keyProp];
if (typeof key === 'undefined') {
this.warn && console.warn("data[".concat(i, "][").concat(keyProp, "] \u4E3A undefined\uFF0C\u8BF7\u786E\u4FDD keyProp \u5BF9\u5E94\u7684\u503C\u4E0D\u4E3Aundefined"));
}
res[key] = total;
var curSize = sizes[key];
var size = typeof curSize === 'number' ? curSize : itemSize;
total += size;
}
return res;
},
// 树节点的 children 映射,通过响应式关联起来,那么children中添加、删除节点会触发treeMap computed,从而监听treeMap更新视图【注:children 添加删除不会触发data watch,data只是浅监听】
treeMap: function treeMap(_ref2) {
var data = _ref2.data,
keyProp = _ref2.keyProp,
treeProps = _ref2.treeProps,
isTree = _ref2.isTree;
if (!isTree || !treeProps) return;
var res = {};
var children = treeProps.children;
var traverse = function traverse(nodes) {
nodes.forEach(function (node) {
var key = node[keyProp];
if (typeof key !== 'undefined' && node[children]) {
res[key] = node[children];
traverse(node[children]);
}
});
};
// 开始遍历树结构
traverse(data);
return res;
}
},
methods: {
// 初始化数据
initData: function initData() {
var _this = this;
this.destory(); // 销毁,防止多次调用
// 可视范围内显示数据
this.renderData = [];
// 页面可视范围顶端、底部
this.top = undefined;
this.bottom = undefined;
// 截取页面可视范围内显示数据的开始和结尾索引
this.start = 0;
this.end = undefined;
// 是否是表格内部滚动
this.isInnerScroll = false;
// 高亮的行
this.highlightRow = null;
// 滚动位置
this.scrollPos = [0, 0];
// 触发scroll
this.triggleScroll = false;
// 多选:记录多选选项的顺序
this.checkOrder = 0;
// 验证ElTable组件
this.elTable = this.getElTable();
if (!this.elTable || this.elTable.$options.name !== 'ElTable') {
throw new Error('未找到 <el-table> 组件. 请确保 <el-table> 组件在虚拟组件内,且 getElTable 方法能获取到正确的 <el-table> 组件!');
}
if (!this.elTable.rowKey) {
this.warn && console.warn('[el-table-virtual-scroll]: 建议设置 <el-table> 组件的 rowKey 属性');
}
this.scroller = this.getScroller();
this.observeElTable();
// 监听事件
this.onScroll = !this.throttleTime ? this.handleScroll : throttle_1(this.handleScroll, this.throttleTime);
this.scroller.addEventListener('scroll', this.onScroll);
window.addEventListener('resize', this.onScroll);
// 兼容
this.hackTableExpand(); // 兼容表格展开行
this.hackTableHeaderDrag(); // 兼容表格头拖拽
this.hackTableSort(); // 兼容表格排序
this.hackTableFilter(); // 兼容表格筛选
this.hackRowHighlight(); // 兼容单选
this.hackSelection(); // 兼容多选
this.hackCustomTree(); // 兼容树形表格
this.bindTableDestory(); // 绑定表格销毁事件
// 设置listData,首次updateTreeData会在node上添加$v_tree属性,触发data watch,从而触发 onSortChange,所以defaultSort就无需再次触发
this.treeProps = this.elTable.treeProps || {
children: 'children',
hasChildren: 'hasChildren'
};
// 此处兼容 default-sort 属性
if (this.elTable.defaultSort) {
this.$nextTick(function () {
// 此处使用nextTick是因为 el-tale的sortingColumn排序数据还没设置好,得等一会
_this.onSortChange(); // onSortChange 会触发updateTreeData
});
} else {
this.updateTreeData();
}
// 初次执行 (固定高度的表格布局好后,会触发 bodyHeight 更改(已手动监听,位于 unWatch2代码处),从而触发 onScroll,所以无需手动执行onScroll)
setTimeout(function () {
!_this.triggleScroll && _this.onScroll();
}, 100);
},
// 滚轮滚动速度减缓,减少快速滚动白屏
// slowNum - 减速的值,值越大,滚动越慢
slowOnMousewheel: function slowOnMousewheel() {
var slowNum = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var scroller = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.scroller;
this.removeMousewheelEvent && this.removeMousewheelEvent();
this.removeMousewheelEvent = null;
if (!slowNum) return;
this.removeMousewheelEvent = setMousewheelSlow(scroller, slowNum);
},
// 获取滚动元素
getScroller: function getScroller() {
var el;
if (this.scrollBox) {
if (this.scrollBox === 'window' || this.scrollBox === window) return window;
el = document.querySelector(this.scrollBox);
if (!el) throw new Error(" scrollBox prop: '".concat(this.scrollBox, "' is not a valid selector"));
if (!isScroller(el)) console.warn("Warning! scrollBox prop: '".concat(this.scrollBox, "' is not a scroll element"));
return el;
}
// 如果表格是固定高度,则获取表格内的滚动节点,否则获取父层滚动节点
if (this.elTable && (this.elTable.height || this.elTable.maxHeight || this.elTable.height === 0 || this.elTable.maxHeight === 0)) {
this.isInnerScroll = true;
return this.$el.querySelector('.el-table__body-wrapper');
} else {
return getParentScroller(this.$el);
}
},
// 设置表格到滚动容器的距离
getToTop: function getToTop() {
if (this.isInnerScroll) {
return 0;
} else {
return this.$el.getBoundingClientRect().top - (this.scroller === window ? 0 : this.scroller.getBoundingClientRect().top) + getScrollTop(this.scroller);
}
},
// 处理滚动事件
handleScroll: function handleScroll() {
var shouldUpdate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
if (this.disabled) return;
if (!this.scroller) return;
this.triggleScroll = true;
// 【修复】如果使用v-show 进行切换表格会特别卡顿 #30;
// 【原因】v-show为false时,表格内滚动容器的高度为auto,没有滚动条限制,虚拟滚动计算渲染全部内容
if (this.isInnerScroll && !this.scroller.style.height && !this.scroller.style.maxHeight) return;
// 如果组件失活,则不再执行handleScroll;否则外部容器滚动情况下记录的scrollTop会是0
if (this.isDeactivated) return;
// 记录scrollPos
// 需要判断表格没有隐藏(修复表格隐藏状态下更新绑定数组长度,显示后滚动条位置异常 #67)
if (this.isInnerScroll && this.elTable.layout.bodyHeight) {
this.scrollPos[0] = this.scroller.scrollTop;
this.scrollPos[1] = this.scroller.scrollLeft;
}
if (!this.virtualized) return;
this.removeHoverRows();
// 更新当前尺寸(高度)
this.updateSizes();
// 计算renderData
this.calcRenderData();
// 计算位置
this.calcPosition();
shouldUpdate && this.updatePosition();
// 触发事件
this.$emit('change', this.renderData, this.start, this.end);
// 同步表格行高亮
this.syncRowsHighlight();
},
// 移除多个hover-row
removeHoverRows: function removeHoverRows() {
var hoverRows = this.$el.querySelectorAll('.el-table__row.hover-row');
if (hoverRows.length > 1) {
Array.from(hoverRows).forEach(function (row) {
row.classList.remove('hover-row');
});
}
},
// 更新尺寸(高度)
updateSizes: function updateSizes() {
var _this2 = this;
if (!this.dynamic) return;
var rows = this.$el.querySelectorAll('.el-table__body > tbody > .el-table__row');
// 处理树形表格(修复树结构懒加载 如果有hasChildren=false的行 行可视区域高度异常 #45)
var isTree = this.elTable.lazy;
var isVTree = this.isTree; // 自定义树(非el-table的树)
var noFirstLevelReg = /el-table__row--level-[1-9]\d*/; // 匹配树形表格非一级行
if (!isVTree && isTree) {
// 筛选出树形表格的一级行,一级行className含有el-table__row--level-0或者不存在层级className
rows = Array.from(this.$el.querySelectorAll('.el-table__body > tbody > .el-table__row')).filter(function (row) {
return !noFirstLevelReg.test(row.className);
});
}
Array.from(rows).forEach(function (row, index) {
var item = _this2.renderData[index];
if (!item) return;
// 计算表格行的高度
var offsetHeight = row.offsetHeight;
// 表格行如果有扩展行,需要加上扩展内容的高度
if (!isTree && !isVTree && row.classList.contains('expanded')) {
offsetHeight += row.nextSibling.offsetHeight;
}
// 表格行如果有子孙节点,需要加上子孙节点的高度
if (isTree) {
var next = row.nextSibling;
while (next && next.tagName === 'TR' && noFirstLevelReg.test(next.className)) {
offsetHeight += next.offsetHeight;
next = next.nextSibling;
}
}
var key = item[_this2.keyProp];
if (offsetHeight && _this2.sizes[key] !== offsetHeight) {
_this2.$set(_this2.sizes, key, offsetHeight);
}
});
},
// 获取某条数据offsetTop
getItemOffsetTop: function getItemOffsetTop(index) {
if (!this.dynamic) {
return this.itemSize * index;
}
var item = this.listData[index];
if (item) {
return this.offsetMap[item[this.keyProp]] || 0;
}
return 0;
},
// 获取某条数据的尺寸
getItemSize: function getItemSize(index) {
if (index <= -1) return 0;
var item = this.listData[index];
if (item) {
var key = item[this.keyProp];
return this.sizes[key] || this.itemSize;
}
return this.itemSize;
},
// 计算只在视图上渲染的数据
calcRenderData: function calcRenderData() {
var scroller = this.scroller,
listData = this.listData,
buffer = this.buffer;
// 计算可视范围顶部、底部
var toTop = this.getToTop(); // 表格到滚动容器的距离
var top = getScrollTop(scroller) - buffer - toTop;
var bottom = getScrollTop(scroller) + getOffsetHeight(scroller) + buffer - toTop;
var start;
var end;
if (!this.dynamic) {
start = top <= 0 ? 0 : Math.floor(top / this.itemSize);
end = bottom <= 0 ? 0 : Math.ceil(bottom / this.itemSize);
} else {
// 二分法计算可视范围内的开始的第一个内容
var l = 0;
var r = listData.length - 1;
var mid = 0;
while (l <= r) {
mid = Math.floor((l + r) / 2);
var midVal = this.getItemOffsetTop(mid);
if (midVal < top) {
var midNextVal = this.getItemOffsetTop(mid + 1);
if (midNextVal > top) break;
l = mid + 1;
} else {
r = mid - 1;
}
}
start = mid;
// 二分法计算可视范围内的结束的最后一个内容
l = start;
r = listData.length - 1;
mid = 0;
while (l <= r) {
mid = Math.floor((l + r) / 2);
var _midVal = this.getItemOffsetTop(mid);
if (_midVal >= bottom) {
var _midNextVal = this.getItemOffsetTop(mid - 1);
if (_midNextVal < bottom) break;
r = mid - 1;
} else {
l = mid + 1;
}
}
end = mid;
}
if (this.isRowSpan()) {
// 计算包含合并行的开始结束区间(⚠️注意:合并行不支持使用斑马纹,因为不能100%确定合并行的开始行是偶数,可能会向上找一直到第一行,导致渲染非常多行,浪费性能)
var _this$calcRenderSpanD = this.calcRenderSpanData(start, end);
var _this$calcRenderSpanD2 = _slicedToArray(_this$calcRenderSpanD, 2);
start = _this$calcRenderSpanD2[0];
end = _this$calcRenderSpanD2[1];
} else {
// 开始索引始终保持偶数,如果为奇数,则加1使其保持偶数【确保表格行的偶数数一致,不会导致斑马纹乱序显示】
if (start % 2) start = start - 1;
}
this.top = top;
this.bottom = bottom;
this.start = start;
this.end = end;
this.renderData = listData.slice(start, end + 1);
if (this.start === 0 && this.end > 30 && this.end === this.listData.length - 1) {
this.warn && console.warn('[el-table-virtual-scroll] 表格数据全部渲染,渲染数量为:' + this.listData.length);
}
},
// 是否是合并行
isRowSpan: function isRowSpan() {
return typeof this.rowSpanKey === 'function';
},
// 如果存在合并行的情况,渲染的数据范围扩大到包含合并行
calcRenderSpanData: function calcRenderSpanData(start, end) {
// 从开始节点向上查找是否有合并行
var prevKey;
while (start > 0) {
var curRow = this.listData[start];
var curkey = this.rowSpanKey(curRow, start);
// 如果不存在key,说明当前行不属于合并行
if (isEmpty(curkey)) break;
// 如果当前行与后面一行的key不相同,说明则当前行不属于合并行,从后一行开始截断
if (!isEmpty(prevKey) && prevKey !== curkey) {
start++;
break;
}
prevKey = curkey;
start--;
}
// 从末端节点向下查找是否有合并行
var len = this.listData.length;
prevKey = undefined;
while (end < len) {
var _curRow = this.listData[end];
var _curkey = this.rowSpanKey(_curRow, end);
// 如果不存在key,说明当前行不属于合并行
if (!_curkey) break;
// 如果当前行与前面一行的key不相同,说明则当前行不属于合并行,从前一行开始截断
if (prevKey && prevKey !== _curkey) {
end--;
break;
}
prevKey = _curkey;
end++;
}
return [start, end];
},
// 计算位置
calcPosition: function calcPosition() {
var _this3 = this;
var last = this.listData.length - 1;
// 计算内容总高度
var wrapHeight = this.getItemOffsetTop(last) + this.getItemSize(last);
// 计算当前滚动位置需要撑起的高度
var offsetTop = this.getItemOffsetTop(this.start);
var tableWrapEl;
// 设置dom位置
TableBodyClassNames.forEach(function (className, index) {
var el = _this3.$el.querySelector(className