2017-08-16 276 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; 
     }