yaogengzhu / Learning-notes

基础回顾、笔记
1 stars 0 forks source link

如何监听dom元素触底, 实现下拉刷新(2020-11-14) #10

Open yaogengzhu opened 3 years ago

yaogengzhu commented 3 years ago

方式1: IntersectionObserver

import React, { useCallback, useRef } from 'react'
import { createUseStyles } from 'react-jss'

const styeles = createUseStyles({
    box: {
        width: '100%',
        height: '100px'
    }
})
export const Demo = () => {
    const classes = styeles()

    const observerRef: any = useRef()

    const lastBooksEelmentRef = useCallback((node) => {

        if (observerRef.current) {
            observerRef.current.disconnect()
        }

        observerRef.current = new IntersectionObserver((entries) => {
            console.log('entries', entries[0])
            if (entries[0].isIntersecting) {
                console.log('visiable')
            }
        })
        if (node) {
            return observerRef.current.observe(node)
        }
    }, [])

    const arr = Array.from({length: 20}, (v, k) => k)

    return (
        <div onClickCapture={(e) => {
            console.log(e, 'e')
        }}>
            {
                arr.map((item, index: number) => {
                    if (arr.length === index + 1) {
                        return <div key={item} className={ classes.box } ref={lastBooksEelmentRef}>{ item }</div>
                    } else {
                        return <div key={item} className={ classes.box }>{ item }</div>
                    }
                })
            }
        </div>
    )
}
yaogengzhu commented 3 years ago

补充一个 onScrollCapture

import { Column } from '@/components/layout/base'
import React from 'react'
import { createUseStyles } from 'react-jss'

const styeles = createUseStyles({
    box: {
        width: '100%',
        height: '100px'
    }
})
export const Demo = () => {
    const classes = styeles()
    const arr = Array.from({length: 20}, (v, k) => k)

    return (
        <Column style={{ height: '100vh', overflow: 'hidden'}}>
           <div
            style={{ overflow: 'auto'}}
            onScrollCapture={(e) => {
                // 容器高度 - 容器向上滚动的高度 - 当前视口的高度 === 0 表示触底。
                if (e.currentTarget.scrollHeight - e.currentTarget.scrollTop - e.currentTarget.clientHeight === 0) {
                    console.log('触底了, ----')
                }
            }}
            >
                {
                    arr.map((item, index: number) => {
                        if (arr.length === index + 1) {
                            return <div key={item} className={ classes.box }>{ item }</div>
                        } else {
                            return <div key={item} className={ classes.box }>{ item }</div>
                        }
                    })
                }
           </div>
        </Column>
    )
}
yaogengzhu commented 3 years ago

demo 测试

import { useEffect, useState } from 'react'
import axios, { Canceler } from 'axios'

export function UsesearchBoos(query: string, pageNums: number) {
    const [books, setBooks] = useState([])
    const [loading, setLoading] = useState(true)
    const [hasMore, setHasMore] = useState(false)

    useEffect(() => {
        setBooks([])
    }, [query])

    useEffect(() => {
        setLoading(true)
        let cancel: Canceler
        axios({
            method: 'GET',
            url: 'https://openlibrary.org/search/subjects.json',
            params: {
                q: query,
                page: pageNums
            },
            cancelToken: new axios.CancelToken( c => cancel = c)
        }).then( res => {
            console.log(res.data.docs)
            setBooks((prevBoos): any => {
                return [...prevBoos, ...res.data.docs.map( (i: { name: string }) => i.name)]
            })
            setHasMore(res.data.docs.length > 0)
        }).catch( e => {
            console.log(e)
        }).finally(() => {
            setLoading(false)
        })

        return () => cancel()
    }, [query, pageNums])

    return {
        books,
        loading,
        hasMore
    }
}
yaogengzhu commented 3 years ago

example

import { Column } from '@/components/layout/base'
import uuidv4 from '@/utils'
import React, { useState } from 'react'
import { createUseStyles } from 'react-jss'
import { UsesearchBoos } from './searchBooks'

const styeles = createUseStyles({
    box: {
        width: '100%',
        height: '100px'
    },
    loading: {
        width: '100%',
        height: '50px',
        backgroundColor: 'pink',
        fontSize: '20px',
        color: '#fff'
    }
})
export const Demo = () => {
    const [page , setpage] = useState(1)
    const [keyword, setKeyword] = useState('')
    const classes = styeles()

    const { books, loading, hasMore } = UsesearchBoos(keyword, page)

    const onChange = (e: any) => {
        setKeyword(e.target.value)
    }

    return (
        <Column style={{ height: '100vh', overflow: 'hidden'}}>
           <div
            style={{ overflow: 'auto'}}
            onScrollCapture={(e) => {
                // 容器高度 - 容器向上滚动的高度 - 当前视口的高度 === 0 表示触底。
                if (e.currentTarget.scrollHeight - e.currentTarget.scrollTop - e.currentTarget.clientHeight === 0) {
                    // console.log('触底了, ----')
                    if (hasMore && !loading) {
                        setpage((prvePage) => {
                            return prvePage + 1
                        })
                    }
                }
            }}
            >
                <input type="text" value={ keyword}  onChange={ onChange } />
                {
                    books.map((item: any, index: number) => {
                        return <div className={ classes.box } key={ uuidv4() }>{ item }</div>
                    })
                }
                { page !== 1 && loading && <div className={ [classes.loading, 'center', classes.loading ].join(' ')} >加载中....</div>}
           </div>
        </Column>
    )
}