美文网首页
Weex扩展-原生刷新功能

Weex扩展-原生刷新功能

作者: 崔可一 | 来源:发表于2017-11-03 16:03 被阅读326次

    Weex SDK中提供了下拉刷新和上拉加载的组件,但是功能比较单一,不能做到跟手滑动操作,还会导致weex刷新和原生刷新不统一的问题,所以最好的操作是扩展导出原生的刷新组件。

    refresh组件是WeexSDK官方提供的,但是不好在这个组件内进行扩展,为了方便前端的使用和客户端的扩展,最终在list组件的基础上进行扩展,因为几乎所有的刷新和加载都是基于list组件的。

    iOS端

    为了方便扩展,我选择继承官方的WXListComponent类,先整体了解一下整个类中的代码

    @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,默认是false。此值决定 list 是否开启下拉刷新功能。

    loading {boolean}:可选值为true/false,默认是false。此值决定 list 是否开启上拉加载功能。

    下拉刷新的时候,会触发list组件的refresh方法,上拉加载的时候,会触发list组件的loading方法。当数据返回的时候,我们需要手动去关闭刷新或者加载,因为数据什么时候回来只有weex端才知道,所以扩展了一下几个方法:

    WX_EXPORT_METHOD(@selector(endRefreshing));    // 停止刷新
    
    - (void)endRefreshing
    {
       if (_refreshHeader) {
           UIScrollView *scrollView = (UIScrollView *)self.view;
           [scrollView.header endRefreshing];
           // weex在调用停止刷新后,scroll并不会回到顶部,需要我们手动进行设置一下。
           [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;
            // 此处的处理因为数据返回时候,weex的render需要一定的时间,所有绝大部分时候,是先看到footer,然后cell才会一个一个进行渲染,所以此处先隐藏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;
            });
        }
    }
    

    当没有更多数据的时候,我们可以调用这个方法进行设置

    WX_EXPORT_METHOD(@selector(noticeNoMoreData));  // 提示没有更多数据了
    
    - (void)noticeNoMoreData
    {
        if (_refreshFooter) {
            UIScrollView *scrollView = (UIScrollView *)self.view;
            [scrollView.footer noticeNoMoreData];
        }
    }
    

    前端

    在设置样式的模块代码如下

    <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) {
                // 请求数据,结束后
                if (_platform==='iOS') {
                    let list = this.$refs.list;
                    if (list) {
                        if (isRefresh) {
                            list.endRefreshing();
                        }
                        if (this.noMoreData) {
                            list.noticeNoMoreData();
                        } else {
                            list.endLoading();  
                        }
                    }
                }
            }
        }
    }
    </script>
    

    通过上述操作,就可以将原生的代码桥接到weex中使用啦。

    相关文章

      网友评论

          本文标题:Weex扩展-原生刷新功能

          本文链接:https://www.haomeiwen.com/subject/plbtmxtx.html