refresh 刷新

解释: 可用于页面任意区域;使用时需自行添加下拉逻辑改变offset-y参数;smt-feed组件对smt-refresh进行了封装,支持手势交互和api调起刷新。

# 属性说明

属性名 类型 必填 默认值 说明
theme String - 主题配置,默认浅色;深色主题请指定dark
loadingHgt Number 192px(需转换为设备尺寸) 加载区域高度
offsetY Number 0 垂直移动距离,*建议后续在sjs中使用
status Number 0 加载状态 0: 未开始 1: 加载中 2: 展示话术
text String 建议最多显示18个汉字,超出内容截断 加载成功时的展示话术

# 示例

在开发者工具中预览效果

# 扫码体验

# 代码示例

    <view class="container {{theme}}" >
        <view class="refresh-wrap {{theme}}">
            <view class="mode-title {{theme}}">
                <view class="mode-title-line-left"></view>
                <view class="mode-title-text">手动下拉刷新</view>
                <view class="mode-title-line-right"></view>
            </view>
            <view
                class="smt-card-area"
                catch:touchstart="noop"
                catch:touchmove="noop"
                catch:touchend="noop"
            >
                <smt-feed
                    class="smt-feed pull-down-refresh"
                    ext-cls-feed="custom-cls-feed"
                    ext-cls-loading="custom-cls-loading"
                    theme="{{theme}}"
                    pull-to-refresh
                    bind:refresh="onRefresh"
                    text="{{pullText}}"
                >
                    <view class="list {{theme}}">
                        <view
                            class="{{'list-item ' + (val === 1 ? 'first' : '')}}"
                            s-for="val in list"
                            style="{{theme === 'dark' ? 'border-bottom: solid 1px rgba(255, 255, 255, .2);' : 'border-bottom: solid 1px #e0e0e0;'}}"
                            key="{{val}}"
                        >
                            <view class="left">
                                <view class="row begin"></view>
                                <view class="row center"></view>
                                <view class="row end"></view>
                            </view>
                            <view class="right"></view>
                        </view>
                    </view>
                </smt-feed>
            </view>
        </view>
    
        <view class="refresh-wrap">
            <view class="mode-title {{theme}}">
                <view class="mode-title-line-left"></view>
                <view class="mode-title-text">自动刷新</view>
                <view class="mode-title-line-right"></view>
            </view>
            <view class="smt-card-area" >
                <smt-feed
                    class="smt-feed auto-refresh"
                    ext-cls-feed="custom-cls-feed"
                    theme="{{theme}}"
                    disable-touch
                    text="{{autoRefreshText}}"
                >
                     <view class="list {{theme}}">
                        <view
                            class="{{'list-item ' + (val === 1 ? 'first' : '')}}"
                            s-for="val in list"
                            style="{{theme === 'dark' ? 'border-bottom: solid 1px rgba(255, 255, 255, .2);' : 'border-bottom: solid 1px #e0e0e0;'}}"
                            key="{{val}}"
                        >
                            <view class="left">
                                <view class="row begin"></view>
                                <view class="row center"></view>
                                <view class="row end"></view>
                            </view>
                            <view class="right"></view>
                        </view>
                    </view>
                </smt-feed>
            </view>
        </view>
    
        <view class="refresh-wrap">
            <view class="mode-title {{theme}}">
                <view class="mode-title-line-left"></view>
                <view class="mode-title-text">刷新失败</view>
                <view class="mode-title-line-right"></view>
            </view>
            <view class="smt-card-area fail" >
                <view class="fail {{fail ? 'enable' : ''}}"><view class="text">刷新失败</view></view>
                <smt-feed
                    class="smt-feed auto-refresh-fail"
                    ext-cls-feed="custom-cls-feed"
                    theme="{{theme}}"
                    disable-touch
                >
                     <view class="list {{theme}}">
                        <view
                            class="{{'list-item ' + (val === 1 ? 'first' : '')}}"
                            s-for="val in list"
                            style="{{theme === 'dark' ? 'border-bottom: solid 1px rgba(255, 255, 255, .2);' : 'border-bottom: solid 1px #e0e0e0;'}}"
                            key="{{val}}"
                        >
                            <view class="left">
                                <view class="row begin"></view>
                                <view class="row center"></view>
                                <view class="row end"></view>
                            </view>
                            <view class="right"></view>
                        </view>
                    </view>
                </smt-feed>
            </view>
        </view>
    
        <view class="theme-control {{theme}}" >
            <text>沉浸式主题</text>
            <switch class="switch" color="{{dark ? '#f5f5f5' : '#ddd'}}" bind:change="themeChange"></switch>
        </view>
    </view>
    
    
    {
        "navigationBarTitleText": "刷新",
        "usingComponents": {
            "smt-feed": "@smt-ui/component/src/feed"
        },
        "navigationStyle": "default",
        "disableSwipeBack": true
    }
    
    
    import {selComponent, syncSetData} from '@smt-ui/component/src/common/utils';
    
    const systemInfo = (() => {
        let info = {};
        try {
            info = swan.getSystemInfoSync();
        }
        catch (err) {
            throw '获取系统信息错误: ' + err;
        }
        return info;
    })();
    
    Page({ // eslint-disable-line
        data: {
            list: [1, 2, 3],
            autoRefreshText: '不超过18个字',
            pullText: '',
            theme: 'dark',
            fail: false,
            statusBarHeight: systemInfo.statusBarHeight
        },
    
        /**
         * 请求时长1200ms
         *
         * @param {number=} ms 默认1200毫秒
         * @return {Promise}
         */
        async fetchData(ms = 1200) {
            const empty = Math.random() > .7;
            const data = {
                code: 0,
                data: empty ? null : Array.from({length: Math.random() * 10 + 10 | 0}, (_, i) => i)
            };
            return new Promise(r => setTimeout(() => r(data), ms));
        },
    
        async guide() {
            const refresh = await selComponent(this, '.pull-down-refresh');
            refresh.startRefresh();
            this.onRefresh();
        },
    
        /**
         * 触发刷新时回调
         */
        async onRefresh() {
            const refresh = await selComponent(this, '.pull-down-refresh');
            const {data: list} = await this.fetchData();
            await new Promise(r => setTimeout(r, 300));
            await syncSetData(this, {
                pullText: list ? `为你推荐${list.length}条更新` : '暂时没有更新,休息一下'
            });
            refresh.stopRefresh();
        },
    
        // 阻止冒泡: 多点触控在滚动的页面上会出问题
        noop() {},
    
        /**
         * 自动加载
         *
         * @param {boolean} fail 是否失败
         */
        async autoRefresh(fail) {
            const clkRefresh = await selComponent(this, '.auto-refresh' + (fail ? '-fail' : ''));
            const autoLoad = async () => {
                clkRefresh.startRefresh();
                const {data: list} = await this.fetchData();
                await new Promise(r => setTimeout(r, 300));
                if (fail) {
                    await clkRefresh.closeLoading();
                    await syncSetData(this, {fail});
                    await new Promise(r => setTimeout(r, 3000));
                    await syncSetData(this, {fail: false});
                    return await autoLoad();
                }
                await syncSetData(this, {
                    list: list || this.data.list,
                    autoRefreshText: list ? `为你推荐${list.length}条更新` : '暂时没有更新,休息一下'
                });
                await clkRefresh.stopRefresh();
                await new Promise(r => setTimeout(r, 500)); // 加载完一轮等500ms
                await autoLoad();
            };
            autoLoad();
        },
    
        themeChange({detail}) {
            const checked = detail.checked;
            this.setData({
                theme: checked ? 'dark' : ''
            });
    
            swan.setBackgroundColor({
                backgroundColor: checked ? '#3670c2' : '#f5f5f5'
            });
        },
    
        swtichHdl({detail}) {
            const checked = detail.checked;
            this.setData({
                theme: checked ? 'dark' : ''
            });
        },
    
        onReady() {
            swan.setBackgroundColor({
                backgroundColor: '#f5f5f5'
            });
            this.setData({dark: false});
            this.autoRefresh();
            this.autoRefresh(true);
            this.guide();
        }
    });
    
    
    * {
        margin: 1;
        padding: 0;
        box-sizing: border-box;
    }
    
    .container {
        font-size: .16rem;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        min-height: 100%;
    }
    .mode-title {
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: .16rem;
        color: #000;
        font-family: PingFangSC-Medium;
    }
    
    .mode-title-text {
        margin: 0 .12rem;
    }
    
    .mode-title-line-left {
        border-radius: 3px;
        height: 1px;
        width: .23rem;
        background-image: linear-gradient(90deg, #f5f5f5 0%, #d5d5d5 100%);
    }
    
    .mode-title-line-right {
        border-radius: 3px;
        height: 1px;
        width: .23rem;
        background-image: linear-gradient(-90deg, #f5f5f5 0%, #d5d5d5 100%);
    }
    
    .theme-control{
        width: 100%;
    }
    
    .refresh-wrap {
        margin-bottom: .4rem;
    }
    
    .smt-card-area {
        margin-top: .14rem;
    }
    
    .smt-card-area.fail {
        position: relative;
    }
    
    .smt-card-area .fail {
        display: flex;
        position: absolute;
        z-index: 1;
        height: 100%;
        width: 100%;
        top: 0;
        left: 0;
        opacity: 0;
        transition: opacity 120ms linear;
        align-items: center;
        justify-content: center;
    }
    
    .smt-card-area .fail.enable {
        opacity: 1;
    }
    
    .smt-card-area .fail.enable .text {
        display: flex;
        background-color: rgba(0, 0, 0, .8);
        color: #fff;
        height: .43rem;
        padding: 0 .17rem;
        align-items: center;
        border-radius: .08rem;
    }
    
    .container {
        padding-top: .167rem;
        padding-bottom: .85rem;
        background-color: #f5f5f5;
        transition: background-color 200ms linear;
    }
    
    .smt-feed {
        height: 3.51rem;
        display: block;
        background-color: #fff;
    }
    
    .smt-feed.dark {
        background-color: #fbfbfb;
    }
    
    .card-area.theme {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: .16rem .17rem;
    }
    
    .card-area.theme .line-02 {
        color: #999;
        margin-top: .05rem;
        font-size: .14rem;
    }
    
    .theme-control {
        display: flex;
        height: .58rem;
        padding: 0 .17rem;
        margin-top: .1rem;
        align-items: center;
        justify-content: space-between;
        font-size: .16rem;
        background-color: #fff;
        transition: background-color 200ms linear;
    }
    
    .theme-control.dark {
        background-color: #4985da;
        color: #fff;
    }
    
    .mode-title-line.dark {
        color: #fff;
    }
    
    .mode-title.dark .mode-title-text {
        color: #fff;
        transition: color 200ms linear;
    }
    
    .mode-title.dark .mode-title-line-left {
        background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, .3) 100%);
        transition: background-image 200ms linear;
    }
    
    .mode-title.dark .mode-title-line-right {
        background-image: linear-gradient(90deg, rgba(255, 255, 255, .3) 0%, rgba(255, 255, 255, 0) 100%);
        transition: background-image 200ms linear;
    }
    
    .dark {
        background-color: #3670c2;
    }
    
    .dark .custom-cls-loading {
        background-color: #fff;
    }
    
    .dark .switch .swan-switch-input:after {
        background-color: #38f;
    }
    .list {
        transition: background-color 200ms linear;
        padding: 0 .17rem;
    }
    
    .list-item {
        display: flex;
        justify-content: space-between;
        height: 1.17rem;
        box-sizing: border-box;
        flex: none;
        padding: .17rem 0;
        color: #fff;
    }
    
    .list-item .left {
        display: flex;
        flex: auto;
        flex-flow: column nowrap;
    }
    
    .list-item .left .row {
        width: 100%;
        height: .19rem;
        background: #e0e0e0;
        transition: background-color 200ms linear;
        margin-bottom: .06rem;
    }
    
    .list-item .left .row.end {
        height: .12rem;
        margin-top: .27rem;
        margin-bottom: 0;
        width: 1.15rem;
    }
    
    .list-item .right {
        display: flex;
        justify-content: center;
        align-items: center;
        color: #ccc;
        width: 1.24rem;
        height: .83rem;
        margin-left: .17rem;
        border-radius: .03rem;
        background: #e0e0e0;
        transition: background-color 200ms linear;
    }
    
    .list.dark {
        background-color: transparent;
    }
    
    .list.dark .list-item .left .row,
    .list.dark .list-item .right {
        background-color: rgba(255, 255, 255, .2);
    }