前言
我们在开发组件的时候,很自然的会把组件挂载在父组件上。但是像Modal这类组件,放在具体的DOM中不太合适,应该放在body下比较合适。
那么有没有方法将组件直接挂载到body下呢?答案是有的。 我们可以使用ReactDom.createPortal方法。 Portal 有一个很形象的名称:传送门。就是把组件挂载到任意dom上。
代码示例
如果没有安装react-dom,需要先安装:
yarn add react-dom
我们创建一个Dialog,包括简易内容和样式:
src/portal/Dialog.tsx 内容如下:
import React from 'react'
import './index.css'
export default function Dialog (props: any) {
return (
props.visible && (
<div className='container'>
<div className='content'>{props.content}</div>
<div
className='btn'
onClick={() => {
props.close()
}}
>
关闭
</div>
</div>
)
)
}
src/portal/index.css 如下:
.container {
height: 200px;
width: 200px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: #ddd;
}
.content {
padding: 20px;
}
.btn {
position: absolute;
padding-bottom: 10px;
bottom: 0;
text-align: center;
width: 100%;
cursor:default;
}
接下来是createPortal的使用:
createPortal.tsx:
import React, { useState } from 'react'
import { createPortal } from 'react-dom'
import Dialog from './Dialog'
const Portal = (props: any) => {
const [content, setContent] = useState(new Date().toString())
const [dialogVisible, setDialogVisible] = useState(false)
const div = document.createElement('div')
document.body.appendChild(div)
console.log('render')
return (
<div>
{createPortal(
<Dialog
visible={dialogVisible}
content={content}
close={() => {
setDialogVisible(false)
}}
>
{content}
</Dialog>,
div
)}
<button
onClick={() => {
setContent(new Date().toString())
setDialogVisible(true)
}}
>
弹出消息
</button>
</div>
)
}
export default Portal
createPortal的具体描述如下:
- 方法
createPortal(child, container)
- 参数
-- child
是任何可渲染的 Rax 子元素,例如一个元素,字符串或 Fragment
-- container
是一个 DOM 元素。
在App.tsx中引用 Portal
import React from 'react'
import './App.css'
import Portal from './portal/CreatePortal'
function App () {
return (
<div className='App'>
<header className='App-header'>
<Portal></Portal>
</header>
</div>
)
}
export default App
代码效果
页面中只有一个按钮:
点击以后:
大概的示例就写好了。如果需要丰富的,可自行实现。