React模态框设计(一)弹窗的初步实现

自定义组件是每个前端开发者必备的技能。我们在使用现有框架时难免有一些超乎框架以处的特别的需求,比如关于弹窗,每个应用都会用到,但是有时我们使用的框架中提供的弹窗功能也是功能有限,无法满足我们的应用需求,今天 我来讲一下在React中如何自定义各种样式的弹窗。相信通过这篇文章,你能在自定义组件方面技能有一个质的提升。相关的知识能够掌握的更加牢固。

先看最终的效果:

首先本实例都是在MUI及基础上设计的,样式部分我使用了emotion-react

弹窗的设计有两种方案,一种是直接把弹窗组件嵌入到页面中,用的时候让它直接显示或关闭即可,一般的UI框架都是采用这种方法。这种使用方法有一个好处是不受浏览器插件的影响,尤其是广告拦截插件的影响。但使用上有点不方便,必须要在使用弹窗的组件中加入这个弹窗,使用上不太方便。另一种方案是动态创建弹窗组件,在使用的时候直接alert就可以了。就像使用js原生的弹窗一样简单。本篇文章就是围绕这种设计思路设计一个优雅的弹窗组件。

弹窗遮罩

遮罩很简单,就一个div, 在MUI里就是一个Box组件。

javascript 复制代码
const maskCss = css`
        position: fixed;
        background-color: rgba(0,0,0,0.6);
        border-radius: 5px;
        top: 0px;
        left: 0px;
        width: 100%;
        height: 100%;
        overflow: hidden;
        z-index: 999;
        display: flex;
        justify-content: center;
        align-items: center;
    `;

这是遮罩的样式,我直接赋于一个Box就好了。

javascript 复制代码
/** @jsxImportSource @emotion/react */
import { css, jsx, keyframes } from '@emotion/react'
import { useState, useRef, useEffect, useCallback } from 'react';
import Box from '@mui/material/Box';

export default function Model(props) {
  return (
    <Box css={maskCss}>
    </Box>
  )
}

我们再来临时创建一个简单的弹窗主体

javascript 复制代码
/** @jsxImportSource @emotion/react */
import { css, jsx, keyframes } from '@emotion/react'
import React, { useState } from 'react';
import Box from '@mui/material/Box';

const maskCss = css`
        position: fixed;
        background-color: rgba(0,0,0,0.6);
        border-radius: 5px;
        top: 0px;
        left: 0px;
        width: 100%;
        height: 100%;
        overflow: hidden;
        z-index: 999;
        display: flex;
        justify-content: center;
        align-items: center;
    `;

const modelCss = css`
        position: relative;
        background-color: white;
        border: 1px solid #ccc;
        border-radius: 5px;
        overflow: hidden;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
        width: 400px;
        height: 300px;
    `

const titleCss = css`
        background-color: #f0f0f0;
        padding: 8px;
        cursor: move;
    `;

const modelContentCss = css`
        padding: 16px;
    `;

const Modal = (props) => {
  	const {onClose} = props;
    const onClick = (e) => { 
        console.log('target:', e.target.className);
    }

    return (
      <Box 
      	css={maskCss}
				onClick = {onClose}
			>
          <Box css={modelCss}>
              <Box
                  css={titleCss}
                  className=".modelHandler"
              >
                  这是标题
              </Box>
              <Box css={modelContentCss}>
                  这是弹窗内容
              </Box>
          </Box>
    	</Box>
    );
};

export default Modal;

这是一个简单的弹窗,如何让它弹出来呢。我的想法是动态的把这个弹窗插入到documentbody

javascript 复制代码
// 创建一个div容器,作为弹窗的根节点
const modelContainer = document.createElement("div");

// 将div容器添加到body中
document.body.appendChild(modelContainer);

上面我只是创建了一个dom节点,但我们必须把这个dom节点添加到React中才能真实的渲染出来。

javascript 复制代码
// 创建一个根节点
const modelRoot = ReactDOM.createRoot(modelContainer);

然后渲染出来

javascript 复制代码
modelRoot.render(
    <Model />
);

这样就在body中插入了model组件了,并且能渲染出来。当然能挂载我们还要有卸载才行。很简单

javascript 复制代码
// 卸载事件
const unmountEvent = () => {
    modelContainer.remove();
}

我们将上面的弹窗方法整合成一个hook就好了,这样调用起来就相当的哇塞了。

javascript 复制代码
import ReactDOM from 'react-dom/client';
import Model from './_Model';

//可高度自定义的统一弹窗。
export default function useAlert() {
    return (configure) => {
            // 创建一个div容器,作为弹窗的根节点
            const modelContainer = document.createElement("div");

            // 将div容器添加到body中
            document.body.appendChild(modelContainer);

            // 创建一个根节点
            const modelRoot = ReactDOM.createRoot(modelContainer);

            // 卸载事件
            const unmountEvent = () => {
                modelContainer.remove();
            }

            modelRoot.render(
                <Model
                    onClose={unmountEvent}
                    {...configure}
                >
                    {configure.component || null}
                </Model>
            );
        }
    
}

我们把卸载事件传递给了Model,在遮罩点击事件上调用,这样就能开发弹窗也能关闭弹窗。

我们这样调用就好了:

javascript 复制代码
const alert = useAlert();
alert();

你看一个基本的弹窗就设计完了。

相关推荐
OK_boom26 分钟前
React-改变当前页class默认的样式
前端·javascript·react.js
谢尔登1 天前
【React Native】快速入门
javascript·react native·react.js
进取星辰1 天前
32、跨平台咒语—— React Native初探
javascript·react native·react.js
君的名字1 天前
怎么判断一个Android APP使用了React Native 这个跨端框架
android·react native·react.js
iamtsfw1 天前
从头实现react native expo本地生成APK
javascript·react native·react.js
whatever who cares1 天前
react native搭建项目
react.js
每一天,每一步1 天前
React+MapBox GL JS引入URL服务地址实现自定义图标标记地点、区域绘制功能
前端·javascript·react.js
HaanLen1 天前
React19源码系列之渲染阶段performUnitOfWork
前端·javascript·react.js·react19源码
GISer_Jing1 天前
React Hooks底层执行逻辑详解、自定义Hooks、Fiber&Scheduler
前端·javascript·react.js
蓉妹妹2 天前
React+Taro 微信小程序做一个页面,背景图需贴手机屏幕最上边覆盖展示
react.js·微信小程序·taro