我正在创建一个消息应用程序,当向数组中添加新消息时,我在滚动到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();
}