源码 - mmrxia/js-pull-to-refresh GitHub Wiki

/* global define, Roll */ (function(window, document, Roll) { 'use strict'

var rAF = window.requestAnimationFrame || window.webkitRequestAnimationFrame || function(callback) {
    setTimeout(callback, 17)
}
var TSF = Roll.utils.TSF
var moveTo = Roll.utils.moveTo
var IMG_LOADING = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAEU0lEQVRoQ+1aXVITQRDuXs3yKJ7AWEU2vhmqTF6NJxBOIJzAcALwBOIJhBMAJyC+Zq0yPmaWKsMJwEcG3LZ6zaR2k/nbdQUs3dfM9PQ3/fU3PT1BKPm1Wt2tAPFjmWlEdIkAY0K8BIAxpul4cvb5pIwN01isYqQKCN06BHAMAMdCjA6r+MFzKgHgiXWBYFscIUDcl1J+mE7HHCXvrzKAukHkgAzKRMQLQLPZWQ3DsC/EiENe+OqMxNww0fDq+nrTJxpOAK1WtxMgHgFAMyXaTpL44DZAMK0I4FWSxGMbn6wA2HkEOEXEVWWkLAiU8unNw4fNIAjYRgeJ+oD40ofks9zY1kVezTcC0DlfBcREjJbWYEo2Go0NRBwgwHMXmB9p+urs7PNQN04LwOa8MkIAmz45oQOQd2SWQ3sA8MQExEYn7e6shOEX5rzRIMA7IUa8qPbLJ7YLgDIQtboHiPjGEo3plZTri4m9BCCKekcIsGEyZMoBU2L7AvCRZT74hBht5tcqAFhbe9F/EASnOueJ6DsB9F2qsEgPnWrZOB9FvQ0EYNXTfovULQBoR71vJur47rwrIX1+b6+9GEAQvDeMnU7E6OmSCtkOJHJw3sepsmNsOZHfzHkELLt/PhEjY0KXdcx3PEvtShjyIaZTp3kUMgA23tk02NeZquMcrMhk/BcAk4QRfZokcb+qA3XMa0e9qS4KRHQoknhLAbjIlwtq4dtMXJ8zJT+GDzeRxI/RJp1XUj72qQjr2GmTjWfNTpPCkNVx6UuJ1tEoWfeAPsrjKOqNtTVTmu5gu9XdB8S3i/DuQjpNUYii3h4C7C79TvSBAQx15a2pWPuTdDHZtrHECOAu5XMRiDFPiT79B3AblPo3I3AfDrGcjOpL7FkO/N0yatJYIhqLJF6/DY671jBJPfBBdt9LiVlZfaEDyVKfFXPtqEeGWkPbyHLtWJ2/m0pqvuKKJF5V9wGuq18vlRP3gEbtVvcUEJdK+mI5bblI36UaWZsMs75U/kqpvTgAQOESXSc9XLaiVvcLInY04+bX3DkAY8X3q39/IJJ427Vgnb/b/NFe6rMWeqMxRcRHd53Qjpb9+ZWUHXXRKvSFXL1+vgGVaWzxRrDNMs0tV1/W2tjKJNVwP1BRKZvULNG+cxgsArzX3c95fQI4EWJUaHtqm7s2KrGhlGg/SeIdH86rM8YFIop6uwhgbBgDQIE6am1be31oyofZ5CkB7NgeHxYPSRMIW8JmO2/py9oeOPzeg4mGhHggpTzRdTAWT3kjCENvytVUdj0x+YGYhWT27jtOU8peU25urr+uhOFSHeMLwuU8r+H1yIcALjr5pENhjAeI85Row6V6TgC8alYRNhrHvo9zvmhsOSGl3PdpqnkBUA5xe4MQ9xzJ7et/Ns6lTi5jpQCoaIRhOACiQV1AfgdEaQBqR9RTaQCwVQe1qoKoDCAfWvVXBPWQTYh80XC+/y7SowqIn38e2kAN1dhNAAAAAElFTkSuQmCC'
var IMG_ARROW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAACWUlEQVRoQ+2ZQU7DMBBFZwIKW7hBF0nKjiA13VJuACegnAB6AsoJ6A0oJwBOQNkmSMCyThbcALZEIoOMCKqAJrY7EalItx7b/813bI+LsOQ/XHL90ADMOthq+etrtv1c6GqWDabJ3YjLeVYHHKfTW7GsmyJxBHAqRDhcZoBrIcK9pQUAottpHPVqCdB2OsdgWWeF4uoM8PERr672ybLW50EQ0VUcRw+1dIBLlM44rLuQzsRcsawAntcdItFO4TaK+CJEuF9LgLYbTACxEEAKn4qQLXFsA0lhnhvcI6Jflt3XNN14enp4KYtTaWcFaHtdUpn0Lct2k+RuohJbFtMAzGZIHmRFZ0Aem6bpqJZLqMzuKtpZl1AVAsvGZAPYbPmtzLbPkGjuNSIXkwEMuK4TbACe191DgMuyjMl2zpqAE2CIACf/AoCzJvgTB2oJ4LpB3wLoKy0hxAlXXczmgIrwKmIagDyrchsFgC3FLD8KEV4pxhaGsTmgehPN1XDVBA1AnlFdB7iKGm0HHCf4UTKuIPiAqPfeSXT8RvDjeSVJoludb0MLwHUD30K815lANzYj2ta56GkBSDEfBxbiua4wlfiM6DCOo7FKbB6jDVAVhIl4qcUIgBvCVPxCALJz2w1GgHikY/n32EVrA2MHvk5gNxgj4oEJBBFdiDhSugDOG39hADmwZwDBIX7hJTSbFR0ILvGsAKpOcIpnByiD4BZfCcA8iCrEVwYg/2qybXuCn/UBAcj7f+mrtclOxrIL/TZxDiHb0jTtcb2Ffp+rMgCTbJr0aQBMssbZ5x0jdQNAR+TKsgAAAABJRU5ErkJggg=='
var IMG_FINISH = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAADMklEQVRoQ+1ZS3LTQBDtFrFZEk6AqYoUdmiBvMU+AeEEOCcAn4BwgoQTJJyAcAJ7bacqYodHXjg3SJaRCjU1LqkYy9LMaCT5UxUv7emZ97pbr9/ICHv+wT3HD08ENlXBTsc9bLda52EUDRcL/z49dy8q8KbjduJW6yciuhDHw9n85mJvCNi25yLACBEPE9CLGZu83gsCtu0NLMRLsU1jotMgmF7tPAHb9s4txC8ieCL6wYLpQPxuJ58Bx/YuEXEFaB54TmSnCCRKw/vdXck8wG/GJivf7VwLFYEHgLvHMHRF6dy5FspRmiVGInoggF4QTP2iebP1FioCzwFnFSePxFYJHB2961mIfEClGv8fI9H3WTBdUaGdIpCn8SlAkjy0WRJbqYAUPNGDFUXun4W/0PFZGycgA6/b91tTIRV4AvjF2OREJ/MbnwMq8Cq936qMaoCHv3Hcn89vxmWyL7USjtM9IaL3QTAdlt1UXK8DHjQlU1tGxUOJyA+jqF80ymXkZENKiJNaBVXy1lQoL2MmJDTBG7dO7kOs0GffiqKPOvrMjdnzdvsWADqyDJqojnSQOU7XR4C3RYcS0T0B9GXmisc6tnebtcTZPblRC6OoY9KahXMguTz7iPjClETeZSR3r8zlXNXr2jKa9O5YRQIQTxmbXJdWHG6TS3gdFbFcK6ElfRm7m1SPt866s8ygMNV8bRld9rHTPUOAr6oMpJ792PZGgNhTrS+626ritFtIXOjY3hUiflJuTjTWBF/KaSrP1bnUq5RJ55B0DQF8Y2xyViZGtVZpp5eX7XZ7LJNX1SH897pkUzoHioDoKJOKhM79VrVHqYc4u5iTsBD5dDX53M3YRDqVTTblMcoWMtH5LJimsl+aAA84tr0LQPxcImONZd+IwHJG6Mqr5rudEslYW1qqhdLoEsrUaPaNK8ADE8vMX/m9Kspgk72fnmlUgTRYIa+NZ79SBVIS/PXgM8sabVJ5xLMqVUCoxMpfQXzqsmCqdKVVHt5aWkgEICpTE56niGwtFUg3d5zuNQJ8eAzDl1WvirrVqZXAUpkODgbi/7i6QEzX1UrAFESVuCcCVbJXR+w/WhqbQHiqjtIAAAAASUVORK5CYII='
var IMG_STYLE = 'width:24px;height:24px;display:block;'

Roll.prototype.pulldown = function(params) {
    var me = this
    var keys = Object.keys(params || {})

    var boxDiv
    var iconSpan
    var textSpan
    var loading
    var rotating
    var angle = 0

    // 默认选项
    var options = {
        iconArrow: "<img style='" + IMG_STYLE + "' src='" + IMG_ARROW + "'>",
        iconLoading: "<img style='" + IMG_STYLE + "' src='" + IMG_LOADING + "'>",
        iconFinish: "<img style='" + IMG_STYLE + "' src='" + IMG_FINISH + "'>",
        textPull: '下拉刷新',
        textRelease: '释放刷新',
        textLoading: '正在加载',
        textFinish: '刷新完成',
        spinning: true,
        // 应网友要求添加一个选项控制loading时是否旋转icon
        refresh: null// 刷新自定义执行的函数
    }

    for (var k in keys) {
        options[keys[k]] = params[keys[k]]
    }

    // 先行加载图片,触发浏览器缓存起来避免刷新时再加载显得不流畅
    document.createElement('div').innerHTML = options.iconArrow + options.iconLoading + options.iconFinish

    // 创建下拉的div
    boxDiv = document.createElement('div')
    boxDiv.className = 'roll-plugin-pulldown'
    boxDiv.style.cssText = 'position:absolute;top:-44px;width:100%;height:44px;line-height:44px;font-size:16px;text-align:center;'

    iconSpan = document.createElement('span')
    iconSpan.className = 'roll-plugin-pulldown-icon'
    iconSpan.style.cssText = 'display:inline-block;width:24px;height:24px;position:absolute;top:10px;left:25%;'
    iconSpan.innerHTML = options.iconArrow
    boxDiv.appendChild(iconSpan)

    textSpan = document.createElement('span')
    textSpan.className = 'roll-plugin-pulldown-text'
    textSpan.innerHTML = options.textPull
    boxDiv.appendChild(textSpan)

    me.wrapper.appendChild(boxDiv)

    // 监听滑动事件
    me.on('scroll', function() {
        boxDiv.style[TSF] = me.scroller.style[TSF]

        // 达到一定位置显示释放刷新
        if (!loading) {
            if (me.y > 44) {
                iconSpan.style[TSF] = 'rotateZ(180deg)'
                textSpan.innerHTML = options.textRelease
            } else {
                iconSpan.style[TSF] = 'rotateZ(0deg)'
                textSpan.innerHTML = options.textPull
            }
        }
    })
    me.on('touchEnd', function() {
        if (me.y >= 44) {
            // 超过44px禁止回弹
            me.y = 0
            me.options.momentum = false

            // 刷新
            iconSpan.style[TSF] = 'rotateZ(0deg)'
            iconSpan.innerHTML = options.iconLoading
            textSpan.innerHTML = options.textLoading
            setTimeout(function() {
                me.scrollTo(0, 44, 200, true, doRefresh).minScrollY = 44
                moveTo(boxDiv, 0, 44, 200)

                me.options.momentum = true
            }, 10)
        } else if (!loading) {
            moveTo(boxDiv, 0, 0, 200)
        }
    })

    // 执行刷新
    function doRefresh() {
        if (!loading) {
            loading = true
            rotating = true
            angle = 0
            if (options.spinning) {
                makeRotate()
            }
            setTimeout(function() {
                if (typeof options.refresh === 'function') {
                    options.refresh(function() {
                        // 完成刷新
                        rotating = false
                        iconSpan.innerHTML = options.iconFinish
                        textSpan.innerHTML = options.textFinish

                        // 收起刷新栏
                        setTimeout(function() {
                            moveTo(boxDiv, 0, 0, 200)

                            me.scrollTo(0, 0, 200, true, function() {
                                loading = false
                                iconSpan.innerHTML = options.iconArrow
                                textSpan.innerHTML = options.textPull
                            }).minScrollY = 0
                        }, 500)
                    })
                }
            }, 200)
        }
    }

    // 使iconSpan旋转下来
    function makeRotate() {
        angle = angle + 6 >= 360 ? 0 : angle + 6
        iconSpan.style[TSF] = 'rotateZ(' + angle + 'deg)'

        if (rotating) {
            rAF(makeRotate)
        } else {
            iconSpan.style[TSF] = 'rotateZ(0deg)'
        }
    }

    return me
}

Roll.prototype.pulldown.version = '{{version}}'

// CommonJS/AMD/CMD规范导出Roll
if (typeof module !== 'undefined' && module.exports) {
    module.exports = Roll
}
if (typeof define === 'function') {
    define(function() {
        return Roll
    })
}

} )(window, document, Roll)