AlloyTouch實現下拉重新整理

【當耐特】發表於2017-01-09

原文地址:https://github.com/AlloyTeam/AlloyTouch/wiki/Pull-to-refresh

效果展示

AlloyTouch實現下拉重新整理

掃碼體驗

AlloyTouch實現下拉重新整理

你也可以點選這裡訪問Demo
可以點選這裡檢視程式碼

背景

在手機QQ內部,其實客戶端提供了下拉重新整理的能力,拖動整個webview進行下拉重新整理,loading以及loading相關的wording和動畫都是客戶端的。解決了一部分需要下拉場景的問題。但是在某些場景下,還是需要web擁有自身的下拉重新整理的能力。比如:

  • 需要統一IOS和安卓的體驗
  • 需要自定義下拉重新整理動畫
  • 需要已web內的背景或者其他Dom元素有聯動互動反饋

而拖動整個webview的下拉重新整理無法滿足這些場景。AlloyTouch很明顯非常擅長處理web下拉重新整理的需求。

頁面骨架實現

AlloyTouch實現下拉重新整理

pullRefresh在AlloyTouch header的下面,其中:
header zIndex > pullRefresh zIndex >wrapper和scroller的 zIndex。

下拉動畫實現

看以看到,下拉到一定程度,箭頭有個旋轉動畫,以及wording描述也會變化。這裡主要利用js去切換class去實現,動畫使用CSS transition實現。所以要預先定義好兩種class。

.arrow {
    margin-top: 5px;
    margin-bottom: 5px;
}

.arrow:after {
    content: "Pull to refresh";
}
    
.arrow_up.arrow:after {
    content: "Release to refresh";
}

.arrow_up img {
    transform: rotateZ(180deg);
    -webkit-transform: rotateZ(180deg);
}

.pull_refresh img {
    width: 20px;
    transition: transform .4s ease;
}

通過上面定要好的class,在js邏輯裡面只需要負責remove和add arrow_up clas便可以實現箭頭旋轉和wording的切換。

Loading動畫實現

<svg width='40px' height='40px' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" class="uil-default">
    <rect x="0" y="0" width="100" height="100" fill="none" class="bk"></rect><rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' fill='#00a9f2' transform='rotate(0 50 50) translate(0 -30)'>
        <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0s' repeatCount='indefinite' />
    </rect><rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' fill='#00a9f2' transform='rotate(30 50 50) translate(0 -30)'>
        <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.08333333333333333s' repeatCount='indefinite' />
       ...
       ...
</svg>

loading效果使用SVG去實現,利用12個rect的 indefinite animate去實現。begin代表開始時間有個遞增達到loading的效果。

核心實現

var scroller = document.querySelector("#scroller"),
    arrow = document.querySelector("#arrow"),
    pull_refresh = document.querySelector("#pull_refresh"),
    list = document.querySelector("#list"),
    index = 0;

//給pull_refresh注入transform屬性並且關閉透視投影
Transform(pull_refresh, true);
//給scroller注入transform屬性並且關閉透視投影
Transform(scroller, true);

new AlloyTouch({
    touch: "#wrapper",
    target: scroller, 
    property: "translateY",  
    initialVaule: 0,
    min: window.innerHeight - 45 - 48 - 2000, 
    max: 0,
    change: function (value) {
        //pull_refresh的translateY由scroller的value決定,所以向下拉scroller的時候,可以拉動pull_refresh
        pull_refresh.translateY = value;
    },
    touchMove: function (evt, value) {
        if (value > 70) { //當下拉到達70px的時候下箭頭變成上箭頭並且修改wording
            //為了程式碼簡潔,直接使用classList
            //http://caniuse.com/#search=classList
            //下箭頭變成上箭頭並且修改wording
            arrow.classList.add("arrow_up");
        } else {  //當下拉未到達70px上箭頭變成下箭頭並且修改wording
            arrow.classList.remove("arrow_up");
        }
    },
    touchEnd: function (evt, value) {
        if (value > 70) {
            //運動到60px的地方,用來顯示loading
            this.to(60);
            //模擬請求~~~
            mockRequest(this);
            //return false很重要,用來防止執行alloytouch內部超出邊界的回彈和慣性運動
            return false;
        }
    }
});

//模擬請求~~~
function mockRequest(at) {
    //顯示loading~~
    pull_refresh.classList.add("refreshing");
    //模擬cgi請求
    setTimeout(function () {
        var i = 0,
            len = 3;
        for (; i < len; i++) {
            var li = document.createElement("li");
            li.innerHTML = "new row " + index++;
            list.insertBefore(li, list.firstChild);
        }
        //重置下拉箭頭和wording
        arrow.classList.remove("arrow_up");
        //移除loading
        pull_refresh.classList.remove("refreshing");
        //回到初始值
        at.to(at.initialVaule);
        //由於加了三個li,每個li高度為40,所以min要變得更小
        at.min -= 40 * 3;
    }, 500);
}

不廢話,都在註釋裡。

開始AlloyTouch

Github:https://github.com/AlloyTeam/AlloyTouch

任何意見和建議歡迎new issue,AlloyTouch團隊會第一時間反饋。

相關文章