2017-08-16 271 views
26

我有一个ulmax-heightoverflow-y: auto滚动到反应中溢出的div的底部

当用户输入足够的li元素时,ul开始滚动,但我想最后li在它与form始终存在并显示给用户。

我已经尝试实现scrollToBottom功能,看起来像这样:

scrollToBottom() { 
    this.formLi.scrollIntoView({ behavior: 'smooth' }); 
} 

但是,这只是使ul跳到屏幕的顶部,显示li与形式,它作为唯一可见事情。

有没有更好的方法来实现这个目标?我发现的答案往往会有点老,并使用ReactDOM。谢谢!

CSS:

.prompt-box .options-holder { 
    list-style: none; 
    padding: 0; 
    width: 95%; 
    margin: 12px auto; 
    max-height: 600px; 
    overflow-y: auto; 
} 

HTML:

​​
+0

在这种情况下,也许你将最后一个li移出ul并添加另一个包装 –

+0

为什么我要这样做,而不是只滚动ul? –

回答

1

我有我在我的项目之一,用于平滑滚动顶部的脚本,我做了一个小重构滚动高度你的div(滚动底部)我希望它有帮助。

scroll.js

function currentYPosition() { 
    if (self.pageYOffset) return self.pageYOffset; 
    if (document.documentElement && document.documentElement.scrollHeight) return document.documentElement.scrollHeight; 
    if (document.body.scrollHeight) return document.body.scrollHeight; 

    return 0; 
} 

function elmYPosition(eID) { 
    let elm = document.getElementById(eID); 
    let y = elm.offsetHeight; 
    let node = elm; 
    while (node.offsetParent && node.offsetParent != document.body) { 
    node = node.offsetParent; 
    y += node.offsetHeight; 
    } 
    return y; 
} 

export default function smoothScroll(eID, string) { 
    let startY = currentYPosition(); 
    let stopY = elmYPosition(eID); 
    let distance = stopY > startY ? stopY - startY : startY - stopY; 
    let speed = Math.round(distance/10); 
    let speedTimeout = 250; 
    if (speed >= 100) speed = 100; 
    if (string) speed = 1; 
    let step = Math.round(distance/25); 
    let leapY = stopY > startY ? startY + step : startY - step; 
    let timer = 0; 
    if (stopY > startY) { 
    for (let i = startY; i < stopY; i += step) { 
     setTimeout('window.scrollTo(0, ' + leapY + ')', timer * speed); 
     leapY += step; 
     if (leapY > stopY) leapY = stopY; 
     timer++; 
    } 
    return; 
    } 
    for (let i = startY; i > stopY; i -= step) { 
    setTimeout('window.scrollTo(0, ' + (leapY) + ')', timer * speed); 
    leapY -= step; 
    if (leapY < stopY){ 
     leapY = stopY; 
    } 
    timer++; 
    } 
} 

你应该导入这个您的组件里面,有2个参数(你的元素的ID,在这种情况下,你可以使用参考。第二个是我已经用于治疗的滚动速度的字符串。

import scroll from './your-path/scroll.js'; 
. 
. 
. 
<ul className='options-holder'> 
{ 
    this.state.items.map((item, index) => (
     <li key={item.id} className={`option ${index === 0 ? 'first' : ''}`} ref={el => (this.formLi = el)}> 
      <div className='circle' onClick={this.removeItem} /> 

      <p className='item-text'>{ item.text }</p> 
     </li> 
    )) 
} 

<li key={0} className={`option form ${this.state.items.length === 0 ? 'only' : ''}`} ref={el => (this.formLi = el)}> 
    <div className='circle form' /> 

    <form className='new-item-form' onSubmit={this.handleSubmit}> 
     <input 
      autoFocus 
      className='new-item-input' 
      placeholder='Type something and press return...' 
      onChange={this.handleChange} 
      value={this.state.text} 
      ref={(input) => (this.formInput = input)} /> 
    </form> 
</li> 

Idk你如何在你的渲染中映射这个LI,但你应该进行验证,如果有属性溢出,你应该运行滚动。

有一个合理的答案,你的组件跳到第一个元素,你击中了第一个元素的ref,而不是最后一个。

可能的解决方法:

scroll(this.state.items[this.state.items.length - 1]); 

更新1:吉斯特原scroll.js的,scrolling to the top

+0

谢谢尤里。要清楚的是,只有里面带有'form'的'li'具有'ref'标签。不是其他的。可能的解决方法是不工作的'ref'也不''this'具有'滚动'功能 –

2

好像你正在构建一个聊天式界面。您可以尝试包裹<ul>,并在一个单独的DIV的div.circle-form象下面这样:

ul{ 
 
    border:1px solid red; 
 
    height:13em; 
 
    overflow-y:auto; 
 
    position:relative; 
 
} 
 
ul li{ 
 
    border-bottom:1px solid #ddd; 
 
    list-style:none; 
 
    margin-left:0; 
 
    padding:6px; 
 
} 
 

 
.wrapper{ 
 
    background:#eee; 
 
    height:15em; 
 
    position:relative; 
 
} 
 
.circle-form{ 
 
    background:#ddd; 
 
    height:2em; 
 
    padding:3px; 
 
    position:absolute; 
 
    bottom:0; 
 
    left:0; 
 
    right:0; 
 
    z-index:2; 
 
} 
 
.circle-form input[type=text]{ 
 
    padding:8px; 
 
    width:50%; 
 
}
<div class="wrapper"> 
 
    <ul id="list"> 
 
     <li>item</li> 
 
     <li>item</li> 
 
     <li>item</li> 
 
     <li>item</li> 
 
     <li>item</li> 
 
     <li>item</li> 
 
     <li>item</li> 
 
     <li>item</li> 
 
    </ul> 
 
    <div class="circle-form"> 
 
     <input type="text" name="type_here" placeholder="Enter something..." autofocus/> 
 
    </div> 
 
</div>

编辑

而且滚动到列表的底部用JavaScript

var list = document.getElementById("list"); 
list.scrollTop = list.offsetHeight; 
+2

我没有在我的应用程序中使用jQuery,并且不打算 –

+0

从jquery编辑到香草javascript – William

2

使用react-scroll库。但是,您必须明确设置您的ul的ID。

import { animateScroll } from "react-scroll"; 

scrollToBottom() { 
    animateScroll.scrollToBottom({ 
     containerId: "options-holder" 
    }); 
} 

您可以在回调的setState叫scrollToBottom

例如

this.setState({ items: newItems}, this.scrollToBottom); 

,或者使用的setTimeout。

或者你甚至可以设置Elementreact-scroll和滚动到某个li

1

只需使用position:sticky s.t.最后的列表项总是显示。

li:last-child { 
    position:sticky; 
    bottom:0; 
} 

Demo

Caniuse

1

我有一个类似的问题,当它来渲染,从一个用户导入进来组件阵列。我结束了使用componentDidUpdate()函数让我的工作。

componentDidUpdate() { 
     // I was not using an li but may work to keep your div scrolled to the bottom as li's are getting pushed to the div 
     const objDiv = document.getElementById('div'); 
     objDiv.scrollTop = objDiv.scrollHeight; 
     }