警告:validateDOMNesting(...):<html>不能显示为 <div 的子级>

Warning: validateDOMNesting(...): <html> cannot appear as a child of <div>

提问人:Freaked Out 提问时间:10/9/2023 最后编辑:Freaked Out 更新时间:10/9/2023 访问量:108

问:

[编辑:我也尝试了dangerouslySetInnerHTML的代码,解决了validateDOMNesting问题,但仍然没有交互性,我猜javascript代码被禁用或不起作用]

所以我从后端获取一个文件并在我的 react 应用程序中渲染它。我正在获取的文件是游戏文件,如井字游戏、石头剪刀布等,所有这些游戏都是用 html 和 js 构建的。问题是,当我渲染 html 文件时,处理程序不起作用,例如在井字游戏中,我有处理点击的函数,在用户单击某个点后,其 innerHtml 设置为 X 或 O,但这些处理程序不起作用,并且发生错误: 我在下面附上了代码和屏幕截图

default function RenderGame({ game }) {
    return (
        <>
            <div>
                {ReactHtmlParser(game)}
            </div>
        </>
    )
}


const PlayGame = ({ temp }) => {
    const [game, setGame] = useState({})
    const params = useParams()
    const gameID = <params className="id"></params>


    useQuery(`project-${gameID}`, async () => {
        const resp = await axios.get(`${import.meta.env.VITE_API_URL}/projects/${gameID}/iframe`)
        console.log(resp)
        return resp.data
    }, {
        onSuccess: (data) => {
            setGame(data)
        }
    })

    const handleDestroy = (e) => {
        e.preventDefault()
        deleteGame.mutate()
    }

    return (
        <RenderGame game={game}></RenderGame>
    )
}

export default PlayGame;

the boxes you are seeing are clickable and are working just fine from backend, but when the files are fetched and rendered then the handlers stop working

游戏代码如下:

"<!-- app/views/projects/iframe.html.erb -->
<!DOCTYPE html>
<html>
<head>
  <!-- Add the base tag here only if there are image files -->

  <base href="/uploads/image_folder_1693815923/">
  
</head>
<body>
  <!-- Render the HTML content -->
  <div class="message-code">
    <!DOCTYPE html>
<html>
    <head>
        <style>
            *{
                margin: 0;
                padding: 0;
                background-color: black
            }        
            .title{
                text-align: center;
                margin-bottom: 0px;
                color: #808080;
                font-style: italic;
                font-weight: bold;
            }    
            .gameContainer{ 
                display: flex;
                justify-content: center;
                padding-top: 20px;
            }

            .container{
                display: grid;
                grid-template-rows: repeat(3, 10vw);
                grid-template-columns: repeat(3, 10vw);
                position: relative;
                justify-content: center;            
            }

            .box{
                border: 2px solid #C0C0C0;
                font-size: 6vw;
                cursor: pointer;
                display: flex;
                justify-content: center;
                align-items: center;
            }

            .box:hover{
                background-color: #191919;
            }

            .info {
                font-size: 28px;
                color: #A0A0A0;
                text-align: center;
                font-style: italic;
            }
            .player {
                text-align: center;
            }

            .gameInfo{
                padding: 30px 34px;
                text-align: center;
            }
            .btn{
                margin-top: 4px;
                cursor: pointer;
            }
            .line{
                background-color: black;
                height: 3px;
                width: 0;
                position: absolute;
                background-color: #911d91;
                transition: width 0.3s ease-in-out;
                text-align:center;
            }
            .boxtext{
                color: white;
                background-color: transparent;
            }

        </style>
    </head>

    <body>
        <h1 class="title">Welcome To Tic Tac Toe</h1>

        <div class="player">
        <span class="info">Turn for: X</span>
        </div>

        <div class="gameContainer">
        <div class="container">
            <div class="line"></div>
            <div class="box border-top-0 border-left-0"><span class="boxtext"></span></div>
            <div class="box border-top-0"><span class="boxtext"></span></div>
            <div class="box border-top-0 border-right-0"><span class="boxtext"></span></div>
            <div class="box border-left-0"><span class="boxtext"></span></div>
            <div class="box"><span class="boxtext"></span></div>
            <div class="box border-right-0"><span class="boxtext"></span></div>
            <div class="box border-bottom-0 border-left-0"><span class="boxtext"></span></div>
            <div class="box border-bottom-0"><span class="boxtext"></span></div>
            <div class="box border-bottom-0 border-right-0"><span class="boxtext"></span></div>
        </div>
        </div>
        <div class="gameInfo">
        <button id="reset" class="btn btn-secondary btn-lg">Start New Game</button>
        </div>


        <script>

            function initializetictactoe(){

                let turn = "X"
                let isgameover = false;

                const changeTurn = ()=>{
                    return turn === "X"? "0": "X"
                }

                const checkWin = ()=>{
                    let boxtext = document.getElementsByClassName('boxtext');
                    let wins = [
                        [0, 1, 2, 5, 5, 0],
                        [3, 4, 5, 5, 15, 0],
                        [6, 7, 8, 5, 25, 0],
                        [0, 3, 6, -5, 15, 90],
                        [1, 4, 7, 5, 15, 90],
                        [2, 5, 8, 15, 15, 90],
                        [0, 4, 8, 5, 15, 45],
                        [2, 4, 6, 5, 15, 135],
                    ]
                    wins.forEach(e =>{
                        if((boxtext[e[0]].innerText === boxtext[e[1]].innerText) && (boxtext[e[2]].innerText === boxtext[e[1]].innerText) && (boxtext[e[0]].innerText !== "") ){
                            document.querySelector('.info').innerText = boxtext[e[0]].innerText + " Won"
                            isgameover = true
                            document.querySelector(".line").style.transform = `translate(${e[3]+29}vw, ${e[4]}vw) rotate(${e[5]}deg)`
                            document.querySelector(".line").style.width = "20vw";   
                            setTimeout(function() {
                                if (confirm(turn+' Lose! Play Again?')) {
                                location.reload();
                                } else {
                                window.location.href = '<%= user_path(current_user.id) %>';
                                }
                            }, 400);     
                        }
                    })
                }

                let boxes = document.getElementsByClassName("box");
                Array.from(boxes).forEach(element =>{
                    let boxtext = element.querySelector('.boxtext');
                    element.addEventListener('click', ()=>{
                        if(boxtext.innerText === ''){
                            boxtext.innerText = turn;
                            turn = changeTurn();
                            checkWin();
                            if (!isgameover){
                                document.getElementsByClassName("info")[0].innerHTML = "Turn for<strong>: " + turn + "</strong>";
                            } 
                        }
                    })
                })

                reset.addEventListener('click', ()=>{
                    let boxtexts = document.querySelectorAll('.boxtext');
                    Array.from(boxtexts).forEach(element => {
                        element.innerText = ""
                    });
                    turn = "X"; 
                    isgameover = false
                    document.querySelector(".line").style.width = "0vw";
                    document.getElementsByClassName("info")[0].innerText  = "Turn for " + turn;
                })
            }

            initializetictactoe();
            
        </script>

    </body>


  </div>

</body>
</html>
"

error log

JavaScript HTML Reactjs Ruby-on-Rails 公理

评论


答:

2赞 Nkemdi Anyiam 10/9/2023 #1

我认为您可以再次尝试使用 dangerouslySetInnerHTML,但这一次,尝试使用游戏 HTML 并将其放入 (NOT ) 属性中。该属性允许您指定要在 .<iframe>srcdocsrcsrcdoc<iframe>

这是我制作的一个 CodePen,用于演示用法(如果一开始没有正确加载,请使用 Ctrl+Shift+7 重新运行代码。我不知道它为什么这样做,但是当我从桌面尝试本地 React 项目中的代码时,它运行良好): https://codepen.io/SonicBoomNFA/pen/eYbbQLy

getGame()模拟检索游戏的 HTML。它返回测试两个事件侦听器的普通 HTML(一个直接在黄色方块上使用属性,另一个使用 using 下面的标签)。我还调用了字符串,它替换了游戏 HTML 中的所有双引号,因为嵌套的双引号会破坏代码。onclick<script><body>addEventListener()sanitize()&quot;

该属性调整 iframe 的大小以适合其内容(受此启发,调整 iframe 的宽度和高度以适合其中的内容)。onload<iframe>

评论

0赞 Freaked Out 10/22/2023
谢谢你的建议,它对我有用
0赞 Nkemdi Anyiam 10/23/2023
好。你能接受答案,这样这个问题就可以解决了吗?