fineui是帆软报表和BI产品线所使用的前端框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

149 lines
4.0 KiB

/**
* 边滚动边加载的列表控件
*
* Created by GUY on 2017/5/23.
* @class BI.ListView
* @extends BI.Widget
*/
import { Widget, shortcut } from "../../core";
@shortcut()
export class ListView extends Widget {
props() {
return {
baseCls: "bi-list-view",
overscanHeight: 100,
blockSize: 10,
scrollTop: 0,
el: {},
items: [],
itemFormatter: (item, index) => {
return item;
},
};
}
init() {
this.renderedIndex = -1;
this.cache = {};
}
static xtype = "bi.list_view";
render() {
const { el } = this.options;
return {
type: "bi.vertical",
items: [BI.extend({
type: "bi.vertical",
scrolly: false,
ref: (_ref) => {
this.container = _ref;
},
}, el)],
element: this,
};
}
// mounted之后绑定事件
mounted() {
const o = this.options;
// 这里无法进行结构,因为存在赋值操作,如果使用结构则this.options的值不会跟随变化
o.items = BI.isFunction(o.items) ? this.__watch(o.items, (context, newValue) => {
this.populate(newValue);
}) : o.items;
this._populate();
this.element.scroll((e) => {
o.scrollTop = this.element.scrollTop();
this._calculateBlocksToRender();
});
let lastWidth = this.element.width(),
lastHeight = this.element.height();
BI.ResizeDetector.addResizeListener(this, () => {
if (!this.element.is(":visible")) {
return;
}
const width = this.element.width(),
height = this.element.height();
if (width !== lastWidth || height !== lastHeight) {
lastWidth = width;
lastHeight = height;
this._calculateBlocksToRender();
}
});
}
_renderMoreIf() {
const { scrollTop, overscanHeight, blockSize, items, itemFormatter } = this.options;
const height = this.element.height();
const minContentHeight = scrollTop + height + overscanHeight;
let index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + blockSize)) || 0;
let cnt = this.renderedIndex + 1;
let lastHeight;
const getElementHeight = () => {
return this.container.element.height();
}
lastHeight = getElementHeight();
while ((lastHeight) < minContentHeight && index < items.length) {
const itemsArr = items.slice(index, index + blockSize);
this.container.addItems(itemsArr.map((item, i) => {
return itemFormatter(item, index + i);
}), this);
const addedHeight = getElementHeight() - lastHeight;
this.cache[cnt] = {
index: index,
scrollTop: lastHeight,
height: addedHeight,
};
this.renderedIndex = cnt;
cnt++;
index += blockSize;
lastHeight = getElementHeight();
}
}
_calculateBlocksToRender() {
// BI-115750 不可见状态下依赖元素实际尺寸构造的线段树会分段错误,所以不进行后续计算和线段树的初始化。
// 这样从不可见状态变为可见状态能够重新触发线段树初始化
if (!this.element.is(":visible")) {
return;
}
this._renderMoreIf();
}
_populate(items) {
const { scrollTop } = this.options;
if (items && this.options.items !== items) {
this.options.items = items;
}
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
restore() {
this.renderedIndex = -1;
this.container.empty();
this.cache = {};
}
scrollTo(scrollTop) {
this.options.scrollTop = scrollTop;
this._calculateBlocksToRender();
this.element.scrollTop(scrollTop);
}
populate(items) {
if (items && this.options.items !== items) {
this.restore();
}
this._populate(items);
}
beforeDestroy() {
BI.ResizeDetector.removeResizeListener(this);
this.restore();
}
}