React 模态框的设计(七)整合与测试

一个弹窗是不是也挺复杂的,是的,往往看似简单的东西真正做起来很复杂。只有多试验才能出真知。光看不练肯定是不行的。下面我们来把前几节的内容整合一下就大功告成了。

_Model.jsx

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

import ModelHeader from './_ModelHeader';
import ModelMask from './_ModelMask';
import ModelContent from './_ModelContent';
import ModelActions from './_ModelActions';
import ModelContainer from './_ModelContianer';
import Draggable from './_Draggable';
import { ModelContext } from './_useModel';
import SThemeProvider from '../STheme/SThemeProvider';
import { useSTheme } from '../STheme/useToggleThemeHook';

function Model(props) {
    const {
        sizeMode = "sm", //弹窗的大小
        level = "default", // 弹窗的类型(主要是颜色类型),选项有:normal, error, warning, success, info
        title = "提示", //标题
        isDark,
        onClose,  //关闭弹窗后的回调
        enableDragging = true,
        enableController = true, //是否显示控制按钮
        content = "暂无弹窗内容", //弹窗内容
        actions = [ //操作按钮
            {
                title: "确定", //按钮标题
                attention: false, //是否为操作按钮
                onClick: (setLoading, setTitle, setDisable, onClose) => { onClose(); } //按钮回调
            },
        ],//功能按钮
    } = props;

    const [stateMode, setStateMode] = useState(1); // 弹窗的状态,0: 最小化, 1: 正常, 2: 最大化
    const theme = useSTheme(); //获取主题
    console.log(`theme => ${theme}`);

    return (
        <SThemeProvider isDark={isDark}>
            <ModelContext.Provider value={{
                stateMode, // 弹窗的状态,0: 最小化, 1: 正常, 2: 最大化
                setStateMode, // 设置弹窗的状态
                sizeMode, //弹窗最大宽度
                onClose, //关闭弹窗的回调
                isDark, //是否是暗黑模式
                level, // 弹窗的类型(主要是颜色类型),选项有:normal, error, warning, success, info
            }}>
                <ModelMask>
                    <Draggable
                        enableDragging={enableDragging && stateMode !== 2 }
                        enableHandler={true}
                        stateMode={stateMode}
                    >
                        <ModelContainer>
                            <ModelHeader
                                className=".model-handler"
                                title={title}
                                level={level}
                                onClose={onClose}
                                enableController={enableController}
                            />

                            {
                                content &&
                                <ModelContent>
                                    {
                                        content
                                    }
                                </ModelContent>
                            }

                            {
                                actions && actions.length > 0 &&
                                <ModelActions actions={actions} onClose={onClose} />
                            }
                        </ModelContainer>
                    </Draggable>
                </ModelMask>
            </ModelContext.Provider>
        </SThemeProvider>
    );
};

export default Model;

相关的内容前几节已经讲得很通透了。

下面我们来测试吧:

PopModelTest.jsx

javascript 复制代码
import React from 'react';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
import useModel from '../../framework-kakaer/SModel/_useModel';
import Model from '../../framework-kakaer/SModel/_Model';

const longContent = `碧玉妆成一树高",写柳树给人的总体印象。柳树的形象美在于它那曼长披拂的枝条,一年一度,它长出了嫩绿的新叶,丝丝下垂,在春风吹拂中,有着一种迷人的意态。这里的"碧玉"既可指真实的玉,又暗含"碧玉小家女"(《碧玉歌》)中"碧玉"之意,指小户人家出身的年轻秀美的女子。古典诗词常借用柳树的形象美来形容美人苗条的身段、婀娜的腰肢,但此诗别出新意,翻转过来,将柳树化身为美人。用"碧玉"来比柳实际上有两层意思:一是"碧玉"和柳的颜色有关,"碧"和下句的"绿"是互相生发、互为补充的;二是"碧玉"这个人在人们头脑中留下的是年轻的印象,在古代文学作品里,"碧玉"几乎成了年轻貌美的女子的泛称。用"碧玉"来比柳,人们就会想象到这美人还未到丰容盛鬋的年华,这柳也还是早春稚柳,没有到密叶藏鸦的时候,同时和下文的"细叶""二月春风"又是有联系的。
"万条垂下绿丝绦",具体描写那茂密并轻柔下垂的柳枝,它是柳树最具代表性的部分。有了上句的铺垫,这千条万缕的垂丝,也随之变成了美人的裙带。上句的"高"字,衬托出美人婷婷袅袅的风姿;下句的"垂"字,暗示出纤腰在风中款摆。诗中没有"杨柳"和"腰肢"字样,然而这早春的垂柳以及柳树化身的美人,却给写活了。《南史》说刘悛之为益州刺史,献蜀柳数株,"条甚长,状若丝缕"。齐武帝把这些杨柳种植在太昌云和殿前,玩赏不置,说它"风流可爱"。这里把柳条说成"绿丝绦",可能是暗用这个关于杨柳的典故。但这里的化用,几乎看不出一点痕迹。
"不知细叶谁裁出,二月春风似剪刀。"这两句进一步细描细绘,刻画柳树的嫩叶。每一片树叶都造型别致,纹理细腻,仿佛都是精心裁剪而出。诗人由于惊叹不禁发问:这满树的细叶到底出自哪位高明的裁缝之手?接着找到了答案:原来是大自然的杰作,她手持二月春风这把大剪刀裁出了满树春色。绿叶好比美人衣裙上的花纹和图案,至此,那位美人便形神毕现地跃然纸上了。"二月春风似剪刀"这一新巧的比喻,把视之无形又不可捉摸的春风形象化地描绘出来。春风和剪刀,本来全不相干,它们的相同处只存在于诗人的想象之中。因此,"二月春风似剪刀"既新奇,又能唤起人们丰富的联想。
这首诗立意高远,比喻巧妙,先从大处着眼,然后分部描述,越写越细,把柳树的形神栩栩如生地表现了出来。题目是咏柳,但又不仅仅是咏柳,更是咏春,歌咏自然造化。全诗由"碧玉妆成"引出了"绿丝绦","绿丝绦"引出了"谁裁出",最后,那视之无形的不可捉摸的"春风",也被用"似剪刀"形象化地描绘了出来。这"剪刀"裁制出嫩绿鲜红的花花草草,给大地换上了新妆,它正是自然活力的象征,是春给予人们美的启示。从"碧玉妆成"到"剪刀",可以看出诗人一系列艺术构思的过程。诗歌里出现的一连串的形象,是一环紧扣一环的。`;

const normalContent = "唐玄宗天宝三载(744),贺知章奉诏告老回乡,百官送行。他坐船经南京、杭州,顺萧绍官河到达萧山县城,越州官员到驿站相迎,然后再坐船去南门外潘水河边的旧宅。此时正是二月早春,柳芽初发,春意盎然,微风拂面。贺知章如脱笼之鸟回到家乡,心情自然格外高兴,即景写下了这首诗。";

function PopModelTest() { 
    const alertDefault = useModel({
        title: "默认提示",
        content: normalContent,
        enableController: false,
    });
    const alertIno = useModel({
        title: "信息提示",
        level: "info",
        content: normalContent,
        enableController: false,
    });

    const alertSuccess = useModel({
        title: "成功提示",
        level: "success",
        content: normalContent,
        enableController: false,
    });

    const alertWarning = useModel({
        title: "警告提示",
        level: "warning",
        content: normalContent,
        enableController: false,
    });

    const alertError = useModel({
        title: "错误提示",
        level: "error",
        content: normalContent,
        enableController: false,
    });

    const alertLong = useModel({
        title: "长内容提示",
        content: longContent,
        enableController: false,
    });

    let initStatus = true;
    const alertLoading = useModel({
        title: "异步提交提示",
        content: normalContent,
        enableController: false,
        actions: [
            {
                title: "提交",
                attention: false,
                onClick: (setLoading, setTitle, setDisable, onClose) => {
                    if (initStatus) {
                        setLoading(true);
                        setTimeout(() => {
                            setLoading(false);
                            setTitle("提交成功, 可关闭");
                            initStatus = false;
                        }, 3000);
                    } else {
                        initStatus = true;
                        onClose();
                    }
                    

                }
            }
        ]
    });

    const alertMaxMin = useModel({
        title: "最大化最小化测试",
        level: "warning",
        content: normalContent,
        enableController: true,
        enableDragging: true,

    });

    const alertDrag = useModel({
        title: "拖动测试",
        level: "error",
        content: normalContent,
        enableController: false,
        enableDragging: true,
    });

    const morActionsAlert = useModel({
        title: "confirm测试",
        level: "info",
        content: normalContent,
        enableController: false,
        actions: [
            {
                title: "取消",
                attention: false,
                onClick: (setLoading, setTitle, setDisable, onClose) => {
                    onClose();
                }
            },
            {
                title: "确定",
                attention: true,
                onClick: (setLoading, setTitle, setDisable, onClose) => {
                    setLoading(true);
                    setTimeout(() => {
                        onClose();
                    }, 3000);
                    
                }
            }
        ]
    });

    return (
        <Stack spacing={2}>
            <Button
                variant='contained'
                onClick={() => { alertDefault(Model) }}
            >
                default 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertIno(Model) }}
            >
                info 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertError(Model) }}
            >
                error 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertWarning(Model) }}
            >
                warning 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertSuccess(Model) }}
            >
                success 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertLong(Model) }}
            >
                长文 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertLoading(Model) }}
            >
                loading 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { morActionsAlert(Model) }}
            >
                多Action 弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertDrag(Model) }}
            >
                可拖动弹窗
            </Button>

            <Button
                variant='contained'
                onClick={() => { alertMaxMin(Model) }}
            >
                可最大化最小化弹窗
            </Button>
        </Stack>
    )
}

export default PopModelTest;

本示例中所有的引入目录的位置请根据自己的项目做适当的调整。是不是很不错? 本弹窗系列到此完结。

相关推荐
m0_748247552 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255023 小时前
前端常用算法集合
前端·算法
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203983 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2343 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1234 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~5 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语5 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport5 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg5 小时前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全