javascript - dangerouslysetinnerhtml - react.fragment vs div
¿Cómo puedo desplazar un div para que sea visible en ReactJS? (8)
Tengo una lista emergente que es un
div
que contiene una lista vertical de
div
s secundarios.
He agregado la navegación arriba / abajo del teclado para cambiar qué niño está resaltado actualmente.
En este momento, si presiono la tecla hacia abajo varias veces, el elemento resaltado ya no es visible. Lo mismo ocurre también con la tecla arriba si la vista se desplaza.
¿Cuál es la forma correcta en React para desplazar automáticamente un
div
hijo a la vista?
En caso de que alguien tropiece aquí, lo hice de esta manera.
componentDidMount(){
const node = this.refs.trackerRef;
node && node.scrollIntoView({block: "end", behavior: ''smooth''})
}
componentDidUpdate() {
const node = this.refs.trackerRef;
node && node.scrollIntoView({block: "end", behavior: ''smooth''})
}
render() {
return (
<div>
{messages.map((msg, index) => {
return (
<Message key={index} msgObj={msg}
{/*<p>some test text</p>*/}
</Message>
)
})}
<div style={{height: ''30px''}} id=''#tracker'' ref="trackerRef"></div>
</div>
)
}
scrollIntoView
es un
link
función DOM nativo
Siempre mostrará
tracker
div
En su controlador keyup / down solo necesita establecer la propiedad
scrollTop
del div que desea desplazar para que se desplace hacia abajo (o hacia arriba).
Por ejemplo:
JSX:
<div ref="foo">{content}</div>
keyup / down handler:
this.refs.foo.getDOMNode().scrollTop += 10
Si hace algo similar a lo anterior, su div se desplazará hacia abajo 10 píxeles (suponiendo que el div esté configurado para desbordarse
auto
o
scroll
en css, y su contenido se desborda, por supuesto).
Tendrá que ampliar esto para encontrar el desplazamiento del elemento dentro de su div de desplazamiento al que desea desplazar el div hacia abajo, y luego modificar el
scrollTop
para desplazarse lo suficiente como para mostrar el elemento en función de su altura.
Echa un vistazo a las definiciones de MDN de scrollTop y offsetTop aquí:
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop
Otro ejemplo que usa la función en ref en lugar de string
class List extends React.Component {
constructor(props) {
super(props);
this.state = { items:[], index: 0 };
this._nodes = new Map();
this.handleAdd = this.handleAdd.bind(this);
this.handleRemove = this.handleRemove.bind(this);
}
handleAdd() {
let startNumber = 0;
if (this.state.items.length) {
startNumber = this.state.items[this.state.items.length - 1];
}
let newItems = this.state.items.splice(0);
for (let i = startNumber; i < startNumber + 100; i++) {
newItems.push(i);
}
this.setState({ items: newItems });
}
handleRemove() {
this.setState({ items: this.state.items.slice(1) });
}
handleShow(i) {
this.setState({index: i});
const node = this._nodes.get(i);
console.log(this._nodes);
if (node) {
ReactDOM.findDOMNode(node).scrollIntoView({block: ''end'', behavior: ''smooth''});
}
}
render() {
return(
<div>
<ul>{this.state.items.map((item, i) => (<Item key={i} ref={(element) => this._nodes.set(i, element)}>{item}</Item>))}</ul>
<button onClick={this.handleShow.bind(this, 0)}>0</button>
<button onClick={this.handleShow.bind(this, 50)}>50</button>
<button onClick={this.handleShow.bind(this, 99)}>99</button>
<button onClick={this.handleAdd}>Add</button>
<button onClick={this.handleRemove}>Remove</button>
{this.state.index}
</div>
);
}
}
class Item extends React.Component
{
render() {
return (<li ref={ element => this.listItem = element }>
{this.props.children}
</li>);
}
}
Demostración: https://codepen.io/anon/pen/XpqJVe
Para React 16, la respuesta correcta es diferente de las respuestas anteriores:
class Something extends Component {
constructor(props) {
super(props);
this.boxRef = React.createRef();
}
render() {
return (
<div ref={this.boxRef} />
);
}
}
Luego, para desplazarse, simplemente agregue (después del constructor):
componentDidMount() {
if (this.props.active) { // whatever your test might be
this.boxRef.current.scrollIntoView();
}
}
Nota: debe usar ''.current'' y puede enviar opciones para desplazarse por ViewInto:
scrollIntoView({
behavior: ''smooth'',
block: ''center'',
inline: ''center'',
});
(Encontrado en http://www.albertgao.xyz/2018/06/07/scroll-a-not-in-view-component-into-the-view-using-react/ )
Al leer la especificación, fue un poco difícil descubrir el significado de bloque e inline, pero después de jugar con ella, descubrí que para una lista de desplazamiento vertical, block: ''end'' se aseguró de que el elemento fuera visible sin desplazar artificialmente la parte superior de mi contenido fuera de la ventana gráfica. Con ''centro'', un elemento cerca del fondo se deslizaría demasiado y aparecería un espacio vacío debajo. Pero mi contenedor es un padre flexible con justificación: ''estiramiento'' para que eso pueda afectar el comportamiento. No excavé mucho más. Los elementos con desbordamiento oculto afectarán la forma en que actúa scrollIntoView, por lo que probablemente tendrá que experimentar por su cuenta.
Mi aplicación tiene un padre que debe estar a la vista y si se selecciona un niño, también se desplaza a la vista. Esto funcionó bien ya que el DidMount principal ocurre antes que el DidMount del niño, por lo que se desplaza hacia el padre, luego, cuando se procesa el hijo activo, se desplaza aún más para mostrarlo.
Para basarme en la respuesta de @Michelle Tilley, a veces quiero desplazarme si la selección del usuario cambia, por lo que activé el desplazamiento en
componentDidUpdate
.
También hice algunos cálculos para averiguar hasta dónde desplazarse y si era necesario desplazarse, lo que para mí se parece a lo siguiente:
componentDidUpdate() {
let panel, node;
if (this.refs.selectedSection && this.refs.selectedItem) {
// This is the container you want to scroll.
panel = this.refs.listPanel;
// This is the element you want to make visible w/i the container
// Note: You can nest refs here if you want an item w/i the selected item
node = ReactDOM.findDOMNode(this.refs.selectedItem);
}
if (panel && node &&
(node.offsetTop > panel.scrollTop + panel.offsetHeight || node.offsetTop < panel.scrollTop)) {
panel.scrollTop = node.offsetTop - panel.offsetTop;
}
}
Solo estoy agregando otro bit de información para otros que buscan una capacidad de desplazamiento en React. Había vinculado varias bibliotecas para hacer Scroll-To para mi aplicación, y ninguna funcionó desde mi caso de uso hasta que encontré react-scrollchor, así que pensé en pasarla. https://github.com/bySabi/react-scrollchor
Supongo que tiene algún tipo de componente
List
y algún tipo de componente
Item
.
La forma en que lo hice
en un proyecto
fue informarle al elemento si estaba activo o no;
el elemento le pedirá a la lista que lo desplace a la vista si es necesario.
Considere el siguiente pseudocódigo:
class List extends React.Component {
render() {
return <div>{this.props.items.map(this.renderItem)}</div>;
}
renderItem(item) {
return <Item key={item.id} item={item}
active={item.id === this.props.activeId}
scrollIntoView={this.scrollElementIntoViewIfNeeded} />
}
scrollElementIntoViewIfNeeded(domNode) {
var containerDomNode = React.findDOMNode(this);
// Determine if `domNode` fully fits inside `containerDomNode`.
// If not, set the container''s scrollTop appropriately.
}
}
class Item extends React.Component {
render() {
return <div>something...</div>;
}
componentDidMount() {
this.ensureVisible();
}
componentDidUpdate() {
this.ensureVisible();
}
ensureVisible() {
if (this.props.active) {
this.props.scrollIntoView(React.findDOMNode(this));
}
}
}
Probablemente, una mejor solución es hacer que la lista sea responsable de desplazar el elemento a la vista (sin que el elemento sepa que está incluso en una lista).
Para hacerlo, puede agregar un atributo de
ref
a un determinado elemento y encontrarlo con eso:
class List extends React.Component {
render() {
return <div>{this.props.items.map(this.renderItem)}</div>;
}
renderItem(item) {
var active = item.id === this.props.activeId;
var props = {
key: item.id,
item: item,
active: active
};
if (active) {
props.ref = "activeItem";
}
return <Item {...props} />
}
componentDidUpdate(prevProps) {
// only scroll into view if the active item changed last render
if (this.props.activeId !== prevProps.activeId) {
this.ensureActiveItemVisible();
}
}
ensureActiveItemVisible() {
var itemComponent = this.refs.activeItem;
if (itemComponent) {
var domNode = React.findDOMNode(itemComponent);
this.scrollElementIntoViewIfNeeded(domNode);
}
}
scrollElementIntoViewIfNeeded(domNode) {
var containerDomNode = React.findDOMNode(this);
// Determine if `domNode` fully fits inside `containerDomNode`.
// If not, set the container''s scrollTop appropriately.
}
}
Si no desea hacer los cálculos para determinar si el elemento está visible dentro del nodo de la lista, puede usar el
método DOM
scrollIntoView()
o el
scrollIntoViewIfNeeded
específico del
scrollIntoViewIfNeeded
, que
tiene un polyfill disponible
para que pueda usarlo en -Webkit navegadores.
Tenía un NavLink que quería que al hacer clic se desplazara a ese elemento como lo hace el ancla con nombre. Lo implementé de esta manera.
<NavLink onClick={() => this.scrollToHref(''plans'')}>Our Plans</NavLink>
scrollToHref = (element) =>{
let node;
if(element === ''how''){
node = ReactDom.findDOMNode(this.refs.how);
console.log(this.refs)
}else if(element === ''plans''){
node = ReactDom.findDOMNode(this.refs.plans);
}else if(element === ''about''){
node = ReactDom.findDOMNode(this.refs.about);
}
node.scrollIntoView({block: ''start'', behavior: ''smooth''});
}
Luego le doy el componente que quería desplazar a una referencia como esta
<Investments ref="plans"/>