From 546087ba62d5f24dd326b3e6fe8f72819b4cb9c2 Mon Sep 17 00:00:00 2001 From: guy Date: Mon, 22 May 2017 17:22:59 +0800 Subject: [PATCH] virtuallist --- bi/base.js | 135 ++++++++++++--------- demo/js/core/abstract/demo.virtual_list.js | 8 +- docs/base.js | 135 ++++++++++++--------- docs/demo.js | 8 +- src/base/list/virtuallist.js | 135 ++++++++++++--------- 5 files changed, 233 insertions(+), 188 deletions(-) diff --git a/bi/base.js b/bi/base.js index 5f1c88b26..b14612763 100644 --- a/bi/base.js +++ b/bi/base.js @@ -15476,6 +15476,10 @@ BI.VirtualList = BI.inherit(BI.Widget, { init: function () { this.renderedIndex = -1; this.cache = {}; + this._scrollLock = false; + this._debounceRelease = BI.debounce(function () { + self._scrollLock = false; + }, 1000 / 60); }, render: function () { @@ -15511,23 +15515,27 @@ BI.VirtualList = BI.inherit(BI.Widget, { self._calculateBlocksToRender(); }); BI.ResizeDetector.addResizeListener(this, function () { - self._renderMoreIf(); + self._calculateBlocksToRender(); }); }, _renderMoreIf: function () { - var o = this.options; + var self = this, o = this.options; var height = this.element.height(); var minContentHeight = o.scrollTop + height + o.overscanHeight; var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0, cnt = this.renderedIndex + 1; var lastHeight; - while ((lastHeight = this.container.element.height()) < minContentHeight && index < o.items.length) { + var getElementHeight = function () { + return self.container.element.height() + self.topBlank.element.height() + self.bottomBlank.element.height(); + }; + while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container.addItems(items); - var addedHeight = this.container.element.height() - lastHeight; + var addedHeight = getElementHeight() - lastHeight; this.cache[cnt] = { index: index, + scrollTop: lastHeight, height: addedHeight }; this.tree.set(cnt, addedHeight); @@ -15540,66 +15548,69 @@ BI.VirtualList = BI.inherit(BI.Widget, { _calculateBlocksToRender: function () { var o = this.options; this._renderMoreIf(); - // var height = this.element.height(); - // var minContentHeightFrom = o.scrollTop - o.overscanHeight; - // var minContentHeightTo = o.scrollTop + height + o.overscanHeight; - // var start = this.tree.greatestLowerBound(minContentHeightFrom); - // var end = this.tree.leastUpperBound(minContentHeightTo); - // var summaryTopHeight = 0; + var height = this.element.height(); + var minContentHeightFrom = o.scrollTop - o.overscanHeight; + var minContentHeightTo = o.scrollTop + height + o.overscanHeight; + var start = this.tree.greatestLowerBound(minContentHeightFrom); + var end = this.tree.leastUpperBound(minContentHeightTo); // this.topBlank.setHeight(0); // this.bottomBlank.setHeight(0); - // var needDestroyed = []; - // for (var i = 0; i < start; i++) { - // var index = this.cache[i].index; - // summaryTopHeight += this.cache[i].height; - // if (!this.cache[i].destroyed) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // needDestroyed.push(this.container._children[j]); - // this.container._children[j] = null; - // } - // this.cache[i].destroyed = true; - // // this.topBlank.setHeight(summaryTopHeight); - // } - // } - // summaryTopHeight = 0; - // for (var i = end + 1; i <= this.renderedIndex; i++) { - // var index = this.cache[i].index; - // summaryTopHeight += this.cache[i].height; - // if (!this.cache[i].destroyed) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // needDestroyed.push(this.container._children[j]); - // this.container._children[j] = null; - // } - // this.cache[i].destroyed = true; - // // this.bottomBlank.setHeight(summaryTopHeight); - // } - // } - // var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment(); - // var currentFragment = firstFragment; - // for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) { - // var index = this.cache[i].index; - // if (!this.cache[i].destroyed) { - // currentFragment = lastFragment; - // } - // if (this.cache[i].destroyed === true) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // var w = this.container._children[j] = BI.createWidget(BI.extend({ - // root: true - // }, BI.stripEL(o.items[j]))); - // currentFragment.appendChild(w.element[0]); - // } - // this.cache[i].destroyed = false; - // } - // } - // this.container.element.prepend(firstFragment); - // this.container.element.append(lastFragment); - // BI.each(needDestroyed, function (i, child) { - // child && child._destroy(); - // }); + var needDestroyed = []; + for (var i = 0; i < start; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + needDestroyed.push(this.container._children[j]); + this.container._children[j] = null; + } + this.cache[i].destroyed = true; + } + } + for (var i = end + 1; i <= this.renderedIndex; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + needDestroyed.push(this.container._children[j]); + this.container._children[j] = null; + } + this.cache[i].destroyed = true; + } + } + var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment(); + var currentFragment = firstFragment; + for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + currentFragment = lastFragment; + } + if (this.cache[i].destroyed === true) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + var w = this.container._children[j] = BI.createWidget(BI.extend({ + root: true + }, BI.stripEL(o.items[j]))); + w.element.css("position", "relative");//vertical布局下position要改成relative + currentFragment.appendChild(w.element[0]); + } + this.cache[i].destroyed = false; + } + } + this._scrollLock = true; + this.container.element.prepend(firstFragment); + this.container.element.append(lastFragment); + this.topBlank.setHeight(this.cache[start < 0 ? 0 : start].scrollTop); + var lastCache = this.cache[Math.min(end, this.renderedIndex)]; + this.bottomBlank.setHeight(this.tree.sumTo(this.renderedIndex) - lastCache.scrollTop - lastCache.height); + BI.each(needDestroyed, function (i, child) { + child && child._destroy(); + }); + this._debounceRelease(); }, - _populate: function () { + _populate: function (items) { var o = this.options; + if (items && this.options.items !== items) { + this.options.items = items; + } this.tree = BI.PrefixIntervalTree.empty(Math.ceil(o.items.length / o.blockSize)); this._calculateBlocksToRender(); this.element.scrollTop(o.scrollTop); @@ -15611,7 +15622,10 @@ BI.VirtualList = BI.inherit(BI.Widget, { }, populate: function (items) { - + if (items && this.options.items !== items) { + this.restore(); + } + this._populate(); }, destroyed: function () { @@ -15619,6 +15633,7 @@ BI.VirtualList = BI.inherit(BI.Widget, { } }); BI.shortcut('bi.virtual_list', BI.VirtualList); + /** * 分页控件 * diff --git a/demo/js/core/abstract/demo.virtual_list.js b/demo/js/core/abstract/demo.virtual_list.js index 1a8a754d8..30b7c0358 100644 --- a/demo/js/core/abstract/demo.virtual_list.js +++ b/demo/js/core/abstract/demo.virtual_list.js @@ -5,12 +5,12 @@ Demo.Func = BI.inherit(BI.Widget, { render: function () { return { type: "bi.virtual_list", - items: BI.map(BI.makeArray(200, 0), function (i, item) { - return { + items: BI.map(Demo.CONSTANTS.ITEMS, function (i, item) { + return BI.extend({}, item, { type: "bi.label", height: 30, - text: i - }; + text: (i + 1) + "." + item.text, + }); }) } } diff --git a/docs/base.js b/docs/base.js index 5f1c88b26..b14612763 100644 --- a/docs/base.js +++ b/docs/base.js @@ -15476,6 +15476,10 @@ BI.VirtualList = BI.inherit(BI.Widget, { init: function () { this.renderedIndex = -1; this.cache = {}; + this._scrollLock = false; + this._debounceRelease = BI.debounce(function () { + self._scrollLock = false; + }, 1000 / 60); }, render: function () { @@ -15511,23 +15515,27 @@ BI.VirtualList = BI.inherit(BI.Widget, { self._calculateBlocksToRender(); }); BI.ResizeDetector.addResizeListener(this, function () { - self._renderMoreIf(); + self._calculateBlocksToRender(); }); }, _renderMoreIf: function () { - var o = this.options; + var self = this, o = this.options; var height = this.element.height(); var minContentHeight = o.scrollTop + height + o.overscanHeight; var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0, cnt = this.renderedIndex + 1; var lastHeight; - while ((lastHeight = this.container.element.height()) < minContentHeight && index < o.items.length) { + var getElementHeight = function () { + return self.container.element.height() + self.topBlank.element.height() + self.bottomBlank.element.height(); + }; + while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container.addItems(items); - var addedHeight = this.container.element.height() - lastHeight; + var addedHeight = getElementHeight() - lastHeight; this.cache[cnt] = { index: index, + scrollTop: lastHeight, height: addedHeight }; this.tree.set(cnt, addedHeight); @@ -15540,66 +15548,69 @@ BI.VirtualList = BI.inherit(BI.Widget, { _calculateBlocksToRender: function () { var o = this.options; this._renderMoreIf(); - // var height = this.element.height(); - // var minContentHeightFrom = o.scrollTop - o.overscanHeight; - // var minContentHeightTo = o.scrollTop + height + o.overscanHeight; - // var start = this.tree.greatestLowerBound(minContentHeightFrom); - // var end = this.tree.leastUpperBound(minContentHeightTo); - // var summaryTopHeight = 0; + var height = this.element.height(); + var minContentHeightFrom = o.scrollTop - o.overscanHeight; + var minContentHeightTo = o.scrollTop + height + o.overscanHeight; + var start = this.tree.greatestLowerBound(minContentHeightFrom); + var end = this.tree.leastUpperBound(minContentHeightTo); // this.topBlank.setHeight(0); // this.bottomBlank.setHeight(0); - // var needDestroyed = []; - // for (var i = 0; i < start; i++) { - // var index = this.cache[i].index; - // summaryTopHeight += this.cache[i].height; - // if (!this.cache[i].destroyed) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // needDestroyed.push(this.container._children[j]); - // this.container._children[j] = null; - // } - // this.cache[i].destroyed = true; - // // this.topBlank.setHeight(summaryTopHeight); - // } - // } - // summaryTopHeight = 0; - // for (var i = end + 1; i <= this.renderedIndex; i++) { - // var index = this.cache[i].index; - // summaryTopHeight += this.cache[i].height; - // if (!this.cache[i].destroyed) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // needDestroyed.push(this.container._children[j]); - // this.container._children[j] = null; - // } - // this.cache[i].destroyed = true; - // // this.bottomBlank.setHeight(summaryTopHeight); - // } - // } - // var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment(); - // var currentFragment = firstFragment; - // for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) { - // var index = this.cache[i].index; - // if (!this.cache[i].destroyed) { - // currentFragment = lastFragment; - // } - // if (this.cache[i].destroyed === true) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // var w = this.container._children[j] = BI.createWidget(BI.extend({ - // root: true - // }, BI.stripEL(o.items[j]))); - // currentFragment.appendChild(w.element[0]); - // } - // this.cache[i].destroyed = false; - // } - // } - // this.container.element.prepend(firstFragment); - // this.container.element.append(lastFragment); - // BI.each(needDestroyed, function (i, child) { - // child && child._destroy(); - // }); + var needDestroyed = []; + for (var i = 0; i < start; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + needDestroyed.push(this.container._children[j]); + this.container._children[j] = null; + } + this.cache[i].destroyed = true; + } + } + for (var i = end + 1; i <= this.renderedIndex; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + needDestroyed.push(this.container._children[j]); + this.container._children[j] = null; + } + this.cache[i].destroyed = true; + } + } + var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment(); + var currentFragment = firstFragment; + for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + currentFragment = lastFragment; + } + if (this.cache[i].destroyed === true) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + var w = this.container._children[j] = BI.createWidget(BI.extend({ + root: true + }, BI.stripEL(o.items[j]))); + w.element.css("position", "relative");//vertical布局下position要改成relative + currentFragment.appendChild(w.element[0]); + } + this.cache[i].destroyed = false; + } + } + this._scrollLock = true; + this.container.element.prepend(firstFragment); + this.container.element.append(lastFragment); + this.topBlank.setHeight(this.cache[start < 0 ? 0 : start].scrollTop); + var lastCache = this.cache[Math.min(end, this.renderedIndex)]; + this.bottomBlank.setHeight(this.tree.sumTo(this.renderedIndex) - lastCache.scrollTop - lastCache.height); + BI.each(needDestroyed, function (i, child) { + child && child._destroy(); + }); + this._debounceRelease(); }, - _populate: function () { + _populate: function (items) { var o = this.options; + if (items && this.options.items !== items) { + this.options.items = items; + } this.tree = BI.PrefixIntervalTree.empty(Math.ceil(o.items.length / o.blockSize)); this._calculateBlocksToRender(); this.element.scrollTop(o.scrollTop); @@ -15611,7 +15622,10 @@ BI.VirtualList = BI.inherit(BI.Widget, { }, populate: function (items) { - + if (items && this.options.items !== items) { + this.restore(); + } + this._populate(); }, destroyed: function () { @@ -15619,6 +15633,7 @@ BI.VirtualList = BI.inherit(BI.Widget, { } }); BI.shortcut('bi.virtual_list', BI.VirtualList); + /** * 分页控件 * diff --git a/docs/demo.js b/docs/demo.js index 0c590a563..2f6f7af47 100644 --- a/docs/demo.js +++ b/docs/demo.js @@ -3489,12 +3489,12 @@ BI.shortcut("demo.virtual_group_item", Demo.Item);Demo.Func = BI.inherit(BI.Widg render: function () { return { type: "bi.virtual_list", - items: BI.map(BI.makeArray(200, 0), function (i, item) { - return { + items: BI.map(Demo.CONSTANTS.ITEMS, function (i, item) { + return BI.extend({}, item, { type: "bi.label", height: 30, - text: i - }; + text: (i + 1) + "." + item.text, + }); }) } } diff --git a/src/base/list/virtuallist.js b/src/base/list/virtuallist.js index 2b164bd6b..025921ded 100644 --- a/src/base/list/virtuallist.js +++ b/src/base/list/virtuallist.js @@ -19,6 +19,10 @@ BI.VirtualList = BI.inherit(BI.Widget, { init: function () { this.renderedIndex = -1; this.cache = {}; + this._scrollLock = false; + this._debounceRelease = BI.debounce(function () { + self._scrollLock = false; + }, 1000 / 60); }, render: function () { @@ -54,23 +58,27 @@ BI.VirtualList = BI.inherit(BI.Widget, { self._calculateBlocksToRender(); }); BI.ResizeDetector.addResizeListener(this, function () { - self._renderMoreIf(); + self._calculateBlocksToRender(); }); }, _renderMoreIf: function () { - var o = this.options; + var self = this, o = this.options; var height = this.element.height(); var minContentHeight = o.scrollTop + height + o.overscanHeight; var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0, cnt = this.renderedIndex + 1; var lastHeight; - while ((lastHeight = this.container.element.height()) < minContentHeight && index < o.items.length) { + var getElementHeight = function () { + return self.container.element.height() + self.topBlank.element.height() + self.bottomBlank.element.height(); + }; + while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container.addItems(items); - var addedHeight = this.container.element.height() - lastHeight; + var addedHeight = getElementHeight() - lastHeight; this.cache[cnt] = { index: index, + scrollTop: lastHeight, height: addedHeight }; this.tree.set(cnt, addedHeight); @@ -83,66 +91,69 @@ BI.VirtualList = BI.inherit(BI.Widget, { _calculateBlocksToRender: function () { var o = this.options; this._renderMoreIf(); - // var height = this.element.height(); - // var minContentHeightFrom = o.scrollTop - o.overscanHeight; - // var minContentHeightTo = o.scrollTop + height + o.overscanHeight; - // var start = this.tree.greatestLowerBound(minContentHeightFrom); - // var end = this.tree.leastUpperBound(minContentHeightTo); - // var summaryTopHeight = 0; + var height = this.element.height(); + var minContentHeightFrom = o.scrollTop - o.overscanHeight; + var minContentHeightTo = o.scrollTop + height + o.overscanHeight; + var start = this.tree.greatestLowerBound(minContentHeightFrom); + var end = this.tree.leastUpperBound(minContentHeightTo); // this.topBlank.setHeight(0); // this.bottomBlank.setHeight(0); - // var needDestroyed = []; - // for (var i = 0; i < start; i++) { - // var index = this.cache[i].index; - // summaryTopHeight += this.cache[i].height; - // if (!this.cache[i].destroyed) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // needDestroyed.push(this.container._children[j]); - // this.container._children[j] = null; - // } - // this.cache[i].destroyed = true; - // // this.topBlank.setHeight(summaryTopHeight); - // } - // } - // summaryTopHeight = 0; - // for (var i = end + 1; i <= this.renderedIndex; i++) { - // var index = this.cache[i].index; - // summaryTopHeight += this.cache[i].height; - // if (!this.cache[i].destroyed) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // needDestroyed.push(this.container._children[j]); - // this.container._children[j] = null; - // } - // this.cache[i].destroyed = true; - // // this.bottomBlank.setHeight(summaryTopHeight); - // } - // } - // var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment(); - // var currentFragment = firstFragment; - // for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) { - // var index = this.cache[i].index; - // if (!this.cache[i].destroyed) { - // currentFragment = lastFragment; - // } - // if (this.cache[i].destroyed === true) { - // for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { - // var w = this.container._children[j] = BI.createWidget(BI.extend({ - // root: true - // }, BI.stripEL(o.items[j]))); - // currentFragment.appendChild(w.element[0]); - // } - // this.cache[i].destroyed = false; - // } - // } - // this.container.element.prepend(firstFragment); - // this.container.element.append(lastFragment); - // BI.each(needDestroyed, function (i, child) { - // child && child._destroy(); - // }); + var needDestroyed = []; + for (var i = 0; i < start; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + needDestroyed.push(this.container._children[j]); + this.container._children[j] = null; + } + this.cache[i].destroyed = true; + } + } + for (var i = end + 1; i <= this.renderedIndex; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + needDestroyed.push(this.container._children[j]); + this.container._children[j] = null; + } + this.cache[i].destroyed = true; + } + } + var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment(); + var currentFragment = firstFragment; + for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) { + var index = this.cache[i].index; + if (!this.cache[i].destroyed) { + currentFragment = lastFragment; + } + if (this.cache[i].destroyed === true) { + for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { + var w = this.container._children[j] = BI.createWidget(BI.extend({ + root: true + }, BI.stripEL(o.items[j]))); + w.element.css("position", "relative");//vertical布局下position要改成relative + currentFragment.appendChild(w.element[0]); + } + this.cache[i].destroyed = false; + } + } + this._scrollLock = true; + this.container.element.prepend(firstFragment); + this.container.element.append(lastFragment); + this.topBlank.setHeight(this.cache[start < 0 ? 0 : start].scrollTop); + var lastCache = this.cache[Math.min(end, this.renderedIndex)]; + this.bottomBlank.setHeight(this.tree.sumTo(this.renderedIndex) - lastCache.scrollTop - lastCache.height); + BI.each(needDestroyed, function (i, child) { + child && child._destroy(); + }); + this._debounceRelease(); }, - _populate: function () { + _populate: function (items) { var o = this.options; + if (items && this.options.items !== items) { + this.options.items = items; + } this.tree = BI.PrefixIntervalTree.empty(Math.ceil(o.items.length / o.blockSize)); this._calculateBlocksToRender(); this.element.scrollTop(o.scrollTop); @@ -154,7 +165,10 @@ BI.VirtualList = BI.inherit(BI.Widget, { }, populate: function (items) { - + if (items && this.options.items !== items) { + this.restore(); + } + this._populate(); }, destroyed: function () { @@ -162,3 +176,4 @@ BI.VirtualList = BI.inherit(BI.Widget, { } }); BI.shortcut('bi.virtual_list', BI.VirtualList); +