提问人:Freaked Out 提问时间:10/9/2023 最后编辑:Freaked Out 更新时间:10/9/2023 访问量:108
警告:validateDOMNesting(...):<html>不能显示为 <div 的子级>
Warning: validateDOMNesting(...): <html> cannot appear as a child of <div>
问:
[编辑:我也尝试了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;
游戏代码如下:
"<!-- 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>
"
答:
我认为您可以再次尝试使用 dangerouslySetInnerHTML,但这一次,尝试使用游戏 HTML 并将其放入 (NOT ) 属性中。该属性允许您指定要在 .<iframe>
srcdoc
src
srcdoc
<iframe>
这是我制作的一个 CodePen,用于演示用法(如果一开始没有正确加载,请使用 Ctrl+Shift+7 重新运行代码。我不知道它为什么这样做,但是当我从桌面尝试本地 React 项目中的代码时,它运行良好): https://codepen.io/SonicBoomNFA/pen/eYbbQLy
getGame()
模拟检索游戏的 HTML。它返回测试两个事件侦听器的普通 HTML(一个直接在黄色方块上使用属性,另一个使用 using 下面的标签)。我还调用了字符串,它替换了游戏 HTML 中的所有双引号,因为嵌套的双引号会破坏代码。onclick
<script>
<body>
addEventListener()
sanitize()
"
该属性调整 iframe 的大小以适合其内容(受此启发,调整 iframe 的宽度和高度以适合其中的内容)。onload
<iframe>
评论