成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

下拉刷新,上拉加載 的基礎(chǔ)款(基本實(shí)現(xiàn))

Cciradih / 3418人閱讀

摘要:前言現(xiàn)在網(wǎng)上下拉刷新,上拉加載插件一搜一大堆,如果你想用在生產(chǎn)環(huán)境,那你可以直接網(wǎng)上搜一個(gè)靠譜的,我所做的就是不依賴任何插件,一步一步把這個(gè)插件的過程寫一下,各位同學(xué)可以在此基礎(chǔ)上定制,沒有寫過插件的,可以了解下插件怎么寫的,整個(gè)過程定位入

前言

現(xiàn)在網(wǎng)上 下拉刷新,上拉加載 插件一搜一大堆,如果你想用在生產(chǎn)環(huán)境,那你可以直接網(wǎng)上搜一個(gè)靠譜的,我所做的就是不依賴任何插件,一步一步把這個(gè)插件的過程寫一下,各位同學(xué)可以在此基礎(chǔ)上定制,沒有寫過插件的,可以了解下插件怎么寫的,整個(gè)過程定位入門級(jí),看不懂?那么百度插件直接用就好了,修煉一段時(shí)間在考慮怎么寫插件吧。廢話不多說,上效果圖

原理

下拉刷新的原理就是,添加一個(gè) div,這個(gè) div 里面標(biāo)識(shí)加載的過程,根據(jù)拉下的距離改變div的高度,從而顯示 下拉加載 的文字,松手后根據(jù)下拉的距離,判斷是否請(qǐng)求數(shù)據(jù)

構(gòu)建過程

定義默認(rèn)的一些配置項(xiàng)

var defaults = {
    threshold: 100,   // 滑動(dòng)觸發(fā)下拉刷新的距離
    stop: 40,         // 下拉刷新時(shí)停留的位置距離屏幕頂部的距離
    dis: 20           // 距離屏幕底端觸發(fā) 上拉加載 的距離
}

定義構(gòu)造函數(shù)

function JrRefresh (el, options) {
    this.options = Object.assign({}, defaults, options)  // 合并參數(shù)
    this.el = typeof el === "string" ? document.querySelector(el) : el  // 定義要操作對(duì)象
    this.progress = null       // 下拉刷新顯示的 dom
    this.loadMore = null       // 上拉加載顯示的 dom
    this.progressHeight = 0    // 下拉刷新的 dom 的高度
    this.rotate = null         // 下拉刷新 轉(zhuǎn)圈 的角度
    this.touchstartY = 0       // 觸摸到屏幕的坐標(biāo)起始 Y 值
    this.currentY = 0          // 移動(dòng)時(shí)實(shí)時(shí)記錄的坐標(biāo) Y 值
    this.isAnimation = false   // 是否在自動(dòng)回滾
    this.isRefresh = false     // 是否正在刷新數(shù)據(jù)
    this.isLoadMore = false    // 是否正在加載數(shù)據(jù)
    this.hasMore = true        // 是否有更多數(shù)據(jù), 下拉加載會(huì)用
    this.rotateTimer = null    // 控制 下拉刷新 轉(zhuǎn)圈 的時(shí)間計(jì)時(shí)器
    this.event()
    this.init()
}

初始化,添加一些需要用到的 dom 元素

JrRefresh.prototype.init = function () {
    // 增加下拉刷新的顯示
    var refreshHtml = `

下拉刷新

` var divm = document.createElement("div") divm.innerHTML = refreshHtml this.progress = divm.children[0] this.el.prepend(this.progress) // 增加上拉加載的顯示 var loadMoreHtml = `` var div = document.createElement("div") div.innerHTML = loadMoreHtml this.loadMore = div.children[0] this.el.appendChild(this.loadMore) }

定義事件,解釋一下這里用到的 bind 吧,這里的 JrRefresh.prototype.pullDown、JrRefresh.prototype.touchend 等函數(shù)里的 this 綁定到 JrRefresh 的構(gòu)造函數(shù)上, 如果不用的話,pullDown 函數(shù)是由 this.el 調(diào)用的,this 會(huì)指向 this.el。(假裝你們都懂了?)這是寫插件常用到一種綁定 this 的方法之一

JrRefresh.prototype.event = function () {
    this.el.addEventListener("touchstart", this.handleTouchStart.bind(this))
    this.el.addEventListener("touchmove", this.pullDown.bind(this))
    this.el.addEventListener("touchend", this.touchend.bind(this))
    window.addEventListener("scroll", this.handleScroll.bind(this))
}

手指觸摸時(shí)記錄Y值坐標(biāo),用來判斷是向上滑還是向下

JrRefresh.prototype.handleTouchStart = function (e) {
    // 記錄手指觸摸屏幕的 Y 值坐標(biāo)
    this.touchstartY = e.changedTouches[0].clientY
}

手指開始滑動(dòng)時(shí),觸發(fā) pullDown 事件,用 this.currentY 來記錄實(shí)時(shí)的 Y 值坐標(biāo),當(dāng) this.currentY - this.touchstartY > 0 時(shí),說明是手指向下滑動(dòng),這里面 e.preventDefault() 是為了防止微信還有 ios 的瀏覽器下拉時(shí)頂部出現(xiàn)出現(xiàn)默認(rèn)的黑色空白,或者觸發(fā) uc 等瀏覽器自帶的下拉刷新, 由 this.moveDown 專門來控制 下拉刷新顯示的dom(this.progress) 的高度

JrRefresh.prototype.pullDown = function (e) {
    var scrollTop = document.documentElement.scrollTop ||
                    window.pageYOffset ||
                    document.body.scrollTop
    this.currentY = e.targetTouches[0].clientY
    if (this.currentY - this.touchstartY >= 0 && scrollTop <= 0) {
        e.preventDefault()
        if (!this.isAnimation && !this.isRefresh) {
            this.moveDown(this.currentY - this.touchstartY)
        }
    }
}

moveDown 函數(shù)是用來專門控制 this.progress 的高度,rotateProgress 函數(shù)用來專門控制圈圈的旋轉(zhuǎn)角度 changeProgressState 函數(shù)用來專門控制this.progress 顯示內(nèi)容

JrRefresh.prototype.moveDown = function (dis) {
    if (dis < this.options.threshold) {
        this.progress.style.height = this.progressHeight + dis + "px"
        this.rotateProgress(dis*2)
        this.changeProgressState("下拉刷新")
    } else {
        // 當(dāng)滑動(dòng)距離超過 threshold 時(shí),放慢下拉速度
        var aftDis = this.options.threshold + (dis - this.options.threshold) / 3
        var aftAngle = this.options.threshold * 2 + (dis - this.options.threshold) / 1.7
        this.progress.style.height = this.progressHeight + aftDis + "px"
        this.rotateProgress(aftAngle)
        this.changeProgressState("釋放刷新")
    }
}

圈圈只有兩種情況,一種隨手指移動(dòng),超過距離轉(zhuǎn)圈速度變慢,一種是自己不停轉(zhuǎn),前一種情況,手指下滑距離跟旋轉(zhuǎn)角度的比例并不一定按我這個(gè)寫法,主要有一點(diǎn),就是轉(zhuǎn)動(dòng)變慢時(shí)候,圈圈旋轉(zhuǎn)角度不要出現(xiàn)突變,這也是這個(gè)插件的難點(diǎn)之一,不懂的同學(xué)多看多想哈

JrRefresh.prototype.rotateProgress = function (rotate) {
    var rotateDom = this.progress.querySelector(".downwarp-progress")
    if (rotate != undefined) {
        rotateDom.style.transform = "rotate(" + rotate + "deg)"
        this.rotate = rotate
    } else {
        var t = 0;
        this.rotateTimer = setInterval(() => {
            t++
            var angle = (this.rotate + t*15) % 360
            rotateDom.style.transform = "rotate(" + angle + "deg)"
            rotateDom.style.WebkitTransform = "rotate(" + angle + "deg)"
        }, 16)
    }
}

changeProgressState 這個(gè)函數(shù)沒什么好說的了

JrRefresh.prototype.changeProgressState = function (name) {
    this.progress.querySelector(".downwarp-tip").innerHTML = name
}

至此,下滑效果有點(diǎn)樣子了,下面是手指松開時(shí)候的邏輯

JrRefresh.prototype.touchend = function () {
    var scrollTop = document.documentElement.scrollTop ||
                    window.pageYOffset ||
                    document.body.scrollTop
    if (scrollTop > 0 || this.isRefresh|| this.isAnimation) return     //只有 1.在屏幕頂部 2.已完成請(qǐng)求數(shù)據(jù) 3.不在回滾 三條都滿足才進(jìn)行處理
    if ((this.currentY - this.touchstartY) > this.options.threshold) {
        this.options.downCallback()  // 觸發(fā)參數(shù)穿過來的請(qǐng)求數(shù)據(jù)
        this.isRefresh = true
        this.moveBack(this.options.stop)            // 下拉刷新時(shí)停留的位置距離屏幕頂部的距離

    } else  {
        this.moveBack()
    }

}

moveBack 函數(shù)專門把進(jìn)度返回到對(duì)應(yīng)位置

JrRefresh.prototype.moveBack = function (dis) {
    var dis = dis || 0;
    this.isAnimation = true   // 正在回退
    var currentHeight = this.progress.offsetHeight
    var t = 0,                        // 進(jìn)行的步數(shù)
        b = 10,                       // 總步數(shù)
        c = (currentHeight - dis)/b   // 每一步的距離
    var timer = setInterval(() => {
        t++;
        this.progress.style.height = currentHeight - c * t + "px"
        if (t == b) {
            if (dis === 0) {
                this.changeProgressState("下拉刷新")     
                this.progressHeight = 0
            } else {
                this.changeProgressState("正在刷新")
                this.progressHeight = this.options.stop
                this.rotateProgress()
            }
            this.touchstartY = ""
            this.isAnimation = false     // 回退完成
            clearInterval(timer) 
        }
    }, 16)
}

當(dāng)請(qǐng)求數(shù)據(jù)完成,要回滾到原始位置,參數(shù)是 boolean 類型,表明有沒有更多數(shù)據(jù)

JrRefresh.prototype.endSuccess = function (bool) {
    if (this.isRefresh) {      //  如果是正在刷新數(shù)據(jù)
        this.changeProgressState("刷新成功")
        if (bool) {
            setTimeout(() => {     //延遲 500ms 回滾
                this.moveBack(0)
                this.isRefresh = false
                clearInterval(this.rotateTimer)
            },500)
        } else {
            this.toggleLoadingText(true)
        }
    }
    if (this.isLoadMore) {     //  如果是正在加載數(shù)據(jù)
        this.isLoadMore = false
        this.loadMore.style.visibility = "hidden"
        this.toggleLoadingText(bool)
    }
}
JrRefresh.prototype.toggleLoadingText = function (hasMore) {
    if (hasMore) {
        this.loadMore.querySelector(".upwarp-tip").innerHTML = "加載中..."
        this.loadMore.querySelector(".upwarp-progress").style.display = "inline-block"
    } else {
        this.loadMore.style.visibility = "visible"
        this.loadMore.querySelector(".upwarp-tip").innerHTML = "沒有更多數(shù)據(jù)了"
        this.loadMore.querySelector(".upwarp-progress").style.display = "none"
    }
}

至此,下拉刷新的邏輯終于完成了,下面開始上拉加載,比較麻煩的是獲取頁(yè)面高度,數(shù)據(jù)過來的同時(shí)請(qǐng)求頁(yè)面高度,頁(yè)面還沒有渲染完成,頁(yè)面高度可能會(huì)不準(zhǔn),所以我處理方法是延遲100ms 獲取高度,

JrRefresh.prototype.handleScroll = function () {
    var top = this.loadMore.getBoundingClientRect().top;    // 獲取最底部標(biāo)簽距離屏幕頂部的距離
    if (top + 10 < window.innerHeight && !this.isLoadMore && this.hasMore) {
        this.isLoadMore = true
        this.loadMore.style.visibility = "visible"
        this.options.up.callback()
    }
}
用法
//列表內(nèi)容,如:
    列表數(shù)據(jù)
..

好了,大致就介紹這么多,想看源碼的同學(xué),移步這里,后續(xù)的完善和更新也會(huì)在 github 上,有興趣的同學(xué) star 或者 fork 哦

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/51797.html

相關(guān)文章

  • 下拉刷新,拉加 基礎(chǔ)基本實(shí)現(xiàn)

    摘要:前言現(xiàn)在網(wǎng)上下拉刷新,上拉加載插件一搜一大堆,如果你想用在生產(chǎn)環(huán)境,那你可以直接網(wǎng)上搜一個(gè)靠譜的,我所做的就是不依賴任何插件,一步一步把這個(gè)插件的過程寫一下,各位同學(xué)可以在此基礎(chǔ)上定制,沒有寫過插件的,可以了解下插件怎么寫的,整個(gè)過程定位入 前言 現(xiàn)在網(wǎng)上 下拉刷新,上拉加載 插件一搜一大堆,如果你想用在生產(chǎn)環(huán)境,那你可以直接網(wǎng)上搜一個(gè)靠譜的,我所做的就是不依賴任何插件,一步一步把這個(gè)...

    DrizzleX 評(píng)論0 收藏0
  • listloading 一個(gè)移動(dòng)端拉、下拉更多組件

    摘要:是一個(gè)移動(dòng)端的上拉下拉加載更多的組件。因?yàn)樵诠?jié)點(diǎn)元素創(chuàng)建之前,必須先設(shè)定高度,否則會(huì)導(dǎo)致無法滾動(dòng)創(chuàng)建完畢是指定給第一個(gè)子元素滾動(dòng),所以的上拉和下拉刷新也是追加到第一個(gè)子元素里面,其實(shí)把第一個(gè)子元素想象成為里面的就可以了。 listloading.js listloading是一個(gè)移動(dòng)端的上拉、下拉加載更多的組件。主要依賴于iscroll.js v5.1.2基礎(chǔ)上開發(fā)的組件,基礎(chǔ)庫(kù)可以使...

    jeyhan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<