zoukankan      html  css  js  c++  java
  • antd Dialog 学习笔记

    聊聊 AntD 中的 Dialog

    先介绍三种常用的用法,

    • 受控模式,通过 visible 控制 Dialog 在目标组件中的显示,这个时最简单的用法。
    const Demo: React.FC = () => {
      const [visible, setVisible] = React.useState<boolean>(false);
      return (
        <Modal visible={visible} close={() => setVisible(false)}>
          <div>I am dialog body</div>
        </Modal>
      );
    };
    
    • 函数式调用,但是 Dialog 组件还在调用者的 VD 树上,可以通过 context 对其页面刷新进行影响,但是通过 setState 很难,因为闭包的原因或者类似于 memo 的原因,dialog body 以及不在最近一次刷新的范畴内,因为它属于闭包。
      Notes:必须要将 elements 放到 render 函数里面
    const Demo:React.FC=()=>{
        const [fns,elements]=Modal.useModal();
        const openDialog=()=>{
            const {update,destory}=fns.info({
                content:<div>I am dialog body</div>
            })
        }
    
        return (
            <Button onClick={()=>openDialog()}>Open Dialog</Button>
            {elements}
        )
    }
    
    • 函数式调用,但是 Dialog 组件以及不在调用者的 VD 树上了,连 Context 也无法影响到它了。
    function openDialog() {
      const { update, destory } = Modal.info({
        content: <div>I am dialog body</div>,
      });
    }
    

    rc-dialog 这个组件职责是什么?

    这些个组件总是很复杂,让人看的云里雾里,很多的辅助功能将原本的功能给掩盖了,让初学者看得很累。

    • 它负责将某个组件(DialogBody)Portal 到 getContainer 下面,默认是 document.body。
    • 它提供了一些额外的功能,例如 Mask, Dialog 外面在添加 header,close,footer 等。
    • 它还提供了动画,还有垂直方向滚动条出现时的页面抖动问题,通过修改 width 来实现

    关闭的过程逻辑如下: onClose -> 外部组件调用 setVisible(false), Dialog 然后发现 visible=false, -> CSSMotion 开始走 leave 动画,动画结束后发出 afterClose 事件,然后在 DialogWrapper 里面会 返回 null,
    这样整个 Dialog 就返回 null.

    antd-modal 这个组件封装了什么?

    • Modal 这个组件,提供了默认的 footer,样式,类名,关闭按钮等这些东西。
    • ConfirmDialog 这个组件是在Modal的基础上做了封装,它去除了 Modal 里面默认的 header,footer,完全由自己内部定义实现了。注意是为了提供 info,warning,error,confirm,success 这五种风格的弹框。
    • HookModal 是封装了ConfirmDialog,它负责关闭与刷新 ConfirmDialog,同时将这两个接口暴露给外面。它是给useModal使用的。
    • useModal() hook 函数,提供了函数式动态打开 info,warning,error,confirm,success弹框的方式,这种方式创建的组件需要放在当前调用组件的 render 函数里,同在一棵树上。
    • info(),warning(),error(),confirm(),success(),也是函数式调用打开弹框,但是他们不在当前调用树上面。

    学习一下useModal,

    它的功能就是返回一个 ReactElement(用作容器),以及往这个 ReactElement 里面添加(删除)一个元素的方法。它主要使用了usePatchElement()这个 hook 函数,这个函数很简单,很有用。它就是返回一个容器,以及往容器中添加元素的方法,调用这个方法会返回删除这个元素的方法。我们只要将这个容器放到我们调用的 VD 上就行了,同时,我们可以通过 memo,让这个容器里的东西不参与当前 VD 的刷新,来提高性能。

    export default function usePatchElement(): [
      React.ReactElement[],
      (element: React.ReactElement) => Function
    ] {
      const [elements, setElements] = React.useState<React.ReactElement[]>([]);
    
      const patchElement = React.useCallback((element: React.ReactElement) => {
        // append a new element to elements (and create a new ref)
        setElements((originElements) => [...originElements, element]);
    
        // return a function that removes the new element out of elements (and create a new ref)
        // it works a little like useEffect
        return () => {
          setElements((originElements) =>
            originElements.filter((ele) => ele !== element)
          );
        };
      }, []);
    
      return [elements, patchElement];
    }
    

    考虑写一个函数式弹框的组件,由如下需求:

    • 可以带 title,或者不带 title,或者定制化的 title,
    • closable icon
    • 可以带 footer,或者不带 footer,ok? cancel? button
    • 支持在特定的位置弹出来,或者居中弹出
    • 支持同一棵 VD 树,或者不同的 VD 树。

    在写这个函数的过程中遇到些问题

    • 在写依靠某个元素弹出组件的方法时,采用的时 rc-dialog 给它传递一个 rendModal 的方法。这个 rendModal 方法里面采用了 rc-Align 组件。
    const modalRender = React.useMemo(() => {
      if (dependedElement === null) {
        return undefined;
      } else {
        const targetType: TargetType = () => {
          return dependedElement;
        };
        return (element: React.ReactNode) => {
          return (
            <Align key="align" target={targetType} align={align}>
              //<>{element}</> 这种方式是不行的,它是一个Fragment,Align
              必须要求这个是一个 ReactElement,
              因为会设置它的样式,它必须得是个元素。
              {element as React.ReactElement}
            </Align>
          );
        };
      }
    }, [dependedElement, align]);
    
    • 我写好后,发现打开的组件跑偏了,不在 viewport 里面后来找到了原因,我用了 antd 里面的Modal,同时给它传递了一个有效的 transition, 因为动画的问题,是的 dom-align 算了好几次,然后它算的不及时,所以最后的状态不对,就跑偏了,解决方法,一个就是调用 Align 放出的 forceUpdate ref 方法,但是很遗憾,rc-dialog 没有放出 motion onAppearEnd,onEnterEnd这些事件,我没有办法在动画结束的时候调用forceUpdate, 如果用 setTimeout 去做还是有个问题,不知道动画何时结束。强行设置 1000ms, 页面会有停顿感,效果很差。后来采用第二种方法,把动画给关了,直接穿了个'',搞定了。
  • 相关阅读:
    微信小程序日期插件默认获取延后时间示例
    【SpringBoot2 从0开始】底层注解
    【SpringBoot2 从0开始】实现自动配置的过程
    【SpringBoot2 从0开始】开发世界著名程序体验 springboot
    【SpringBoot2 从0开始】springboot 与 spring
    【SpringMVC 从 0 开始】使用注解方式配置 SpringMVC
    【SpringMVC 从 0 开始】异常处理器
    【SpringMVC 从 0 开始】拦截器介绍
    【SpringMVC 从 0 开始】文件上传和下载
    【SpringMVC 从 0 开始】HttpMessageConverter 报文信息转换器
  • 原文地址:https://www.cnblogs.com/kongshu-612/p/15135144.html
Copyright © 2011-2022 走看看