Посмотрите исходные коды для v-chat-scroll , выделите строку # = 27, вы найдете if (pause || e[e.length - 1].addedNodes.length != 1) return;
Когда loader = true (v-if="loader"
),вы увидите e.length=2
и e[e.length - 1].addedNodes.length = 0
, что не соответствует ожиданиям.
Поэтому я использовал одно уменьшение, чтобы суммировать длину добавленных узлов для каждого MutationRecord , затем работает.
Vue.config.productionTip = false
// Below codes (scrollToBottom and vChatScroll) is copied from v-chat-scroll at github:
// https://github.com/theomessin/vue-chat-scroll/blob/master/src/directives/v-chat-scroll.js
const scrollToBottom = el => {
el.scrollTop = el.scrollHeight;
};
const vChatScroll = {
bind: (el, binding) => {
let timeout;
let scrolled = false;
el.addEventListener('scroll', e => {
if (timeout) window.clearTimeout(timeout);
timeout = window.setTimeout(function() {
scrolled = el.scrollTop + el.clientHeight + 1 < el.scrollHeight;
}, 200);
});
(new MutationObserver(e => {
let config = binding.value || {};
let pause = config.always === false && scrolled;
if (pause
||
e.reduce((pre, cur) => { // sum the length of each addedNodes
return pre+cur.addedNodes.length
}, 0) < 1 // if sum(addedNodes.length) === 0, do nothing.
) return;
scrollToBottom(el);
})).observe(el, {childList: true, subtree: true});
},
inserted: scrollToBottom
};
Vue.directive('chat-scroll', vChatScroll)
const str = [
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, similique sequi perspiciatis praesentium iure debitis explicabo animi reiciendis!",
"Error ipsa eaque officia tempore optio laborum porro illo, veritatis atque pariatur, vero voluptatem quos",
"At doloremque eveniet labore, eligendi dicta beatae earum aperiam et, recusandae perspiciatis perferendis corporis dolorum quidem dolores esse labore."
]
new Vue({
el: "#app",
data: {
messages: [],
loader: false
},
methods: {
addMessage() {
this.loader = true
setTimeout(() => {
this.loader = false
let randMsg = str[Math.floor(Math.random()*str.length)]
this.messages.push(randMsg)
}, 2000)
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Montserrat;
}
#app {
background: #D3F3F1;
position: relative;
border-radius: 4px;
height: 300px;
width: 350px;
}
.messages-container {
display: flex;
flex-direction: column;
overflow-y: auto;
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.message {
display: flex;
flex-direction: column;
flex-grow: 1;
flex-shrink: 1;
box-sizing: border-box;
overflow-x: hidden;
position: relative;
width: 100%;
}
.msg-box {
margin: 20px;
padding: 20px;
background-color: #fff;
border-radius: 8px;
}
.input-message {
position: relative;
bottom: 0;
background-color: white;
width: 100%;
height: 50px;
text-align: center;
flex-shrink: 0;
}
button {
margin-top: 10px;
border-radius: 4px;
background: #D3F3F1;
padding: 8px 15px;
border: none;
}
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<div id="app">
<div class="messages-container">
<div class="message" v-chat-scroll>
<div>
<div v-for="message in messages" class="msg-box">
{{ message }}
</div>
<!-- Loader don't scroll to bottom -->
<div v-if="loader" :class="loader ? 'msg-box' : ''">
>>super loader>>
</div>
</div>
</div>
<div class="input-message">
<button @click="addMessage">Add message</button>
</div>
</div>
</div>