欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于React實(shí)現(xiàn)調(diào)用式Modal組件的全流程

 更新時(shí)間:2024年12月15日 14:11:19   作者:寄給江南  
本文基于 nextUI 和 tailwindCSS 實(shí)現(xiàn)調(diào)用式 Modal 組件的封裝,文中通過圖文結(jié)合的方式和代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下

組件的設(shè)計(jì)與實(shí)現(xiàn)

實(shí)現(xiàn) ModalContext

關(guān)于 Context 的概念和具體使用,可以閱讀 React Context 官方文檔。

首先,根據(jù)可能需要自定義的屬性,構(gòu)建 ModalContext 對(duì)象:

// Context.tsx
import { createContext, useContext } from 'react'
import type { ButtonProps, ModalProps as _ModalProps } from '@nextui-org/react'

export type ModalFooterParams = {
  ConfirmButton: (props: ButtonProps) => React.ReactNode
  CancelButton: (props: ButtonProps) => React.ReactNode
  onClose: () => void
}

export type ModalFooterRenderer = (params: ModalFooterParams) => React.ReactNode

export type ModalType = 'default' | 'primary' | 'success' | 'warning' | 'danger'

export type ModalProps = {
  /** 模態(tài)框類型 */
  type?: ModalType
  /** 模態(tài)框標(biāo)題 */
  title?: React.ReactNode
  /** 模態(tài)框內(nèi)容 */
  content?: React.ReactNode
  /** 自定義底部內(nèi)容 */
  footer?: ModalFooterRenderer | React.ReactNode
  /** 關(guān)閉回調(diào) */
  onClose?: () => void

  /** 確認(rèn)按鈕文本 */
  confirmButtonText?: string
  /** 確認(rèn)按鈕屬性 */
  confirmButtonProps?: ButtonProps
  /** 確認(rèn)按鈕圖標(biāo) */
  confirmButtonIcon?: React.ReactNode
  /** 確認(rèn)回調(diào) */
  onConfirm?: () => void
  /** 確認(rèn)前的校驗(yàn)回調(diào) */
  beforeConfirm?: () => boolean
  /** 確認(rèn)按鈕加載狀態(tài) */
  isConfirmLoading?: boolean
  /** 取消按鈕文本 */
  cancelButtonText?: string
  /** 取消按鈕屬性 */
  cancelButtonProps?: ButtonProps
  /** 取消按鈕圖標(biāo) */
  cancelButtonIcon?: React.ReactNode
  /** 取消回調(diào) */
  onCancel?: () => void
} & Partial<Omit<_ModalProps, 'title' | 'content'>>

export const ModalContext = createContext<ModalProps>({} as ModalProps)

export const useModalContext = () => {
  return useContext(ModalContext)
}

實(shí)現(xiàn) ModalFooter 組件

首先,定義按鈕的基本屬性以及與之對(duì)應(yīng)的顏色映射關(guān)系。

隨后,分別對(duì) ConfirmButton、CancelButton 以及 ModalFooter 組件展開具體的實(shí)現(xiàn),各組件內(nèi)根據(jù)獲取到的上下文屬性及相關(guān)邏輯來處理按鈕的顯示、點(diǎn)擊等行為。具體代碼如下:

// Footer.tsx
import { useState } from 'react'
import {
  Button,
  ButtonProps,
  ModalFooter as _ModalFooter,
  useModalContext as _useModalContext,
} from '@nextui-org/react'
import { useModalContext } from './Context'

export const COLOR_MAP = {
  default: 'bg-black dark:text-black dark:bg-white',
  primary: 'bg-secondary',
  success: 'bg-success',
  warning: 'bg-warning',
  danger: 'bg-red-500',
}

export function ConfirmButton(props: ButtonProps) {
  const { onClose: _onClose } = _useModalContext()

  const {
    type = 'default',
    confirmButtonText = '確認(rèn)',
    confirmButtonProps,
    confirmButtonIcon,
    onClose,
    onConfirm,
    beforeConfirm,
    isConfirmLoading,
  } = useModalContext()

  const [isLoading, setIsLoading] = useState(false)

  const onClick = async () => {
    if (confirmButtonProps?.type === 'submit') {
      return
    }
    setIsLoading(!!isConfirmLoading)
    try {
      const isConfirm = await beforeConfirm?.()
      if (isConfirm !== false) {
        await onConfirm?.()
        onClose?.()
        _onClose()
      }
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <Button
      color={type}
      className={`w-max py-2 px-8 rounded-lg flex items-center gap-2 text-white border-slate-400 ${COLOR_MAP[type]}`}
      startContent={confirmButtonIcon}
      isLoading={isLoading}
      onClick={onClick}
      {...props}
      {...confirmButtonProps}>
      {confirmButtonText}
    </Button>
  )
}

export function CancelButton(props: ButtonProps) {
  const { onClose: _onClose } = _useModalContext()

  const {
    cancelButtonText = '取消',
    cancelButtonProps,
    cancelButtonIcon,
    onCancel,
    onClose,
  } = useModalContext()

  const onClick = () => {
    onCancel?.()
    onClose?.()
    _onClose()
  }

  return (
    <Button
      className='rounded-lg text-inherit bg-transparent border border-black/40 dark:border-white hover:bg-default-100'
      startContent={cancelButtonIcon}
      onClick={onClick}
      {...props}
      {...cancelButtonProps}>
      {cancelButtonText}
    </Button>
  )
}

export function ModalFooter() {
  const { onClose } = _useModalContext()
  const { footer } = useModalContext()

  const defaultFooter = (
    <div className='flex items-center gap-2'>
      <CancelButton />
      <ConfirmButton />
    </div>
  )

  if (typeof footer === 'function') {
    return <_ModalFooter>{footer({ ConfirmButton, CancelButton, onClose })}</_ModalFooter>
  }

  return footer !== null ? (
    <_ModalFooter>{footer || defaultFooter}</_ModalFooter>
  ) : null
}

實(shí)現(xiàn) Modal 組件

Modal 組件接收一系列屬性,并通過 ModalContext.Provider 將這些屬性傳遞給子組件。另外,Modal 組件對(duì)彈窗的關(guān)閉邏輯進(jìn)行了整合;當(dāng)我們關(guān)閉模態(tài)框時(shí),會(huì)依次觸發(fā) onCancel 和 onClose 回調(diào)函數(shù),確保關(guān)閉流程的可控性。具體代碼如下:

// Modal.tsx
import {
  Modal as _Modal,
  ModalBody,
  ModalHeader,
  ModalContent,
  ModalFooter as _ModalFooter,
  useModalContext as _useModalContext,
} from '@nextui-org/react'
import { ModalContext, type ModalProps } from './Context'
import { ModalFooter } from './Footer'
import { withType } from './modal'

export function Modal(props: ModalProps) {
  const {
    title,
    content,
    footer,
    onClose: _onClose,
    children,
    confirmButtonText,
    confirmButtonProps,
    onConfirm,
    beforeConfirm,
    isConfirmLoading,
    cancelButtonText,
    cancelButtonProps,
    onCancel,
    ...restProps
  } = props

  function onClose() {
    onCancel?.()
    _onClose?.()
  }

  return (
    <ModalContext.Provider value={props}>
      <_Modal disableAnimation className='m-auto' onClose={onClose} {...restProps}>
        <ModalContent>
          <ModalHeader>{title}</ModalHeader>
          <ModalBody className='text-sm'>
            {content || children}
          </ModalBody>
          <ModalFooter />
        </ModalContent>
      </_Modal>
    </ModalContext.Provider>
  )
}

Modal.default = withType('default')
Modal.primary = withType('primary')
Modal.success = withType('success')
Modal.warning = withType('warning')
Modal.danger = withType('danger')

在上述代碼中,通過向 withType 函數(shù)傳入特定的 type 參數(shù)來創(chuàng)建不同類型的 Modal 組件。

接下來,對(duì) Modal 組件的渲染邏輯以及創(chuàng)建不同類型 Modal 組件的方法進(jìn)行封裝,相關(guān)代碼如下:

// modal.tsx
import { isValidElement } from 'react'
import { createRoot } from 'react-dom/client'
import { Modal } from './Modal'
import type { ModalProps, ModalType } from './Context'

function modal(config: ModalProps) {
  const currentConfig = { ...config, isOpen: true, onClose }

  const container = document.createDocumentFragment()
  const root = createRoot(container)

  function render(config: ModalProps) {
    root.render(<Modal {...config} />)
  }

  function onClose() {
    render({
      ...currentConfig,
      isOpen: false,
    })

    setTimeout(function () {
      root.unmount()
    }, 300)
  }

  render(currentConfig)

  return {
    onClose,
  }
}

export function withType(type: ModalType) {
  function _withType(
    content: React.ReactNode | ModalProps,
    config?: Omit<ModalProps, 'content'>
  ): Promise<void> {
    const _config = isValidElement(content) || typeof content === 'string'
      ? { ...config, content }
      : content as ModalProps

    return new Promise((resolve, reject) => {
      const onConfirm = async () => {
        await _config.onConfirm?.()
        resolve()
      }

      const onCancel = async () => {
        await _config.onCancel?.()
        reject()
      }

      modal({
        ..._config,
        onConfirm,
        onCancel,
        type,
      })
    })
  }

  return _withType
}

組件的使用方式

該組件提供了三種預(yù)期使用方式。

Modal.success("操作成功!");

Modal.success({
  title: "提示",
  content: "操作成功!",
  confirmButtonText: "好的",
});

Modal.success("操作成功!", {
  title: "提示",
  confirmButtonText: "好的",
});

傳入配置對(duì)象

定義 handleClick 函數(shù),隨后在函數(shù)內(nèi)部調(diào)用 Modal 組件,并傳入配置對(duì)象:

import { type ModalType } from '@/components/Modal/Context'
import { COLOR_MAP } from '@/components/Modal/Footer'
import { Modal } from '@/components/Modal'
import { Button } from '@nextui-org/react'

export default function Home() {
  const colorList: ModalType[] = ['default', 'primary', 'success', 'warning', 'danger']

  const handleClick = (type: ModalType) => {
    Modal[type]({
      title: '提示',
      content: `${type} 操作成功!`,
      confirmButtonText: '好的',
      cancelButtonText: '取消',
    })
  }

  return (
    <div className='py-12 flex gap-2 items-center justify-center'>
      {colorList.map((color) => (
        <Button
          key={color}
          color={color}
          className={`rounded-lg text-white ${COLOR_MAP[color]}`}
          onClick={() => handleClick(color)}
        >
          {color} Click
        </Button>
      ))}
    </div>
  )
}

效果分別如下:

傳入文本內(nèi)容

對(duì) handleClick 函數(shù)中 Modal 組件的調(diào)用形式進(jìn)行修改,并且只傳入文本內(nèi)容:

const handleClick = (type: ModalType) => {
  Modal[type](`${type} 操作成功!`)
}

效果分別如下:

傳入文本內(nèi)容和配置對(duì)象

修改 handleClick 函數(shù)中 Modal 組件的調(diào)用形式,同時(shí)傳入文本內(nèi)容與配置對(duì)象:

const handleClick = (type: ModalType) => {
  Modal[type](`${type} 操作成功!`, {
    title: '提示',
    confirmButtonText: '好的',
    cancelButtonText: '取消',
  })
}

效果分別如下:

至此,調(diào)用式 Modal 組件的實(shí)現(xiàn)流程已全部完成。

最后

以上就是基于React實(shí)現(xiàn)調(diào)用式Modal組件的全流程的詳細(xì)內(nèi)容,更多關(guān)于React調(diào)用式Modal組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React實(shí)現(xiàn)雙滑塊交叉滑動(dòng)

    React實(shí)現(xiàn)雙滑塊交叉滑動(dòng)

    這篇文章主要為大家詳細(xì)介紹了React實(shí)現(xiàn)雙滑塊交叉滑動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • React使用Ant Design方式(簡單使用)

    React使用Ant Design方式(簡單使用)

    文章介紹了AntDesign組件庫,它是基于AntDesign設(shè)計(jì)體系的ReactUI組件庫,主要用于研發(fā)企業(yè)級(jí)中后臺(tái)產(chǎn)品,文章詳細(xì)講解了如何下載和按需引入antd組件庫,并通過一個(gè)小案例展示了如何使用antd進(jìn)行布局和改造,最后,文章提醒大家在使用過程中可以參考官網(wǎng)的屬性介紹
    2024-11-11
  • react實(shí)現(xiàn)Radio組件的示例代碼

    react實(shí)現(xiàn)Radio組件的示例代碼

    這篇文章主要介紹了react實(shí)現(xiàn)Radio組件的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 基于Webpack4和React hooks搭建項(xiàng)目的方法

    基于Webpack4和React hooks搭建項(xiàng)目的方法

    這篇文章主要介紹了基于Webpack4和React hooks搭建項(xiàng)目的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-02-02
  • 使用React?SSR寫Demo一學(xué)就會(huì)

    使用React?SSR寫Demo一學(xué)就會(huì)

    這篇文章主要為大家介紹了使用React?SSR寫Demo實(shí)現(xiàn)教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • React如何配置src根目錄@

    React如何配置src根目錄@

    這篇文章主要介紹了React如何配置src根目錄@,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-01-01
  • React如何以Hook的方式使用Echarts

    React如何以Hook的方式使用Echarts

    這篇文章主要介紹了React如何以Hook的方式使用Echarts問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • React實(shí)現(xiàn)父組件調(diào)用子組件的兩種寫法

    React實(shí)現(xiàn)父組件調(diào)用子組件的兩種寫法

    react通信分很多種,比如:父子通信,兄弟通信等等,這里我們就簡單說一下父子通信,父子通信分為:父組件調(diào)用子組件里面的方法;子組件調(diào)用子組件里面的方法,這里我們著重說一下父組件調(diào)用子組件,需要的朋友可以參考下
    2024-04-04
  • React配置Redux并結(jié)合本地存儲(chǔ)設(shè)置token方式

    React配置Redux并結(jié)合本地存儲(chǔ)設(shè)置token方式

    這篇文章主要介紹了React配置Redux并結(jié)合本地存儲(chǔ)設(shè)置token方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React、Vue中key的作用詳解 (key的內(nèi)部原理解析)

    React、Vue中key的作用詳解 (key的內(nèi)部原理解析)

    key是虛擬DOM對(duì)象的標(biāo)識(shí),當(dāng)狀態(tài)中的數(shù)據(jù)發(fā)生變化時(shí),Vue會(huì)根據(jù)[新數(shù)據(jù)]生成[新的虛擬DOM],本文給大家介紹React、Vue中key的作用詳解 (key的內(nèi)部原理解析),感興趣的朋友一起看看吧
    2023-10-10

最新評(píng)論