max-height
とoverflow-y: auto
を持つul
があります。
ユーザーが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:
<ul className='options-holder'>
{
this.state.items.map((item, index) => (
<li key={item.id} className={`option ${index === 0 ? 'first' : ''}`}>
<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>
</ul>
react-scroll libraryを使用します。ただし、ul
のIDを明示的に設定する必要があります。
import { animateScroll } from "react-scroll";
scrollToBottom() {
animateScroll.scrollToBottom({
containerId: "options-holder"
});
}
SetStateコールバックでscrollToBottom
を呼び出すことができます。
例えば
this.setState({ items: newItems}, this.scrollToBottom);
または、setTimeoutを使用します。
または、react-scroll
からElement
を設定し、特定のli
までスクロールすることもできます。
チャットのようなインターフェイスを構築しているようです。 <ul>
そしてその div.circle-form
以下のような別のdivで:
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>
[〜#〜] edit [〜#〜]
そして、javascriptでリストの一番下までスクロールします
var list = document.getElementById("list");
list.scrollTop = list.offsetHeight;
ユーザーインポートから取得したコンポーネントの配列をレンダリングする際に、同様の問題が発生しました。最終的には、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;
}
プロジェクトの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、この場合はrefを使用できます。2番目のパラメーターは、スクロールの速度を処理するために使用した文字列です。
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>
このLIをレンダー内でどのようにマッピングするかをIdkで確認しますが、検証を行う必要があります。プロパティOverflowがある場合は、スクロールを実行する必要があります。
コンポーネントには最初の要素にジャンプするという合理的な答えがあります。最後ではなく、最初の要素の参照にヒットしています。
可能な回避策:
scroll(this.state.items[this.state.items.length - 1]);
更新1:元のscroll.jsの要点、 上部へスクロール