nextTick()实现更新DOM后执行回调

nextTick()
是Vue.js中一个非常重要的方法,它的作用是延迟到下一个DOM更新周期后再执行,执行nextTick里的回调函数。在修改数据后,你立即使用这个方法,获取更新后的DOM。
当你在Vue组件中更改数据时,视图不会立刻更新,而是等到本轮事件循环结束时进行批量更新。如果你需要对更新后的视图做出操作的话,nextTick回调将会是你的绝佳方案。
打个比方,你放学回家后想吃鸡腿,在自己脑中写下了吃鸡腿的代码,但是妈妈还没将鸡腿蒸熟,如果你不使用nextTick回调吃鸡腿的代码,那么你就没有鸡腿可吃了,因为等鸡腿蒸熟后,你吃鸡腿的代码早已经跑过一遍了,大脑默认为你已经吃过了。👉🤣
下面再给出我在项目中碰到的问题:

  1. 问题描述:我要实现一个类似markdown编辑器的效果,当从preview切换到write视图后,会自动聚焦到输入框中,如下图所示。
    在这里插入图片描述

但是我尝试在点击write后执行我的toggleWriteBox函数,并不会自动聚焦至textarea中

………………
const writeBoxRef = ref(null)
function toggleWriteBox() {
    showWriteBox.value = true
    showPreviewBox.value = false
    if (writeBoxRef.value) {
        writeBoxRef.value.focus()
    }
}
………………
<textarea ref="writeBoxRef">

这是因为在点击write时,在DOM还未更新就执行了focus的代码,浏览器没有地方focus,于是使用nextTick()更改代码如下:

function toggleWriteBox() {
    showWriteBox.value = true
    showPreviewBox.value = false
    nextTick(() => {
        if (writeBoxRef.value) {
            writeBoxRef.value.focus()
        }
    })
}

随后,需求就完成了。
还有一个小细节,就是在浏览器更新时也应该自动聚焦,我们使用onMounted函数实现自动聚焦

onMounted(() => {
    if (showWriteBox.value) {
        writeBoxRef.value.focus()
    }
})

全部代码如下所示,可以自己试着玩玩(写的稍显笨拙,见谅):


<script setup>
import { marked } from 'marked'
import { ref, onMounted, nextTick } from 'vue'

const showWriteBox = ref(true)
const showPreviewBox = ref(false)
const writeBoxRef = ref(null)

function toggleWriteBox() {
    showWriteBox.value = true
    showPreviewBox.value = false
    nextTick(() => {
        if (writeBoxRef.value) {
            writeBoxRef.value.focus()
        }
    })
}

function togglePreviewBox() {
    showWriteBox.value = false
    showPreviewBox.value = true
}

onMounted(() => {
    if (showWriteBox.value) {
        writeBoxRef.value.focus()
    }
})
</script>

<template>
    <div class="container">
        <div class="header">
            <div class="ll-box"></div>
            <div class="left-box" :class="{ 'selected-box': showWriteBox, 'unselected-box': showPreviewBox }">
                <button class="left-button" @click="toggleWriteBox"
                    :class="{ 'selected-font': showPreviewBox }">write</button>
            </div>
            <div class="right-box" :class="{ 'selected-box': showPreviewBox, 'unselected-box': showWriteBox }">
                <button class="right-button" @click="togglePreviewBox"
                    :class="{ 'selected-font': showWriteBox }">preview</button>
            </div>
            <div class="rr-box"></div>
        </div>

        <div class="main">
            <textarea ref="writeBoxRef" v-if="showWriteBox" placeholder="Leave a comment" class="google-font write-box"
                cols="90" rows="20"></textarea>
            <div v-if="showPreviewBox" class="preview-box">preview-box</div>
        </div>

        <div class="footer google-font">Remember, contributions to this repository should follow our <a href="#">Github
                Community Guidelines.</a></div>
    </div>
</template>

<style scoped>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: space-between;
    background-color: #ffffff;
    border: 1px solid #d0d7de;
    border-radius: 6px;
    padding: 1rem;
    margin: 1rem;
    /* gap: 1rem; */
}

.header {
    width: 100%;
    height: 50px;
    display: flex;
    padding-bottom: 1rem;
}

.left-box {
    flex: 20%;
    background-color: #ffffff;
}

.right-box {
    flex: 20%;
    background-color: #ffffff;
}

.selected-font {
    color: #999999;
}

.selected-box {
    border: 1px solid #d0d7de;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
    border-bottom: none;
}

.unselected-box {
    border-bottom: 1px solid #d0d7de;
}

.write-box {
    outline: none;
    border: 1px solid #d0d7de;
}

.write-box:focus {
    border: 3px solid #218bff;
    border-radius: 6px;
}

.write-box:not(:focus) {
    background-color: #f6f8fa;
}

.preview-box {
    width: 500px;
    height: 200px;
    background-color: #fff;
}

.ll-box {
    flex: 2%;
    border-bottom: 1px solid #d0d7de;

}

.rr-box {
    flex: 60%;
    border-bottom: 1px solid #d0d7de;
}

.footer {
    font-size: small;
}

.google-font {
    font-family: Roboto, sans-serif;
}

button {
    border: none;
    background-color: transparent;
    outline: none;
}

button:hover {
    color: black;
}</style>
``

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值