• 面试题:React实现一个Dialog模板



    前言

    题目大概是要实现一个dialog的模板,你可以应用他实现很多功能,比如说某个操作的确认提醒等,我们要做的实现这样一个可应用都多个功能的dialog,只要你想要显示的组件写好,外部嵌套这样一个dialog组件,就能实现

    一、简单Dialog实现

    首先我们先实现一个简单的Dialog
    不妨百度一下antd的对话框Modal
    功能如下:

    1.点击出现,周围灰色,中间一个对话框,点击周围关闭对话框,点击对话框不会关闭
    2.这里注意,当对话框出现,原本页面其他事件点击都不会被触发

    思路:
    很简单,设置一个状态,isShow来表示dialog是否出现,页面添加一个按钮(其他的也可以,目的是触发dialog出现),初始化dialogfalse,点击变为true,此时出现的dialog会覆盖整个页面,给这个覆盖了整个页面的dialog_box挂载点击事件,监听如果点击的周围灰色区域,则再把isShow设为false,关闭dialog

    1.react-redux存储状态isShow

    这个状态可能会被很多地方使用,所以直接redux存储,
    步骤:

    1.下载安装react-redux和redux yarn add redux react-redux
    2.创建store
    3.创建reducer
    4.包裹 并传入参数 store={store}


    代码如下:
    首先整体目录:
    在这里插入图片描述
    store.js
    这里使用了combineReducers,主要是熟悉一下,好久不用总要看一眼

    import {combineReducers, createStore} from 'redux'
    import  dialogReducer  from "./reducer/dialogReducer";
    const reducer=combineReducers({
        dialogReducer
    })
    
    const store=createStore(reducer)
    
    export default store
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    dialogReducer.js

    var dialogReducer=(prevState={
        isShow:false,
    },action)=>{
        var state={...prevState};
        switch(action.type){
            case 'DIALOG_SHOW':{
                return {
                    ...state,
                    isShow:action.value,
                }
            }
            default:{
                return state
            }
        }
    }
    
    export default dialogReducer
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    index.js

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import { Provider } from 'react-redux';
    import store from './redux/store'
    
    import App from './App';
    import reportWebVitals from './reportWebVitals';
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
       <Provider store={store}>
       <App />
       </Provider>
      </React.StrictMode>
    );
    
    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.创建Dialog组件

    这里有一步监听是否是dialog对话框还是周围灰色区域,大致如下操作:

    1.创建一个refuseRef创建),挂载到整个Dialog上,这样就能获取到整个dialog_box组件,
    在这里插入图片描述

    在这里插入图片描述

    2.然后添加监听事件,以及出发的处理函数,这个处理函数是要判断当前点击的组件的class类名是否是dialog_box(因为这个点击会精确到具体组件,即点击子组件会返回子组件)
    首先,节点及其类名如下:
    在这里插入图片描述
    添加监听
    在这里插入图片描述
    这里函数dialogFun的参数e是当前点击到的组件,如果是灰色区域,则返回整体dialog_box,点击中间对话框,则返回dialog,然后可以通过e.target.className获取组件类名用于比较,这里props.close()是将isShow设为false的操作,具体定义放在了父组件App
    所以综上:

    ref用来添加监听事件
    e.target用来监听点击到的组件
    注意ref.current可以获取被挂载的组件,e.target.className可以获去class类名


    代码如下
    App.js
    这是一个全局的父组件,所以我直接将处理显示的函数放在了这里然后传递给子组件,这样子组件就不需要再connect获取redux中的状态
    (下面

    组件中的嵌套可以先忽略)

    import React,{useEffect} from 'react'
    import { connect } from 'react-redux'
    import Dialog from './components/Dialog'
    import './App.css'
    import DialogCancle from './components/DialogCancle'
    
    function App(props) {
        const close=function(){
            props.changeShow(false)
        }
      useEffect(() => {
        console.log(props.isShow)
      }, [props.isShow])
      return (
        <div style={{height:'100vh',width:'100vw'}}>App
            <button onClick={()=>{props.changeShow(true)}}>吃点什么</button>
                    {props.isShow?<Dialog close={close}><DialogCancle close={close}/></Dialog>:''}
        </div>
      )
    }
    
    const mapStateToProps=function(state){
        return {
            isShow:state.dialogReducer.isShow,
        }
    }
    const mapStateToDispatch=function(dispatch){
        return {
            changeShow(isShow){
                dispatch({type:"DIALOG_SHOW",value:isShow})
            }
        }
    }
    export default connect(mapStateToProps,mapStateToDispatch)(App)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    Dialog.js

    import React,{useRef,useEffect} from 'react';
    import './Dialog.css'
    
    export default function Dialog(props) {
        useEffect(() => {
           ref.current.addEventListener('click',dialogFun)
        }, [props.isShow])
        const dialogFun=function(e){
            console.log(ref.current)
            if(e.target.className==='dialog_box'){
               props.close()
            }
        }
        var ref=useRef()
        return (
        <div  value="dialog_box" ref={ref} className="dialog_box">
            <div value="dialog" className="dialog">
                <div style={{textAlign:'center',color:'#1890FF',fontSize:'18px',paddingTop:'10px',paddingBottom:'10px'}}>Dialog</div>
                <div >
                   {props.children}
                </div>
            </div>
        </div>
        
      );
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Dialog.css
    css代码可以自定义,我就随便写了些,主要不要忘了zIndex的值要大于原本页面,不然无法覆盖

    .dialog{
    
        /* border-radius: 10px; */
        background-color: white;
        height:150px;
        width:400px;
        margin:0 auto;
        margin-top:100px;
        transition: 3s linner;
    }
    .dialog_box{
        width:100%;
        height:100%;
        position:fixed;
        z-index:10001;
        top:0;
        left:0;
        background-color: rgba(3,3,3,0.4);
        /* opacity: 0.4; */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    到此简单的Dialog他已经完成,接下来我们要实现一个中间传入组件就能显示在Dialog里面的功能

    二、组件嵌套

    看了网上,有很多实现方法,比如render什么的,这里使用插槽,但一直没找到怎么往插槽里直接传参,失败
    直接在

    组件内部添加一个{props.children}用来占位置,这时你只需将你想要显示的子组件外部嵌套一层Dialog组件即可

    <Dialog close={close}>
    	<DialogCancle close={close}/>
    </Dialog>
    
    • 1
    • 2
    • 3

    Dialog组件的内部render

    return (
        <div  value="dialog_box" ref={ref} className="dialog_box">
            <div value="dialog" className="dialog">
                <div style={{textAlign:'center',color:'#1890FF',fontSize:'18px',paddingTop:'10px',paddingBottom:'10px'}}>Dialog</div>
                <div >
                   {props.children}
                </div>
            </div>
        </div>
        
      );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    简单到不能再简单的子组件DialogCancle

    import React,{useEffect} from 'react'
    import Dialog from './Dialog'
    export default function DialogCancle(props) {
       useEffect(() => {
        console.log(props)
       }, [])
      return (
        <div >
            <p>今天中午吃什么??</p>
            <button>不吃饭</button>
            <button onClick={()=>props.close()} >取消</button>
        </div>
      )
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    所以无论你的DialogCancle内部怎么写,只要你外部嵌套Dialog,就可以将组件内容显示再对话框内

    十分粗糙的实现这个样一个小demo,有问题请指出

  • 相关阅读:
    ELK8.1从零搭建
    javascript:for...of和for..in循环的区别
    BUUCTF 不一样的flag
    求和数组连续序列
    AttributeError: module ‘tensorflow‘ has no attribute ‘__version__‘
    React 组件进阶
    vue3中生命周期函数
    在 CentOS 上安装 Docker Engine
    Excel 转 Json 、Node.js实现(应用场景:i18n国际化)
    Vue3 源码阅读(2):响应式系统 —— 核心思想、基本实现
  • 原文地址:https://blog.csdn.net/qq_45856669/article/details/126577449