当外部div的大小发生变化时,可滚动的div可以坚持到底部

Ste*_*ili 36 javascript css css3 flexbox reactjs

这是一个示例聊天应用程序 - >

这里的想法是.messages-container尽可能多地占用屏幕.在其中.messages-container,.scroll保存消息列表,如果有更多消息,则屏幕大小滚动.

现在,考虑这种情况:

  1. 用户滚动到对话的底部
  2. .text-input,动态地变大

现在,不是用户保持滚动到对话的底部,文本输入增加,他们不再看到底部.

一种解决方法,如果我们使用react,计算文本输入的高度,如果有任何变化,让.messages-container知道

componentDidUpdate() {
  window.setTimeout(_ => {
    const newHeight = this.calcHeight();
    if (newHeight !== this._oldHeight) {
      this.props.onResize();
    }
    this._oldHeight = newHeight;
  });
}
Run Code Online (Sandbox Code Playgroud)

但是,这会导致可见的性能问题,并且像这样传递消息很难过.

有没有更好的办法?我可以用这种方式使用css来表达当.text-input-increase增加时,我想要基本上shift up所有的.messages-container

LGS*_*Son 21

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%; }
Run Code Online (Sandbox Code Playgroud)

缺点flex-direction: column-reverse;是IE/Edge/Firefox中的一个错误,滚动条没有显示,你可以在这里阅读更多信息:Firefox/IE中的Flexbox列反转和溢出

好处是你在移动设备/平板电脑上有大约90%的浏览器支持,在桌面上有大约65%的浏览器支持,并且随着bug的修复而计算......并且有一个解决方法.

// 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));
}
Run Code Online (Sandbox Code Playgroud)

在下面的代码片段中,我添加了上面的2个函数,以使IE/Edge/Firefox以相同的方式运行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));
}
Run Code Online (Sandbox Code Playgroud)
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 */
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


附注1:检测方法未经过全面测试,但它应适用于较新的浏览器.

附注2:为聊天输入附加调整大小事件处理程序可能比调用updateScroll函数更有效.

注意:对HaZardouS重用其html结构的信用


Doc*_*cto 11

您只需要一个CSS规则集:

.messages-container, .scroll {transform: scale(1,-1);}
Run Code Online (Sandbox Code Playgroud)

就是这样,你完成了!这将使对话滚动到底部,最后一条消息在视图中,无论是否调整容器,输入框或其他任何内容.它适用于所有现代浏览器.

工作原理:首先,它垂直翻转外部__CODE__元素(处理滚动),使顶部成为底部.然后它翻转内部__CODE__元素,这样消息就不会颠倒.

这种方法确实有一个奇怪的副作用:当您在消息框中使用鼠标滚轮(或模拟一个鼠标滚轮的东西)时,滚动方向相反.如果这让您感到烦恼,可以使用JavaScript修复它(如下所示).

这是一个演示和一个jsfiddle玩:

//Reverse wheel direction
document.querySelector('.messages-container').addEventListener('wheel', function(e) {
  if(e.deltaY) {
    e.preventDefault();
    e.currentTarget.scrollTop -= parseFloat(getComputedStyle(e.currentTarget).getPropertyValue('font-size')) * (e.deltaY < 0 ? -1 : 1) * 2;
  }
});

//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%';
}
Run Code Online (Sandbox Code Playgroud)
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;}
Run Code Online (Sandbox Code Playgroud)
<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
    </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>
Run Code Online (Sandbox Code Playgroud)