概要
みなさんこんにちはcandleです。今回はreact-modalの背面がスクロールした時に動いてしまう問題を解決してみたいと思います。
前提
- reactの知識がある
完成版のサンプルコード
サンプルコードを実際に動かしたい場合は以下の2つのライブラリをインストールしてください。
fakerはダミーデータ生成のためにインストールしています。
yarn add faker react-modal
先に完成版のサンプルコードを記述しておきます。これはsrc/App.js
に記述しています。
import React, { Component } from 'react' import Faker from 'faker' import Modal from 'react-modal' Modal.setAppElement('#root') class App extends Component { constructor(props) { super(props) this.state = { users: [], user: { products: [], }, modalIsOpen: false, } } componentWillMount() { for (let i = 0; i < 10; i++) { let products = [] for (let j = 0; j < 6; j++) { const product = { name: Faker.commerce.productName(), price: Faker.commerce.price(), image: Faker.image.food(30, 40), } products = [...products, product] } const user = { name: Faker.internet.userName(), email: Faker.internet.email(), avatar: Faker.internet.avatar(), products: products, } this.setState(prevState => ({ users: [...prevState.users, user], })) } } openModal(user) { this.setState({ user: user, modalIsOpen: true, }) document.body.setAttribute('style', 'overflow: hidden;') } closeModal() { this.setState({ modalIsOpen: false }) document.body.removeAttribute('style', 'overflow: hidden;') } renderProducts(product) { return ( <div style={{ border: 'solid 1px #eee' }}> <img src={product.image} alt={product.name} width="50" height="50" /> <h4>Name: {product.name}</h4> <h4>Price: {product.price}</h4> </div> ) } renderUsers(user) { return ( <div style={{ border: 'solid 1px #eee' }} onClick={this.openModal.bind(this, user)}> <img src={user.avatar} alt={user.name} width="50" height="50" /> <h4>Name: {user.name}</h4> <h4>Email: {user.email}</h4> </div> ) } render() { return ( <div> {this.state.users.map(user => this.renderUsers(user))} <Modal isOpen={this.state.modalIsOpen} onRequestClose={this.closeModal.bind(this)} style={customStyles} contentLabel="Example Modal" > <h2> {this.state.user.name} の制作物 </h2> <button onClick={this.closeModal.bind(this)}>Close</button> {this.state.user.products.map(product => this.renderProducts(product))} </Modal> </div> ) } } const customStyles = { overlay: { position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(255, 255, 255, 0.75)', }, content: { position: 'absolute', top: '40px', left: '40px', right: '40px', bottom: '40px', border: '1px solid #ccc', background: '#fff', overflow: 'auto', WebkitOverflowScrolling: 'touch', borderRadius: '4px', outline: 'none', padding: '20px', }, } export default App
サーバを起動し、
yarn run start
ブラウザで確認するとこのような画面が表示されます。
モーダルを開いた時に背面が動かないでしょう。
モーダルをcssで固定
固定は簡単で、<body>
タグにcssのoverflow hiddenを付与するだけです。
モーダルを開く関数にdocument.body.setAttribute('style', 'overflow: hidden;')
を付与します。サンプルコードの場合はopenModal()
になります。
openModal(user) { this.setState({ user: user, modalIsOpen: true, }) document.body.setAttribute('style', 'overflow: hidden;') }
逆に、モーダルを閉じる時はこのoverflow: hidden
を取り去ります。
モーダルを閉じる関数にはdocument.body.removeAttribute('style', 'overflow: hidden;')
を書きましょう。
サンプルコードはこうします。
closeModal() { this.setState({ modalIsOpen: false }) document.body.removeAttribute('style', 'overflow: hidden;') }
これで背面が固定されます。
まとめ
ちょっとしたことでしたが、実はこの方法を見つけるまでに試行錯誤と紆余曲折をしました。
良いReactライフを