• react+tsx中使用betterscroll


    首先,你要知道为什么可以滚动,原理很简单,父容器的高度比子元素的小即可。

    在这之前,我们先来看一下浏览器的滚动原理: 浏览器的滚动条大家都会遇到,当页面内容的高度超过视口高度的时候,会出现纵向滚动条;当页面内容的宽度超过视口宽度的时候,会出现横向滚动条。也就是当我们的视口展示不下内容的时候,会通过滚动条的方式让用户滚动屏幕看到剩余的内容。

    第二,你需要滚动的元素应该是父元素下的第一个子元素

    这里要注意的是,BetterScroll 默认处理容器(wrapper)的第一个子元素(content)的滚动,其它的元素都会被忽略。

    第三,为什么我满足了上面两条,为什么还是不能滚动?可能你的content用了异步的数据,better-scroll实例化之后content的高度还是初始时的高度,这当然无法滚动,解决方法是获取到了异步的数据之后使用refresh()更新,或是使用插件@better-scroll/observe-dom来自动更新高度, 或者observeDOM: true,

    配置与初始化

    这里我使用了better-scroll官方提供的几个插件,ObserveDOMMouseWheelScrollBarPullDownPullup

    大致的结构

    import BScroll from '@better-scroll/core'
    import { BScrollConstructor } from '@better-scroll/core/dist/types/BScroll'
    import ObserveDOM from '@better-scroll/observe-dom'
    import MouseWheel from '@better-scroll/mouse-wheel'
    import ScrollBar from '@better-scroll/scroll-bar'
    import PullDown from '@better-scroll/pull-down'
    import Pullup from '@better-scroll/pull-up'
    
    export interface ScrollProps {
      wrapHeight: string;
      prop?: any;
      onPullup?: Function;
      onPulldown?: Function;
    }
    
    const Scroll: React.FC<ScrollProps> = ({   
      wrapHeight,
      prop,
      onPullup,
      onPulldown,
      children,}) => {
      BScroll.use(ObserveDOM)
      BScroll.use(MouseWheel)
      BScroll.use(ScrollBar)
      BScroll.use(PullDown)
      BScroll.use(Pullup)
      
     
     // ...
    
      return (
        <div className="scroll-warpper" ref={wrapRef} style={{ height: wrapHeight, overflow: 'hidden' }}>
          <div className="scroll-content">
            {children}
          </div>
        </div>
      )
    }
    
    export default Scroll
    

      

     

    ok,准备工作完成,接下来准备better-scroll的实例化

    BetterScroll 提供了一个类,实例化的第一个参数是一个原生的 DOM 对象。当然,如果传递的是一个字符串,BetterScroll 内部会尝试调用 querySelector 去获取这个 DOM 对象。

      //  外层的wrap实例
      const wrapRef = useRef<HTMLDivElement>(null)
    
      //  记录Better-scroll是否实例化,为后续挂载下拉刷新和上拉加载做准备
      const initRef = useRef(false)
      
      //  存储better-scroll的实例
      const [scrollObj, setscrollObj] = useState<BScrollConstructor>()
      
      //  better-scroll的配置参数
      const initBScroll = () => {
        setscrollObj(
          new BScroll(wrapRef.current as HTMLDivElement, {
            //probeType 为 3,任何时候都派发 scroll 事件,包括调用 scrollTo 或者触发 momentum 滚动动画
            probetype: 3,
            //  可以使用原生的点击
            click: true,
            //  检测dom变化
            observeDOM: true,
            //  鼠标滚轮设置
            mouseWheel: {
              speed: 20,
              invert: false,
              easeTime: 300
            },
            //  显示滚动条
            scrollY: true,
            scrollbar: true,
            //  过度动画, 在下载更多的时候滚动条会有个过度动画
            useTransition: true,
            //  下拉刷新
            pullDownRefresh: {
              threshold: 70,
              stop: 0
            },
            //  上拉加载更多
            pullUpLoad: {
              threshold: 90,
              stop: 10
            }
          })
        )
      }
    

      

     

    接着是在组件挂载阶段时,将better-scroll进行实例化,以及为其添加下拉和上拉监听函数

      //  对象初始化
      useEffect(() => {
        initBScroll()
        return () => {
          //  组件卸载时记得将其销毁
          scrollObj?.destroy()
        }
      }, [])
      
      //  下拉刷新
      const pulldown = async () => {
        onPulldown && (await onPulldown())
        setTimeout(() => {
          //  记得使用finishPullDown,不然你只能下拉一次
          scrollObj?.finishPullDown()
          //  下拉之后你的content会发生变化,如果不使用refresh,你需要滑动一下才能刷新content的高度
          scrollObj?.refresh()
        }, 500)
      }
      
      //  上拉加载
      const pullup = async () => {
        onPullup && (await onPullup())
        setTimeout(() => {
          scrollObj?.finishPullUp()
          scrollObj?.refresh()
        }, 500)
      }
    
      //  对象事件挂载
      useEffect(() => {
        if (initRef.current === true) {
          //  下拉刷新
          //  每次更新都需要先把之前的pullingDown事件清除,不然会累加
          scrollObj?.off("pullingDown");
          scrollObj?.once("pullingDown", pulldown);
    
          //  上拉加载
          //  每次更新都需要先把之前的pullingUp事件清除,不然会累加
          scrollObj?.off("pullingUp");
          scrollObj?.once("pullingUp", pullup);
        } else {
          initRef.current = true;
        }
        //  为什么监听prop是因为这边监听不到外面的state变化
        //  handlePullUp的[...state, ...res.data]中的state会中始终为一开始的[]
      }, [prop]);
    

      

     

    实践

    import React, { CSSProperties, useEffect, useState, useCallback } from "react";
    import Scroll from "./scroll";
    import axios, { Method } from "axios";
    
    export interface TestProps {}
    
    interface ResponseType {
      code: number;
      data: any;
    }
    
    const Test: React.FC<TestProps> = () => {
      const style: CSSProperties = {
         "500px",
      };
    
      const request = (url: string, method: Method): Promise<ResponseType> => {
        return new Promise((resolve, reject) => {
          const options = {
            url,
            method,
          };
          axios(options)
            .then((res) => {
              const data = res.data as ResponseType;
              resolve(data);
            })
            .catch((err) => reject(err));
        });
      };
    
      const getData = () => request("/api/datasource", "GET");
    
      const getMore = () => request("/api/abc", "GET");
    
      const [state, setstate] = useState<any[]>([]);
    
      // 一开始拉取数据
      useEffect(() => {
        (async function () {
          const res = await getData();
          console.log(res);
          res.code === 0 && setstate(res.data);
        })();
      }, []);
    
      const handlePullUp = useCallback(async () => {
        const res = await getMore();
        res.code === 0 && setstate(state.concat(res.data));
      }, [state]);
    
      async function handlePullDown() {
        const res = await getData();
        res.code === 0 && setstate(res.data);
      }
    
      return (
        <div style={style}>
          <Scroll
            wrapHeight="300px"
            prop={state}
            onPullup={handlePullUp}
            onPulldown={handlePullDown}
          >
            {state.map((item, idx) =>
              idx % 2 === 0 ? (
                <div key={idx} style={{ height: "200px", background: "red" }}>
                  {item}
                </div>
              ) : (
                <div key={idx} style={{ height: "200px", background: "green" }}>
                  {item}
                </div>
              )
            )}
          </Scroll>
        </div>
      );
    };
    
    export default Test;
    

      

  • 相关阅读:
    XAF-内置初始化数据 (XPO)
    XAF中多对多关系 (XPO)
    Implement Custom Business Classes and Reference Properties 实现自定义业务类和引用属性(XPO)
    Add a Class from the Business Class Library 从业务类库添加类 (XPO)
    Set a One-to-Many Relationship设置一对多关系 (XPO)
    Define the Data Model and Set the Initial Data 定义数据模型并设置初始数据
    Create an XAF Application 创建一个XAF应用程序
    XAF Architecture XAF架构
    功能区控件样式设置
    开源项目CIIP(企业信息管理系统框架).2018.1.0910版更新介绍-上周工作总结
  • 原文地址:https://www.cnblogs.com/ygunoil/p/16672843.html
Copyright © 2020-2023  润新知