React.js. Начало работы. Часть 5 из 12
18.10.2019
Теги: API • DOM • JavaScript • React.js • Web-разработка • Компонент • Фреймворк
Доступ к элементам DOM
Иногда необходимо напрямую обращаться к свойствам и методам HTML-документа. Потому что правильно реализовать такое обращение с использованием JSX и методов React сложно. Давайте рассмотрим простой пример палитры, которая окрашивает белый квадрат цветом, который указан в поле ввода.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>React</title> <script src="https://unpkg.com/react@16.0.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <style> .colorizer { margin: 20px; } .colorizer .colorSquare { box-shadow: 0 0 15px 0 #555555; width: 275px; height: 275px; } .colorizer input { padding: 10px; font-size: 16px; border: 2px solid #777777; } .colorizer button { padding: 10px; font-size: 16px; border: 2px solid #777777; background-color: #999999; color: #FFFFFF; margin: 10px; } </style> </head> <body> <div id="container"></div> <script type="text/babel"> class Colorizer extends React.Component { constructor(props) { super(props); this.state = { color: "", bgColor: "white", } this.saveNewColor = this.saveNewColor.bind(this); this.paintNewColor = this.paintNewColor.bind(this); } saveNewColor(e) { this.setState({ color: e.target.value }); } paintNewColor(e) { this.setState({ bgColor: this.state.color }); e.preventDefault(); } render() { var squareStyle = { backgroundColor: this.state.bgColor }; return ( <div className="colorizer"> <div style={squareStyle} className="colorSquare"></div> <form onSubmit={this.paintNewColor}> <input onChange={this.saveNewColor} placeholder="Значение цвета" /> <button type="submit">OK</button> </form> </div> ); } } ReactDOM.render( <Colorizer/>, document.querySelector('#container') ); </script> <body> </html>
В этом приложении неудобно то, что когда кнопка получает фокус, введенное значение цвета остается в поле ввода. Если нужно ввести другое значение цвета, нужно вернуть фокус в текстовое поле и удалить старое значение. Гораздо удобнее, если бы введенное значение сбрасывалось и фокус возвращащался в текстовое поле сразу после нажатия кнопки ОК.
Использование ссылок
Правильно реализовать такое поведение с использованием JSX и традиционных методов React сложно. С другой стороны, сделать это с помощью API DOM JavaScript для HTML-элементов совсем просто. Для этого можно воспользоваться так называемыми ссылками (refs), доступными в React, чтобы получить доступ к HTML-элементам.
class Colorizer extends React.Component { /* .......... */ render() { var squareStyle = { backgroundColor: this.state.bgColor }; var self = this; return ( <div className="colorizer"> <div style={squareStyle} className="colorSquare"></div> <form onSubmit={this.paintNewColor}> <input onChange={this.saveNewColor} ref={ function(element) { self._input = element; } } placeholder="Значение цвета" /> <button type="submit">OK</button> </form> </div> ); } }
Теперь у нас есть свойство _input
объекта компонента. И через это свойство мы имеем доступ к текстовому полю. Так что можно установить фокус и сбросить введенное ранее значение цвета:
class Colorizer extends React.Component { /* .......... */ paintNewColor(e) { this.setState({ bgColor: this.state.color }); // устанавливаем фокус на текстовое поле this._input.focus(); // сбрасываем значение текстового поля this._input.value = ""; e.preventDefault(); } /* .......... */ }
Использование порталов
До сих пор мы вставляли JSX-код внутрь элемента страницы, который указывался вторым аргументом метода render()
:
ReactDOM.render( <Colorizer/>, document.querySelector('#container') );
Но можно отображать JSX-контент внутри любого элемента страницы. Это функционал, известный как порталы. Добавим в наш пример заголовок и будем показывать в заголовке выбранный в палитре цвет.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>React</title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <style> #heading { margin: 20px; font-family: sans-serif; } .colorizer { margin: 20px; } .colorizer .colorSquare { box-shadow: 0 0 15px 0 #555555; width: 275px; height: 275px; } .colorizer input { padding: 10px; font-size: 16px; border: 2px solid #777777; } .colorizer button { padding: 10px; font-size: 16px; border: 2px solid #777777; background-color: #999999; color: #FFFFFF; margin: 10px; } </style> </head> <body> <h1 id="heading">Палитра</h1> <div id="container"></div> <script type="text/babel"> class Colorizer extends React.Component { constructor(props) { super(props); this.state = { color: "", bgColor: "white", } this.saveNewColor = this.saveNewColor.bind(this); this.paintNewColor = this.paintNewColor.bind(this); } saveNewColor(e) { this.setState({ color: e.target.value }); } paintNewColor(e) { this.setState({ bgColor: this.state.color }); e.preventDefault(); } render() { var squareStyle = { backgroundColor: this.state.bgColor }; return ( <div className="colorizer"> <div style={squareStyle} className="colorSquare"></div> <form onSubmit={this.paintNewColor}> <input onChange={this.saveNewColor} placeholder="Значение цвета" /> <button type="submit">OK</button> </form> <ColorLabel color={this.state.bgColor} /> </div> ); } } class ColorLabel extends React.Component { render() { var style = { color: this.props.color == "white" ? "lightgray" : this.props.color } return ReactDOM.createPortal( <span> : <span style={style}>{this.props.color}</span> </span>, document.querySelector('#heading') ); } } ReactDOM.render( <Colorizer/>, document.querySelector('#container') ); </script> <body> </html>
Метод ReactDOM.createPortal()
принимает два аргумента: JSX-код для вывода и элемент DOM для вывода этого кода. Мы добавляем к существующему содержимому заголовка JSX-контент, и в результате наш заголовок будет таким:
<h1 id="heading"> Палитра<span>: <span style="color: green;">green</span></span> </h1>
Поиск: API • DOM • JavaScript • React.js • Web-разработка • Фреймворк • Компонент