Weex SDK中提供了下拉刷新和上拉加載的組件,但是功能比較單一,不能做到跟手滑動(dòng)操作光酣,還會(huì)導(dǎo)致weex刷新和原生刷新不統(tǒng)一的問(wèn)題,所以最好的操作是擴(kuò)展導(dǎo)出原生的刷新組件偿衰。
refresh
組件是WeexSDK官方提供的挂疆,但是不好在這個(gè)組件內(nèi)進(jìn)行擴(kuò)展,為了方便前端的使用和客戶端的擴(kuò)展下翎,最終在list組件的基礎(chǔ)上進(jìn)行擴(kuò)展缤言,因?yàn)閹缀跛械乃⑿潞图虞d都是基于list組件的。
iOS端
為了方便擴(kuò)展视事,我選擇繼承官方的WXListComponent
類胆萧,先整體了解一下整個(gè)類中的代碼
@interface MWSListComponent ()
@property (nonatomic, strong) MJRefreshGifHeader *refreshHeader;
@property (nonatomic, strong) MJRefreshAutoFooter *refreshFooter;
@property (nonatomic, assign) BOOL refresh; /**< 是否開啟下拉刷新 */
@property (nonatomic, assign) BOOL loading; /**< 是否開啟上拉加載 */
@property (nonatomic, assign) BOOL showLoading; /**< 控制loading是否顯示 */
@property (nonatomic, assign) BOOL refreshEvent;
@property (nonatomic, assign) BOOL loadingEvent;
@end
@implementation MWSListComponent
WX_EXPORT_METHOD(@selector(endRefreshing));
WX_EXPORT_METHOD(@selector(endLoading));
WX_EXPORT_METHOD(@selector(noticeNoMoreData));
- (void)dealloc
{
_refreshFooter = nil;
_refreshHeader = nil;
}
- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
{
self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
if (self) {
_refresh = [WXConvert BOOL:attributes[@"refresh"]];
_loading = [WXConvert BOOL:attributes[@"loading"]];
_showLoading = [attributes.allKeys containsObject:@"showLoading"] ? [WXConvert BOOL:attributes[@"showLoading"]] : YES;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self _updateRefreshHeader];
[self _updateRefreshFooter];
[self _updateLoadingState];
}
- (void)addEvent:(NSString *)eventName
{
[super addEvent:eventName];
if ([eventName isEqualToString:@"refresh"]) {
_refreshEvent = YES;
}
if ([eventName isEqualToString:@"loading"]) {
_loadingEvent = YES;
}
}
- (void)removeEvent:(NSString *)eventName
{
[super removeEvent:eventName];
if ([eventName isEqualToString:@"refresh"]) {
_refreshEvent = NO;
}
if ([eventName isEqualToString:@"loading"]) {
_loadingEvent = NO;
}
}
- (void)updateAttributes:(NSDictionary *)attributes
{
[super updateAttributes:attributes];
if ([attributes.allKeys containsObject:@"refresh"]) {
_refresh = [WXConvert BOOL:attributes[@"refresh"]];
[self _updateRefreshHeader];
}
if ([attributes.allKeys containsObject:@"loading"]) {
_loading = [WXConvert BOOL:attributes[@"loading"]];
[self _updateRefreshFooter];
}
if ([attributes.allKeys containsObject:@"showLoading"]) {
_showLoading = [WXConvert BOOL:attributes[@"showLoading"]];
[self _updateLoadingState];
}
}
#pragma mark - Private Method
- (void)_addRefreshHeader
{
if (!_refreshHeader) {
__weak typeof(self) weakSelf = self;
_refreshHeader = [MJRefreshGifHeader headerWithRefreshingBlock:^{
[weakSelf refreshData];
}];
UIScrollView *scrollView = (UIScrollView *)self.view;
scrollView.header = _refreshHeader;
}
}
- (void)refreshData
{
if (_refreshEvent) {
[self fireEvent:@"refresh" params:nil];
}
}
- (void)_removeRefreshHeader
{
if (_refreshHeader) {
UIScrollView *scrollView = (UIScrollView *)self.view;
scrollView.header = nil;
_refreshHeader = nil;
}
}
- (void)_addRefreshFooter
{
if (!_refreshFooter) {
__weak typeof(self) weakSelf = self;
_refreshFooter = [MDRefreshAutoFooter footerWithRefreshingBlock:^{
[weakSelf loadingData];
}];
UIScrollView *scrollView = (UIScrollView *)self.view;
scrollView.footer = _refreshFooter;
[self _updateLoadingState];
}
}
- (void)loadingData
{
if (_loadingEvent) {
[self fireEvent:@"loading" params:nil];
}
}
- (void)_removeRefreshFooter
{
if (_refreshFooter) {
UIScrollView *scrollView = (UIScrollView *)self.view;
scrollView.footer = nil;
_refreshFooter = nil;
}
}
- (void)_updateRefreshHeader
{
if (_refresh) {
[self _addRefreshHeader];
}
else {
[self _removeRefreshHeader];
}
}
- (void)_updateRefreshFooter
{
if (_loading) {
[self _addRefreshFooter];
}
else {
[self _removeRefreshFooter];
}
}
- (void)_updateLoadingState
{
self.refreshFooter.hidden = !_showLoading;
}
#pragma mark - JS call method
- (void)endRefreshing
{
if (_refreshHeader) {
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView.header endRefreshing];
[UIView animateWithDuration:0.4 animations:^{ [(UIScrollView *)self.view setContentOffset:CGPointZero]; }];
}
}
- (void)endLoading
{
if (_refreshFooter) {
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView.footer endRefreshing];
scrollView.footer.hidden = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
scrollView.footer.hidden = NO;
});
}
}
- (void)noticeNoMoreData
{
if (_refreshFooter) {
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView.footer noticeNoMoreData];
}
}
@end
refresh {boolean}
: 可選值為true/false
,默認(rèn)是false
。此值決定 list 是否開啟下拉刷新功能俐东。
loading {boolean}
:可選值為true/false
,默認(rèn)是false
跌穗。此值決定 list 是否開啟上拉加載功能。
下拉刷新的時(shí)候虏辫,會(huì)觸發(fā)list
組件的refresh
方法蚌吸,上拉加載的時(shí)候,會(huì)觸發(fā)list
組件的loading
方法砌庄。當(dāng)數(shù)據(jù)返回的時(shí)候羹唠,我們需要手動(dòng)去關(guān)閉刷新或者加載,因?yàn)閿?shù)據(jù)什么時(shí)候回來(lái)只有weex端才知道娄昆,所以擴(kuò)展了一下幾個(gè)方法:
WX_EXPORT_METHOD(@selector(endRefreshing)); // 停止刷新
- (void)endRefreshing
{
if (_refreshHeader) {
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView.header endRefreshing];
// weex在調(diào)用停止刷新后佩微,scroll并不會(huì)回到頂部,需要我們手動(dòng)進(jìn)行設(shè)置一下萌焰。
[UIView animateWithDuration:0.4 animations:^{ [(UIScrollView *)self.view setContentOffset:CGPointZero]; }];
}
}
WX_EXPORT_METHOD(@selector(endLoading)); // 停止上拉加載
- (void)endLoading
{
if (_refreshFooter) {
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView.footer endRefreshing];
scrollView.footer.hidden = YES;
// 此處的處理因?yàn)閿?shù)據(jù)返回時(shí)候哺眯,weex的render需要一定的時(shí)間,所有絕大部分時(shí)候扒俯,是先看到footer奶卓,然后cell才會(huì)一個(gè)一個(gè)進(jìn)行渲染一疯,所以此處先隱藏footer,0.25s之后再顯示
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
scrollView.footer.hidden = NO;
});
}
}
當(dāng)沒(méi)有更多數(shù)據(jù)的時(shí)候寝杖,我們可以調(diào)用這個(gè)方法進(jìn)行設(shè)置
WX_EXPORT_METHOD(@selector(noticeNoMoreData)); // 提示沒(méi)有更多數(shù)據(jù)了
- (void)noticeNoMoreData
{
if (_refreshFooter) {
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView.footer noticeNoMoreData];
}
}
前端
在設(shè)置樣式的模塊代碼如下
<template>
<div>
<list
ref="list"
refresh="true"
@refresh="_refreshData"
loading="true"
@loading="_loadingData"
>
</list>
</div>
</template>
ref
為了拿到list組件违施,上述代碼開啟了上拉加載和下拉刷新的功能,下面是script模塊的代碼
<script>
export default {
methods: {
_refreshData() {
this._fetchData(true)
},
_loadingData() {
this._fetchData(false)
},
_fetchData(isRefresh) {
// 請(qǐng)求數(shù)據(jù)瑟幕,結(jié)束后
if (_platform==='iOS') {
let list = this.$refs.list;
if (list) {
if (isRefresh) {
list.endRefreshing();
}
if (this.noMoreData) {
list.noticeNoMoreData();
} else {
list.endLoading();
}
}
}
}
}
}
</script>
通過(guò)上述操作磕蒲,就可以將原生的代碼橋接到weex中使用啦。