Nhảy tới nội dung

recycle-view

  • recycle-view dùng để hiển thị một danh sách dữ liệu lớn. Nó giúp tối ưu performance bằng cách chỉ render một số lượng các item cần thiết trong phạm vi nhìn thấy của người dùng.
  • Nó có height mặc định là window height, bạn có thể thay đổi thông qua style của recycle-view.
  • recycle-view được phân làm hai loại grid view và list view. Mỗi loại đều có các thuộc tính riêng.
    • Grid view hiển thị nhiều item trên mỗi dòng. Số lượng item trên mỗi dòng thì đồng nhất.
    • List view hiển thị một item trên một dòng.
Cảnh báo

recycle-view đang trong giai đoạn phát triển, chưa phải là bản chính thức nên có thể sẽ có lỗi phát sinh trong quá trình sử dụng.

Quét mã để trải nghiệm

Xem code mẫu trên Tini Studio

Demo

Trải nghiệm thử với trình giả lập bên dưới

Các thuộc tính chung của recycle-view

Thuộc tínhKiểu dữ liệuBắt buộcMô tả
totalCountstringTổng số lượng các phần tử có trong mảng.
isGridbooleanChỉ định hiển thị view dưới dạng grid, có thể có nhiều phần tử trên 1 dòng. mặc định là false.
hasPlaceholderbooleanKhi scroll quá nhanh thì có thể sẽ bị trắng một lúc do quá trình tính toán, có thể dùng placeholder để hiển thị thay vùng trắng đó. Bắt buộc phải dùng chung với component <recycle-placeholder>. Mặc định là false
hasLoadingbooleanDo recycle view sử dụng cơ chế lazy load, nên có thể mất một khoảng thời gian để khởi tạo component, có thể dùng loading để hiển thị trong lúc chờ component được load xong. Bắt buộc phải dùng chung với component <recycle-loading>
onReadyeventSự kiện được gọi khi recycle view được khởi tạo xong
onEndReachedeventSự kiện được gọi khi scroll tới vị trí của phần tử cuối cùng trong danh sách
onScrollingeventSự kiện được gọi khi đang scroll, trả về detail {isScrolling: boolean}, với isScrolling là true nếu đang scroll, false nếu dừng scroll
onRangeChangedeventSự kiện được gọi khi các phần tử trong phạm vi hiển thị bị thay đổi, trả về detail {startIndex: number, endIndex: number}

List view

Các thuộc tính

Thuộc tínhKiểu dữ liệuBắt buộcMô tả
initialTopMostItemIndexnumberVị trí của phần tử được xuất hiện đầu tiên, chỉ có tác dụng ở lần đầu khi list được hiển thị, khi thay đổi giá trị này list sẽ không tự động scroll tới. Mặc định là 0, giá trị trong khoảng từ 0 tới totalCount

Cấu trúc của list view:

<recycle-view>
<recycle-item />
<recycle-footer />
<recycle-loading />
<recycle-placeholder />
</recycle-view>

Sample Code

src/pages/component/basic/recycle-view/list/index.txml
<recycle-view
totalCount="{{items.length}}"
hasFooter
overscan="{{500}}"
onRangeChanged="onRangeChanged"
onScroll="onScroll"
onScrolling="onScrolling"
onReady="onRecycleReady"
onEndReached="onEndReached">
<recycle-item class="item" tiki:for="{{items}}">
<view style="height: {{item.height}}px">
{{item.index}}
</view>
</recycle-item>

<recycle-footer>
<view
style="height: 40px; background: blue; color: white; text-align: center"
tiki:if="{{loading}}">
...Loading
</view>
</recycle-footer>
</recycle-view>
src/pages/component/basic/recycle-view/list/index.js
Page({
data: {
items: []
},
canPullDown: true,
onLoad() {
this.onLoadData(true);
},
onPullDownRefresh() {
this.onLoadData(true);
my.stopPullDownRefresh();
},
onLoadData(refresh) {
this.setData({ loading: true });
setTimeout(() => {
const { items } = this.data;
const newItems = [...Array(20).keys()].map((_, index) => {
return {
index: (refresh ? 0 : items.length) + index,
height: Math.floor(Math.random() * 80 + 40)
};
});

if (refresh) {
this.setData({ items: newItems, loading: false });
} else {
this.$spliceData({
items: [items.length, 0, ...newItems],
loading: false
});
}
}, 300);
},
setCanPullDown(canPullDown) {
my.setCanPullDown({ canPullDown });
this.canPullDown = canPullDown;
},
onEndReached() {
this.onLoadData(false);
},
onRecycleReady() {
console.log('ready');
},
onScroll(event) {
if (event.detail.scrollTop === 0 && !this.canPullDown) {
this.setCanPullDown(true);
my.setCanPullDown({ canPullDown: true });
} else if (this.canPullDown) {
this.setCanPullDown(false);
}
console.log('onScroll', event);
},
onRangeChanged(event) {
console.log('onRangeChanged', event);
},
onScrolling(event) {
console.log('onScrolling', event);
}
});

Grid view

  • Grid view và List view dùng chung component là recycle-view. Tuy nhiên, grid cho phép hiển thị nhiều item trên một dòng (số lượng item trên một dòng là giống nhau)
  • Để dùng grid view thì cần khai báo isGrid = true.
  • Các item cần có cùng chiều cao (height) với nhau, nếu không có thể gây ra việc scroll không đúng. Có thể thay đổi chiều cao qua style hoặc class của recycle-item.

Các thuộc tính

Thuộc tínhKiểu dữ liệuBắt buộcMô tả
itemClassNamestringclass cho mỗi item trong grid
listClassNamestringclass cho wrapper của các item

Cấu trúc của list view:

<recycle-view isGrid="{{true}}">
<recycle-item />
<recycle-loading />
<recycle-placeholder />
</recycle-view>

Sample Code

index.txml

src/pages/component/basic/recycle-view/grid/index.txml
<recycle-view
isGrid
onEndReached="onEndReached"
listClassName="list"
itemClassName="item"
totalCount="{{items.length}}" >
<recycle-item tiki:for="{{items}}">
{{item}}
</recycle-item>
</recycle-view>
src/pages/component/basic/recycle-view/grid/index.js
Page({
data: {
items: []
},
onLoad() {
this.onEndReached();
},
onEndReached() {
setTimeout(() => {
const { items } = this.data;
const newItems = [...Array(20).keys()].map(
(_, index) => items.length + index
);
this.$spliceData({ items: [items.length, 0, ...newItems] });
}, 300);
}
});

Các component con

recycle-view sẽ chứa các component con phục vụ việc render, trong đó recycle-item là bắt buộc phải có và hiển thị trên cùng so với các component con khác.

  • recycle-item Danh sách các item được hiển thị. Bắt buộc phải có trong recycle view và phải đặt ở vị trí trên cùng so với các component con khác

  • recycle-footer Chỉ hỗ trợ dạng list

  • recycle-loading Hỗ trợ cả list và grid

  • recycle-placeholder Hỗ trợ cả list và grid

Thuộc tínhKiểu dữ liệuBắt buộcMô tả
classstringCustom class cho component
stylestringInline style cho component

createRecycleContext

Dùng để thực hiện các tác vụ cho recycle-view. Hỗ trợ các hàm:

  • scrollToIndex(location: number | IndexLocationWithAlign)
  • scrollIntoView(location: ScrollIntoViewLocation)
  • scrollTo(location: ScrollToOptions)
  • scrollBy(location: ScrollToOptions)

Trong đó:

type IndexLocationWithAlign = {
/**
* Vị trí của phần tử muốn scroll tới
*/
index: number;
/**
* Vị trí của item trong viewport.
*/
align?: 'start' | 'center' | 'end';
/**
* Sử dụng smooth nếu muốn scroll mượt hơn, mặc định là auto
*/
behavior?: 'smooth' | 'auto';
};

type ScrollIntoViewLocation = {
/**
* Vị trí của phần tử muốn scroll tới
*/
index: number;
/**
* Sử dụng smooth nếu muốn scroll mượt hơn, mặc định là auto
*/
behavior?: 'auto' | 'smooth';
};

type ScrollToOptions = {
/**
* Top px muốn scroll tới
*/
top?: number;
/**
* Sử dụng smooth nếu muốn scroll mượt hơn, mặc định là auto
*/
behavior?: 'auto' | 'smooth';
};
Lưu ý

Behavior smooth không hỗ trợ cho iOS https://caniuse.com/?search=scroll-behavior