# 1. 在 setup 里拿到 ref 元素

App 为根组件 下面 Home 例子都被此组件引用

vue
// App.vue 
<template>
  <div>
    <home></home>
  </div>
</template>
<script>
import Home from "./Home.vue";
export default {
  components: {
    Home,
  },
};
</script>
<style scoped></style>
vue
// Home.vue
<template>
  <div>
    <h2 ref="title">哈哈哈</h2>
  </div>
</template>
<script>
import { ref } from "vue";
export default {
  setup() {
    const title = ref(null);
    // 这里打印会发现并不是绑定的元素,是因为元素还有没有挂载上去,现实的还是默认赋值的 null
    console.log(title.value);
    return {
      title,
    };
  },
};
</script>
<style scoped>
</style>

参考结果:

setup_refEl

# 2. 使用 watchEffect

vue
// Home.vue
<template>
  <div>
    <h2 ref="title">Nekoaimer</h2>
  </div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    const title = ref(null);
    watchEffect(() => {
      // 提问:为什么会先打印出 null 然后才是获取到的元素呢?
      console.log(title.value);
    });
    return {
      title,
    };
  },
};
</script>
<style scoped>
</style>

参考结果:

setup_watchEffect_refEl

# 3.watchEffect 中 flush 的使用

vue
// Home.vue
<template>
  <div>
    <h2 ref="title">Nekoaimer</h2>
  </div>
</template>
<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    const title = ref(null);
    //watchEffect 有两个参数,第一个是回调函数,第二个是一个对象:flush
    watchEffect(
      () => {
        console.log(title.value);
      },
      {
        flush: "post",
      }
    );
    return {
      title,
    };
  },
};
</script>
<style scoped>
</style>

参考结果:

setup_watchEffect_flush

# 4. 总结

  1. 为什么会打印两次不同的结果?
  • 首先应该了解 watchEffect 会默认执行一次,而第一次执行的时候元素还没有挂载上去,所以显示的默认赋的初始值 null
  • 其次等元素挂载上了之后,title 的数据必然会发生改变,那么就会触发 watchEffect 监听 。所以会再一次执行内部函数,打印出已经挂载好的元素!
  • watchEffect 有两个 参数,第一个是 回调函数,第二个是一个对象,里面有一个 flush 属性
  • flush 有三个值 :
    1. 默认为 pre(它会提前执行,不管 DOM 有没有挂载完)
    2. post:(等 DOM 挂载完或者更新完再执行)
    3. sync:强制同步 (官方不建议使用)