React se encuentra con BetterScroll para lograr la carga desplegable y la actualización desplegable

I. Introducción

Recientemente, usé reaccionar para hacer una demostración que imitaba a bilibili. Necesitaba un contenedor de desplazamiento y debería tener las funciones de carga desplegable y actualización desplegable. Pensé que usaba mejor desplazamiento cuando usaba vue para hacer proyectos antes. , así que lo usé esta vez. Pongamos primero las representaciones finales.,,,

desplazamiento complejo use.gif

Dos: no se puede desplazar en mejor desplazamiento y soluciones
  • Algunos elementos se colocan en el contenedor de contenido pero no se pueden desplazar

    Confirme si la altura del contenedor de contenido excede el envoltorio

  • Cuando hay una imagen en el contenedor de contenido, a menudo no se desplaza hasta el final

    Debido a que es posible que la imagen no se cargue hasta que se genere la instancia de bs (better-scroll), lo que resulta en un error en la altura de cálculo de bs. La solución es que la etiqueta img tiene una función de devolución de llamada (onLoad), y el método de actualización de la bs instancia se llama en la función de devolución de llamada. , si hay muchas imágenes, es mejor agregar una capa de antivibración para optimizar el rendimiento

3: Compartiendo la experiencia de pisar el foso

Dado que hemos elegido mejor desplazamiento como contenedor de desplazamiento, definitivamente lo encapsularemos en una capa para facilitar nuestro uso, pero aquí, después de que el desplazamiento se extraiga y se encapsule en un componente, habrá un problema, que está envuelto en los hijos del componente de desplazamiento Suponiendo que hay una imagen, el método de actualización de desplazamiento no se puede llamar después de que se carga, así que aquí uso eventBus para manejar la operación de actualizar el desplazamiento después de que se carga la imagen

Tres: embalaje y uso
  • Primero instale better-scroll en el proyecto (sitio web oficial ( core scroll | BetterScroll 2.0 (better-scroll.github.io) ))

    hilo agregar mejor desplazamiento

  • Instale los componentes pull-up y pull-down en el index.js del proyecto y publique el código principal aquí

    import Pulldown from '@better-scroll/pull-down';
    import Pullup from '@better-scroll/pull-up';
    import BScroll from "@better-scroll/core";
    
    BScroll.use(Pulldown)
    BScroll.use(Pullup)
    复制代码
  • Instalar eventBus de nuevo

    añadir eventos de hilo

    Haga una capa de encapsulación en eventBus, que también es conveniente para nosotros de usar y mantener

    import {EventEmitter} from "events";
    
    const event = new EventEmitter();
    
    class EventUtils {
      static _instance = event;
    
      static emit(key, value = []) {
        this._instance.emit(key, ...value);
      }
    
      static addListener(key, callback) {
        this._instance.addListener(key, callback);
      }
    
      static removeListener(key, callback) {
        this._instance.removeListener(key, callback);
      }
    
    }
    
    class EventKey {
      static scrollRefresh(event = 'default') {
        return `${event}betterScrollRefresh`;
      }
    
      static scrollToTop(event = 'default') {
        return `${event}betterScrollToTop`;
      }
    }
    
    export {
      EventUtils,
      EventKey,
    }
    复制代码
  • Entonces el componente de desplazamiento

    import {debounceUtils} from "../../../utils/function_utils";
    import BScroll from "@better-scroll/core";
    import {useEffect, useRef, useState} from "react";
    import {EventUtils} from "../../../utils/event_utils";
    import {PullDownProgress} from "./pull_down_progress";
    import {BackTopButton} from "./back_top_button";
    
    const pullUpDebounce = debounceUtils()
    const pullDownDebounce = debounceUtils()
    const scrollDebounce = debounceUtils()
    
    class ScrollDirection {
      static vertical = 'vertical';
      static horizontal = 'horizontal';
    }
    
    export function AppScroll(props) {
      //  保存better-scroll实例,在副作用中初始化
      const [controller, setController] = useState(null);
      const wrapperRef = useRef();
      const {
        refreshKey = 'default',
        toKey = 'default',
        children = (<div>scroll默认的内容</div>),
        scrollWidth = '100%',
        scrollHeight = '100px',
        scrollBackground = 'rgba(229, 229, 229, 0.29)',
        direction = ScrollDirection.vertical,
        debounceDelay = 200,
        prototype = 1,
        click = true,
        showBackTop = false,
        showRefreshProgress = false,
        openPullDown = false,
        openPullUp = false,
        onRefresh = async () => {},
        onLoadMore = async () => {},
      } = props;
    
      const handlerPullDown = () => pullDownDebounce(
        async () => {
          if (controller === null) return;
          console.log('下拉');
          await onRefresh();
          controller.finishPullDown();
        }, debounceDelay
      );
    
      const handlerPullUp = () => pullUpDebounce(
        async () => {
          if (controller === null) return;
          console.log('上拉');
          await onLoadMore();
          controller.finishPullUp();
        }, debounceDelay
      );
    
      const handlerRefresh = () => scrollDebounce(
        () => {
          if (controller === null) return;
          console.log('刷新bs');
          controller.refresh();
        }, debounceDelay
      );
    
      const handlerBackTop = () => {
        if (controller === null) return;
        controller.scrollTo(0, 0, 300)
      }
    
      useEffect(() => {
        //  保存父组件或者新生成的better-scroll实例
        const instance = new BScroll(wrapperRef.current, {
          scrollX: direction === ScrollDirection.horizontal,
          scrollY: direction === ScrollDirection.vertical,
          pullDownRefresh: openPullDown,
          pullUpLoad: openPullUp,
          prototype: prototype,
          click: click
        });
        setController(instance);
        return () => {
          console.log('AppScroll 销毁');
          instance.destroy();
          setController(null);
        }
      }, [])
    
      useEffect(() => {
        //  给实例添加事件
        if (controller === null) return;
        if (openPullDown) {
          controller.on('pullingDown', handlerPullDown);
        }
        if (openPullUp) {
          controller.on('pullingUp', handlerPullUp);
        }
      }, [handlerPullDown, handlerPullUp])
    
      useEffect(() => {
        //  父组件通过eventBus给scroll组件传递事件
        //  刷新事件
        EventUtils.addListener(refreshKey, handlerRefresh);
        //  返回顶部事件
        EventUtils.addListener(toKey, handlerBackTop);
        return () => {
          EventUtils.removeListener(refreshKey, handlerRefresh);
          EventUtils.removeListener(toKey, handlerBackTop);
        }
      }, [controller, refreshKey, toKey])
    
      return (
        <div
          ref={wrapperRef}
          style={{
            width: scrollWidth,
            height: scrollHeight,
            background: scrollBackground,
            overflow: 'hidden'
          }}
        >
          <div className={"content position_relative"}>
            {showRefreshProgress && <PullDownProgress/>}
            {children}
          </div>
          {showBackTop && (<BackTopButton click={handlerBackTop}/>)}
        </div>
      )
    }
    复制代码
Cuatro: el efecto logrado
  • Código completo fácil de usar

    import {AppScroll} from "../component/app_scroll";
    
    function Profile() {
      return (
        <AppScroll scrollHeight={'200px'}>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
          <div>xxxxxxxxxxxxxx</div>
        </AppScroll>
      )
    }
    
    export default Profile
    复制代码

scroll简单使用.gif

  • Uso complejo de código completo

    import "../../../../assets/css/home.css"
    import {useCallback, useEffect, useState} from "react";
    import VideoRow from "../../component/video_row";
    import {homeInfoApi} from "../../../../network/api";
    import {HomeDataModel} from "../../../../network/model";
    import {AppScroll} from "../../component/app_scroll";
    import {EventKey, EventUtils} from "../../../../utils/event_utils";
    
    function HomeContent(props) {
      const {tag} = props;
      let [homeData, setHomeData] = useState(new HomeDataModel());
      let [pageIndex, setPageIndex] = useState(1);
      const refreshKey = EventKey.scrollRefresh(tag.name);
      const toKey = EventKey.scrollToTop(tag.name);
    
      useEffect(() => {
        //  切换tab时返回页面的顶部,暂时不做记录之前tab的位置
        EventUtils.emit(toKey)
      }, [tag])
    
      useEffect(() => {
        dataRefresh().then();
      }, [tag])
    
      async function dataRefresh() {
        try {
          const response = await homeInfoApi(tag.name);
          setPageIndex(1);
          setHomeData(response);
        } catch (e) {
          console.log(e);
        }
      }
    
      async function dataLoadMore() {
        try {
          const currentPage = pageIndex + 1;
          const response = await homeInfoApi(tag.name, currentPage);
          const currentHomeData = Object.assign({}, homeData);
          currentHomeData.videoList = homeData.videoList.concat(response.videoList);
          setPageIndex(currentPage);
          setHomeData(currentHomeData);
        } catch (e) {
          console.log(e);
        }
      }
    
      return (
        <AppScroll
          refreshKey={refreshKey}
          toKey={toKey}
          scrollHeight={'calc(100vh - 56px * 3)'}
          scrollBackground={'rgba(229, 229, 229, 0.29)'}
          showRefreshProgress={true}
          showBackTop={true}
          openPullDown={true}
          onRefresh={dataRefresh}
          openPullUp={true}
          onLoadMore={dataLoadMore}
        >
          <div className={"home_content_container"}>
            {
              homeData.videoList.map((item, index) =>
                <VideoRow
                  {
                    ...Object.assign(
                      item, {imgLoaded: () => EventUtils.emit(refreshKey)}
                    )
                  }
                  key={item.vid + index}
                />
              )
            }
          </div>
        </AppScroll>
      )
    }
    
    export default HomeContent
    复制代码

scroll复杂使用.gif

  • ok, está aquí, registre su propia experiencia y espero poder ayudarlo frente a la pantalla. Si tiene alguna pregunta, bienvenido a discutir en el área de comentarios ^_^

Supongo que te gusta

Origin juejin.im/post/7085381319261323272
Recomendado
Clasificación