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
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(); |
|
} |
|
|
|
} |
|
|
|
|