바깥쪽 div 크기가 변경되면 스크롤 가능한 div를 바닥에 고정합니다.
다음은 채팅 앱 예시입니다.->
는, 「아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아,.messages-container
을 사용법★★★내.messages-container
,.scroll
는 메시지 목록을 보관하고 있습니다.메시지가 화면 크기보다 많을 경우 스크롤합니다.
이제 다음 경우를 생각해 보겠습니다.
- 사용자가 대화의 맨 아래까지 스크롤합니다.
.text-input
으로
사용자가 컨버세이션의 맨 아래까지 스크롤하지 않고 텍스트 입력이 증가하여 맨 아래가 표시되지 않게 됩니다.
리액트를 사용하는 경우 텍스트 입력 높이를 계산하고 변경 사항이 있을 경우 .messages-container에 알립니다.
componentDidUpdate() {
window.setTimeout(_ => {
const newHeight = this.calcHeight();
if (newHeight !== this._oldHeight) {
this.props.onResize();
}
this._oldHeight = newHeight;
});
}
하지만 이는 눈에 보이는 성능 문제를 야기하고, 이렇게 메시지를 전달하는 것은 슬픈 일입니다.
더은 방법 ?? ???를 사용하여 .text-input-input-input-increments가 증가할 때 기본적으로 .text-input-input-increments를 할 수 ?shift up
.
2: 이 답변의 두 번째 수정
는 기기입니다.flex-direction: column-reverse;
예를 들어 Skype나 다른 많은 채팅 앱처럼 메시지 컨테이너의 맨 아래에 메시지를 정렬하면서 모든 것을 묻습니다.
.chat-window{
display:flex;
flex-direction:column;
height:100%;
}
.chat-messages{
flex: 1;
height:100%;
overflow: auto;
display: flex;
flex-direction: column-reverse;
}
.chat-input { border-top: 1px solid #999; padding: 20px 5px }
.chat-input-text { width: 60%; min-height: 40px; max-width: 60%; }
「 」의 flex-direction: column-reverse;
는 IE/Edge/Firefox의 버그입니다.스크롤바는 표시되지 않습니다.자세한 내용은 다음 URL에서 확인할 수 있습니다.Firefox/IE의 Flexbox column-reverse 및 overflow 입니다.
장점은 모바일/태블릿에서 최대 90%, 데스크톱에서 최대 65%의 브라우저를 지원한다는 것입니다.또한 버그가 수정되면 회피책이 있습니다.
// scroll to bottom
function updateScroll(el){
el.scrollTop = el.scrollHeight;
}
// only shift-up if at bottom
function scrollAtBottom(el){
return (el.scrollTop + 5 >= (el.scrollHeight - el.offsetHeight));
}
코드 두 flex-direction: column-reverse;
function addContent () {
var msgdiv = document.getElementById('messages');
var msgtxt = document.getElementById('inputs');
var atbottom = scrollAtBottom(msgdiv);
if (msgtxt.value.length > 0) {
msgdiv.innerHTML += msgtxt.value + '<br/>';
msgtxt.value = "";
} else {
msgdiv.innerHTML += 'Long long content ' + (tempCounter++) + '!<br/>';
}
/* if at bottom and is IE/Edge/Firefox */
if (atbottom && (!isWebkit || isEdge)) {
updateScroll(msgdiv);
}
}
function resizeInput () {
var msgdiv = document.getElementById('messages');
var msgtxt = document.getElementById('inputs');
var atbottom = scrollAtBottom(msgdiv);
if (msgtxt.style.height == '120px') {
msgtxt.style.height = 'auto';
} else {
msgtxt.style.height = '120px';
}
/* if at bottom and is IE/Edge/Firefox */
if (atbottom && (!isWebkit || isEdge)) {
updateScroll(msgdiv);
}
}
/* fix for IE/Edge/Firefox */
var isWebkit = ('WebkitAppearance' in document.documentElement.style);
var isEdge = ('-ms-accelerator' in document.documentElement.style);
var tempCounter = 6;
function updateScroll(el){
el.scrollTop = el.scrollHeight;
}
function scrollAtBottom(el){
return (el.scrollTop + 5 >= (el.scrollHeight - el.offsetHeight));
}
html, body { height:100%; margin:0; padding:0; }
.chat-window{
display:flex;
flex-direction:column;
height:100%;
}
.chat-messages{
flex: 1;
height:100%;
overflow: auto;
display: flex;
flex-direction: column-reverse;
}
.chat-input { border-top: 1px solid #999; padding: 20px 5px }
.chat-input-text { width: 60%; min-height: 40px; max-width: 60%; }
/* temp. buttons for demo */
button { width: 12%; height: 44px; margin-left: 5%; vertical-align: top; }
/* begin - fix for hidden scrollbar in IE/Edge/Firefox */
.chat-messages-text{ overflow: auto; }
@media screen and (-webkit-min-device-pixel-ratio:0) {
.chat-messages-text{ overflow: visible; }
/* reset Edge as it identifies itself as webkit */
@supports (-ms-accelerator:true) { .chat-messages-text{ overflow: auto; } }
}
/* hide resize FF */
@-moz-document url-prefix() { .chat-input-text { resize: none } }
/* end - fix for hidden scrollbar in IE/Edge/Firefox */
<div class="chat-window">
<div class="chat-messages">
<div class="chat-messages-text" id="messages">
Long long content 1!<br/>
Long long content 2!<br/>
Long long content 3!<br/>
Long long content 4!<br/>
Long long content 5!<br/>
</div>
</div>
<div class="chat-input">
<textarea class="chat-input-text" placeholder="Type your message here..." id="inputs"></textarea>
<button onclick="addContent();">Add msg</button>
<button onclick="resizeInput();">Resize input</button>
</div>
</div>
Side Note 1: 이 검출 방법은 완전히 테스트되지 않았지만 새로운 브라우저에서 작동합니다.
사이드 노트 2: 채팅 입력에 크기 조정 이벤트핸들러를 접속하는 것이 update Scroll 함수를 호출하는 것보다 효율적일 수 있습니다.
주의: HaZardouS의 html 구조 재사용 크레딧
필요한 CSS 규칙 세트는 1개뿐입니다.
.messages-container, .scroll {transform: scale(1,-1);}
됐어, 넌 끝났어!
구조:먼저 컨테이너 요소를 수직으로 플립하여 맨 위가 맨 아래가 되도록 한 다음(원하는 스크롤 방향을 제공), 메시지가 뒤집히지 않도록 내용 요소를 플립합니다.
이 접근 방식은 최신 브라우저 모두에서 작동합니다.다만, 이상한 부작용이 있습니다.메시지 상자에서 마우스 휠을 사용하면 스크롤 방향이 반대입니다.이것은 아래와 같이 JavaScript의 몇 줄로 수정할 수 있습니다.
여기 데모와 바이올린이 있습니다.
//Reverse wheel direction
document.querySelector('.messages-container').addEventListener('wheel', function(e) {
if(e.deltaY) {
e.preventDefault();
e.currentTarget.scrollTop -= e.deltaY;
}
});
//The rest of the JS just handles the test buttons and is not part of the solution
send = function() {
var inp = document.querySelector('.text-input');
document.querySelector('.scroll').insertAdjacentHTML('beforeend', '<p>' + inp.value);
inp.value = '';
inp.focus();
}
resize = function() {
var inp = document.querySelector('.text-input');
inp.style.height = inp.style.height === '50%' ? null : '50%';
}
html,body {height: 100%;margin: 0;}
.conversation {
display: flex;
flex-direction: column;
height: 100%;
}
.messages-container {
flex-shrink: 10;
height: 100%;
overflow: auto;
}
.messages-container, .scroll {transform: scale(1,-1);}
.text-input {resize: vertical;}
<div class="conversation">
<div class="messages-container">
<div class="scroll">
<p>Message 1<p>Message 2<p>Message 3<p>Message 4<p>Message 5
<p>Message 6<p>Message 7<p>Message 8<p>Message 9<p>Message 10<p>Message 11<p>Message 12<p>Message 13<p>Message 14<p>Message 15<p>Message 16<p>Message 17<p>Message 18<p>Message 19<p>Message 20
</div>
</div>
<textarea class="text-input" autofocus>Your message</textarea>
<div>
<button id="send" onclick="send();">Send input</button>
<button id="resize" onclick="resize();">Resize input box</button>
</div>
</div>
편집: 스크롤 코드의 심플화를 제안해 주신 @Some Special 덕분입니다!
다음 바이올린을 사용해 보세요.https://jsfiddle.net/Hazardous/bypxg25c/현재 바이올린은 jQuery를 사용하여 텍스트 영역을 확대/크기 조정하고 있지만, 핵심은 메시지 컨테이너 및 입력 컨테이너 클래스에 사용되는 플렉스 관련 스타일입니다.
.messages-container{
order:1;
flex:0.9 1 auto;
overflow-y:auto;
display:flex;
flex-direction:row;
flex-wrap:nowrap;
justify-content:flex-start;
align-items:stretch;
align-content:stretch;
}
.input-container{
order:2;
flex:0.1 0 auto;
}
flex-shrink 값은 .messages-container의 경우 1, .input-container의 경우 0으로 설정됩니다.이렇게 하면 크기가 재할당될 때 메시지컨테이너가 축소됩니다.
text-input
의 범위 내에서messages
의 맨 하고 absolute를 지정하면 absolute는 "Absolute"로 지정합니다.messages
충분한 하단 패딩 공간을 확보해야 합니다.
가지 를 실행하여 를 에 합니다.conversation
가 바뀌게 됩니다.text-input
「」의 messages
CSS를 사용하다
JavaScript는 CSS 이행 실행과 동시에 "scrollTo" 함수를 실행하여 스크롤을 맨 아래에 유지합니다.
맨 때, 뺄 수 있습니다.conversation
이게 도움이 됐으면 좋겠다.
https://jsfiddle.net/cnvzLfso/5/
var doScollCheck = true;
var objConv = document.querySelector('.conversation');
var objMessages = document.querySelector('.messages');
var objInput = document.querySelector('.text-input');
function scrollTo(element, to, duration) {
if (duration <= 0) {
doScollCheck = true;
return;
}
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
setTimeout(function() {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop === to) {
doScollCheck = true;
return;
}
scrollTo(element, to, duration - 10);
}, 10);
}
function resizeInput(atBottom) {
var className = 'bigger',
hasClass;
if (objConv.classList) {
hasClass = objConv.classList.contains(className);
} else {
hasClass = new RegExp('(^| )' + className + '( |$)', 'gi').test(objConv.className);
}
if (atBottom) {
if (!hasClass) {
doScollCheck = false;
if (objConv.classList) {
objConv.classList.add(className);
} else {
objConv.className += ' ' + className;
}
scrollTo(objMessages, (objMessages.scrollHeight - objMessages.offsetHeight) + 50, 500);
}
} else {
if (hasClass) {
if (objConv.classList) {
objConv.classList.remove(className);
} else {
objConv.className = objConv.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
}
}
objMessages.addEventListener('scroll', function() {
if (doScollCheck) {
var isBottom = ((this.scrollHeight - this.offsetHeight) === this.scrollTop);
resizeInput(isBottom);
}
});
html,
body {
height: 100%;
width: 100%;
background: white;
}
body {
margin: 0;
padding: 0;
}
.conversation {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
position: relative;
}
.messages {
overflow-y: scroll;
padding: 10px 10px 60px 10px;
-webkit-transition: padding .5s;
-moz-transition: padding .5s;
transition: padding .5s;
}
.text-input {
padding: 10px;
-webkit-transition: height .5s;
-moz-transition: height .5s;
transition: height .5s;
position: absolute;
bottom: 0;
height: 50px;
background: white;
}
.conversation.bigger .messages {
padding-bottom: 110px;
}
.conversation.bigger .text-input {
height: 100px;
}
.text-input input {
height: 100%;
}
<div class="conversation">
<div class="messages">
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is the last message
</p>
<div class="text-input">
<input type="text" />
</div>
</div>
</div>
당신은 글을 쓴다;
Now, consider this case:
The user scrolls to the bottom of the conversation
The .text-input, dynamically gets bigger
.text-input을 동적으로 설정하는 방법은 this.props.onResize()를 실행하는 논리적인 장소가 되지 않을까요?
관련되시는 분께,
위의 답변으로는 내 질문이 충분하지 않았다.
내가 찾은 해결책은 내 이너폭과 이너폭을 만드는 것이다.높이 변수 상수 - 스크롤 막대에 적응하기 위해 스크롤 시 브라우저의 innerWidth가 변경됩니다.
var innerWidth = window.innerWidth
var innerHeight = window.innerHeight
OR FOR REACT
this.setState({width: window.innerWidth, height: window.innerHeight})
즉, 이를 무시하려면 스크롤하지 않는 것처럼 모든 것을 일정하게 만들어야 합니다.크기 조정/방향 변경 시 업데이트해야 합니다!
오스카
IMHO의 현재 답변은 정답이 아닙니다: 1/flex-direction: column-reverse; 메시지 순서를 거꾸로 합니다.원하지 않았습니다.2/ javascript도 약간 해킹적이고 쓸모없는 것이 있습니다.
속성을 가진 스페이서 상자를 사용하여 PRO와 동일하게 만들려면 다음 절차를 따릅니다.
flex-grow: 1;
flex-basis: 0;
는 메시지 위에 있습니다.채팅 입력으로 이동합니다.사용자가 새 메시지를 입력하고 입력 높이가 증가하면 스크롤 막대가 위로 이동하지만 메시지가 전송되면(입력 클리어), 스크롤 막대는 다시 맨 아래로 돌아갑니다.
내 스니펫을 확인합니다.
body {
background: #ccc;
}
.chat {
display: flex;
flex-direction: column;
width: 300px;
max-height: 300px;
max-width: 90%;
background: #fff;
}
.spacer-box {
flex-basis: 0;
flex-grow: 1;
}
.messages {
display: flex;
flex-direction: column;
overflow-y: auto;
flex-grow: 1;
padding: 24px 24px 4px;
}
.footer {
padding: 4px 24px 24px;
}
#chat-input {
width: 100%;
max-height: 100px;
overflow-y: auto;
border: 1px solid pink;
outline: none;
user-select: text;
white-space: pre-wrap;
overflow-wrap: break-word;
}
<div class="chat">
<div class="messages">
<div class="spacer-box"></div>
<div class="message">1</div>
<div class="message">2</div>
<div class="message">3</div>
<div class="message">4</div>
<div class="message">5</div>
<div class="message">6</div>
<div class="message">7</div>
<div class="message">8</div>
<div class="message">9</div>
<div class="message">10</div>
<div class="message">11</div>
<div class="message">12</div>
<div class="message">13</div>
<div class="message">14</div>
<div class="message">15</div>
<div class="message">16</div>
<div class="message">17</div>
<div class="message">18</div>
</div>
<div class="footer">
<div contenteditable role="textbox" id="chat-input"></div>
</div>
<div>
도움이 될 수 있으면 좋겠는데:)
언급URL : https://stackoverflow.com/questions/34213227/scrollable-div-to-stick-to-bottom-when-outer-div-changes-in-size
'programing' 카테고리의 다른 글
트위터 공유 URL의 get_the_title() 인코딩 (0) | 2023.03.23 |
---|---|
각도 지시어에 변수 전달 (0) | 2023.03.23 |
잭슨과 열거를 역직렬화하는 중 (0) | 2023.03.23 |
Postgre가 소개한 JSONB 설명SQL (0) | 2023.03.23 |
시도된 가져오기 오류: 'Switch'가 'react-router-dom'에서 내보내지지 않았습니다. (0) | 2023.03.23 |