You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React on Rails社交项目:实现Ventbox弹窗式/vent路由功能

解决方案:让Ventbox弹窗显示并保留/vent路由

1. 修改NavBar组件

原来的Ventbox被NavLink包裹,点击会触发路由跳转。把NavLink换成普通的div,保留样式和图标,这样点击只会触发弹窗:

import React from 'react'
import { NavLink } from "react-router-dom"
import { navData } from "./navData.js";
import styles from "./styles/navbar.module.css"
import { useState } from "react";
import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight';
import KeyboardDoubleArrowLeftIcon from '@mui/icons-material/KeyboardDoubleArrowLeft';
import Ventbox from './Ventbox'
import CreateIcon from '@mui/icons-material/Create';

export default function NavBar() {
  const [open, setopen] = useState(false)
  
  const toggleOpen = () => {
      setopen(!open)
  }

  return (
    <div className={open?styles.sidenav:styles.sidenavClosed}>
        <button className={styles.menuBtn} onClick={toggleOpen}>
            {open? <KeyboardDoubleArrowLeftIcon />: <KeyboardDoubleArrowRightIcon />}
        </button>
        {navData.map(item =>{
          return <NavLink key={item.id} className={styles.sideitem} to={item.link}>
            {item.icon}
            <span className={styles.linkText}>{item.text}</span>
        </NavLink>
        })}
        {/* 替换NavLink为普通div,避免路由跳转 */}
        <div className={styles.sideitem}>
          <CreateIcon />
          <Ventbox style={styles.linkText} />
        </div>
    </div>
  )
}

2. 优化Ventbox组件

清理无用的useNavigate和to props,新增全屏遮罩确保弹窗在全局显示:

import React, { useState } from "react";
import './styles/Ventbox.css'

function Ventbox({style}) {
    const [popup,setPop] = useState(false);
    const [content, setContent] = useState("");
    const [textLimit, setTextLimit] = useState(250);
    
    const handleClickOpen = () => {
        setPop(!popup);
    }

    const closePopup = () => {
        setPop(false);
    }

    const handleChange = e => {
        setContent(e.target.value);
        setTextLimit(250 - e.target.value.length);
    }

    const handleSubmit = async e => {
        e.preventDefault();
        if (content.length > 250) {
            alert("Text limit reached");
        } else {
            try {
                const response = await fetch(`/posts`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ content: content })
                });
                const data = await response.json();
                console.log(data);
                // 提交成功后关闭弹窗
                closePopup();
            } catch (error) {
                console.error(error);
            }
        }
    }

    return(
        <div>
            <span onClick={handleClickOpen} className={style}>Vent</span>
            {popup && (
                <div className="ventbox-overlay">
                    <div className="popup">
                        <div className="popup-header">
                            <h1>What's on your mind?</h1>
                            <button className="delete-button" onClick={closePopup}>X</button>
                        </div>
                        <div>
                            <form onSubmit={handleSubmit}>
                                <input className="textbox" placeholder="Enter text here" 
                                    value={content} 
                                    onChange={handleChange} 
                                    maxLength={250} 
                                />
                                <p>Characters remaining: {textLimit}</p>
                                <button className="post-button"type="submit">Post</button>
                            </form>
                        </div>
                    </div>
                </div>
            )}
        </div>
    )
}
export default Ventbox;

3. 补充Ventbox全局样式(Ventbox.css)

确保弹窗遮罩覆盖整个页面,层级高于其他内容:

.ventbox-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.popup {
    background-color: white;
    padding: 2rem;
    border-radius: 8px;
    width: 90%;
    max-width: 500px;
    position: relative;
}

.textbox {
    width: 100%;
    min-height: 100px;
    margin: 1rem 0;
    padding: 0.5rem;
    border: 1px solid #eee;
    border-radius: 4px;
}

.post-button {
    background-color: #1da1f2;
    color: white;
    border: none;
    padding: 0.5rem 1.5rem;
    border-radius: 20px;
    cursor: pointer;
}

.delete-button {
    position: absolute;
    top: 1rem;
    right: 1rem;
    border: none;
    background: none;
    font-size: 1.2rem;
    cursor: pointer;
}

4. 保留/vent端点

在路由配置文件(如App.js)中添加/vent路由,渲染独立的发布页面:

import { Routes, Route } from 'react-router-dom';
import Ventbox from './components/Ventbox';

// 新建VentPage组件
function VentPage() {
    return (
        <div style={{ padding: '2rem', maxWidth: '600px', margin: '0 auto' }}>
            <h1>Create a New Vent</h1>
            <Ventbox />
        </div>
    );
}

// 路由配置中添加
<Routes>
    {/* 其他已有路由 */}
    <Route path="/vent" element={<VentPage />} />
</Routes>

修改完成后,点击NavBar的Vent按钮会在当前页面弹出发布框,直接访问/vent也能看到独立的发布界面,完全满足需求。

内容的提问来源于stack exchange,提问作者Jason Tran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:35:31