nextTick()未触发DOM更新



我正在创建一个消息应用程序,当向数组中添加新消息时,我在滚动到ion-content元素的底部时遇到了一些问题。我使用ion-content附带的scrollToBottom()方法,并且在Vue 3中使用Composition API。

考虑一下这个片段:

setup(props) {
const replyContent = ref("")
const messages = ref([])
// References to ion-content in the template
const ionContent = ref(null)
const reply = async () => {
const message = await replyToThread(props.threadId, replyContent.value).then((message) => message)
messages.value.push(message)
nextTick(() => {
console.log("DOM updated!")
if (ionContent.value) {
ionContent.value.$el.scrollToBottom()
}
})
}
return { replyContent, messages, ionContent, reply }
}

replyToThread()执行API调用并返回新消息,nextTick()应确保DOM已更新,以便我可以使用它;DOM已更新&";,但是没有滚动到底部。

但是,每当nextTick()不这样做时,不知何故,当我用以下代码块替换nextTick()代码块时,它就完美地工作了:

setTimeout(() => {
if (ionContent.value) {
ionContent.value.$el.scrollToBottom()
}
}, 200)

我必须将超时时间设置在200毫秒左右,否则就无法工作。但是,当像nextTick()这样的花哨的东西应该起作用时,依赖它会让人觉得很肮脏。有人知道为什么会发生这种事吗?

这是因为nextTick()只保证实际的DOM已经更新:这并不意味着浏览器实际上已经完成了页面的布局。这就是为什么你需要一个任意的超时来确保滚动工作的原因,因为在200ms之后,浏览器很可能会根据更新的DOM进行布局。

要解决此问题,您可能需要依赖window.requestAnimationFrame:

nextTick(() => {
window.requestAnimationFrame(() => {
if (ionContent.value) {
ionContent.value.$el.scrollToBottom()
}
});    
});

如果这对你来说太多嵌套了,你可以创建一个基于rAF:返回promise的方法

methods: {
rAF: function() {
return new Promise(r => window.requestAnimationFrame(r));
}
}

然后是确保nextTick()rAF()返回的承诺在滚动之前得到解决的问题:

await nextTick();
await this.rAF();
if (ionContent.value) {
ionContent.value.$el.scrollToBottom();
}

最新更新