无论是选项式 API 还是组合式 API 我们能可以通过 Ref 来拿到元素或组件的引用。

    1. <template>
    2. <div ref="divRef">Hello Vue3!</div>
    3. <Child ref="childRef" />
    4. </template>
    5. <script>
    6. import { ref, onMounted } from "vue";
    7. import Child from "./components/Child.vue";
    8. export default {
    9. components: {
    10. Child
    11. },
    12. setup() {
    13. const divRef = ref(null);
    14. const childRef = ref(null);
    15. console.log(divRef);
    16. console.log(divRef.value);
    17. console.log(childRef.value);
    18. return {
    19. divRef,
    20. childRef
    21. };
    22. }
    23. };
    24. </script>
    25. <style lang="scss" scoped></style>

    image.png :::warning ⚠️ 注意
    我们在代码中分别打印了divRefdivRef.value,从图中可以看到我们明明拿到了div元素对象。
    这其实是因为我们在控制台点击三角形的时候会触发 getter 机制,此时我们的程序已经跑完,你再去 getter 肯定能拿到div元素。 :::

    通常情况下,我们操作一个响应式数据是很正常的操作:

    1. <template>
    2. <div class="">This is Child component!</div>
    3. <h1 ref="h1Ref">{{ state.title }}</h1>
    4. <button @click="setTitle">Set title</button>
    5. </template>
    6. <script>
    7. import { ref, reactive, nextTick } from "vue";
    8. export default {
    9. setup() {
    10. const h1Ref = ref(null);
    11. const state = reactive({
    12. title: "This is title."
    13. });
    14. const setTitle = () => {
    15. state.title = "这是标题.";
    16. };
    17. return {
    18. h1Ref,
    19. state,
    20. setTitle
    21. };
    22. }
    23. };
    24. </script>
    25. <style lang="scss" scoped></style>

    image.pngimage.png
    以上代码,当你点击按钮的时候会更改state.title的值,相应的页面视图也会进行更新。

    某些情况下,我们可能需要更改完数据后立马获取元素:

    1. const setTitle = () => {
    2. state.title = "这是标题.";
    3. console.log(h1Ref.value);
    4. };

    这时,你会发现获取的 DOM 引用的值还是 This is title.
    这是怎么回事呢?下面是 Vue 文档的原话

    当你更改响应式状态后,DOM 会自动更新。然而,你得注意 DOM 的更新并不是同步的。相反,Vue 将缓冲它们直到更新周期的 “下个时机” 以确保无论你进行了多少次状态更改,每个组件都只更新一次。

    上面这段话的意思是:当数据状态更改后,DOM 是不会立马执行的,DOM 的更新是非同步的,Vue 会把 DOM 更新的任务缓存到一个队列中进行等待,当数据状态全部更改完成后再一次性的更新 DOM。

    而如果你想拿到 DOM 更新后的内容,你可以使用 Vue 提供的nextTick()方法:

    1. const setTitle = () => {
    2. state.title = "这是标题.";
    3. nextTick(() => {
    4. console.log(h1Ref.value);
    5. });
    6. };

    nextTick()方法会在状态变更后立即执行,但是回调方法却是在 DOM 更新后才执行!!!

    另外,nextTick()返回的是一个 Promise:

    1. const setTitle = () => {
    2. state.title = "这是标题.";
    3. const res = nextTick();
    4. console.log(res);
    5. };

    image.png

    所以我们可以使用await进行中止等待:

    1. const setTitle = async () => {
    2. state.title = "这是标题.";
    3. /* nextTick(() => {
    4. console.log(h1Ref.value);
    5. }); */
    6. // 也可以 await 执行
    7. await nextTick();
    8. console.log(h1Ref.value);
    9. };