在 Vue Compostion API 中使用 querySelector()

Ala*_*lan 8 vue.js vuejs3 vue-composition-api

我是 Vue Composition API 的新手,需要使用document.querySelector. 但是,它并没有按预期工作。如果我写

<nav class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed">

<script setup>
import { ref } from "vue";
const observer = new IntersectionObserver(handleIntersection);
const target = document.querySelector(".home-menu");
observer.observe(target);
console.log(target);
Run Code Online (Sandbox Code Playgroud)

targetnull。阅读文档,我看到了该ref属性,如果我

<nav ref="navbar" class="home-menu pure-menu pure-menu-horizontal pure-menu-fixed">
<script setup>
import { ref } from "vue";

const target = ref("navbar");
console.log(target);
Run Code Online (Sandbox Code Playgroud)

记录一个对象。

ref在 Composition API 中获取 DOM 元素的方式吗?
我现在可以target在我的观察者对象中使用吗?
它相当于吗querySelector

我试过

import { ref } from "vue";
const observer = new IntersectionObserver(handleIntersection);

const target = ref("navbar");
observer.observe(target);
Run Code Online (Sandbox Code Playgroud)

但得到这个错误:

未捕获类型错误:IntersectionObserver.observe:参数 1 未实现接口 Element。

Dar*_*kes 14

document.querySelector返回的原因null是 DOM 还不包含该元素。该script setup函数在组件创建时运行,因此组件的 DOM 尚未创建。

您可以使用onMounted生命周期挂钩在组件安装后运行代码。我创建了一个游乐场来演示这一点。

来自生命周期文档

例如,onMounted钩子可用于在组件完成初始渲染并创建 DOM 节点后运行代码

那么有两种方法可以实现你想要的。您可以使用继续使用querySelector,也可以使用模板引用。就我个人而言,我将模板引用用于静态元素(例如导航栏等)和querySelector动态选择。

使用模板引用

模板引用是常规的 Vue 引用,但通过属性将其连接到元素或子组件,ref您可以获得对该元素或组件的直接引用。
如果将其连接到一个元素,则该值将是该元素;如果将其连接到子组件,则该值将是该组件的组件实例;如果没有任何东西与之连接,则该值为null

脚步

  • 创建一个参考:

    const navbar = ref(null);
    
    Run Code Online (Sandbox Code Playgroud)

    这将用于引用该元素。

  • 通过将元素上的属性设置ref为用于模板引用的名称,将模板引用连接到元素:

    <nav ref="navbar" ...>
    
    Run Code Online (Sandbox Code Playgroud)

    解释模板参考文档:
    ref是一个特殊属性。它允许我们在安装后获取对特定 DOM 元素或子组件实例的直接引用。

  • 安装组件时连接观察者:

    onMounted(() => {
      observer.observe(navbar.value);
    })
    
    Run Code Online (Sandbox Code Playgroud)

    再次解释一下文档:请注意,您只能在安装组件后
    才能访问 ref 。如果您在此之前尝试访问,则会出现. 这是因为该元素直到第一次渲染后才存在!navbarnull

  • 或者(见下文),在卸载组件时断开观察者的连接:

    onBeforeUnmount(() => {
      observer.disconnect();
    })
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,我认为这在技术上没有必要,因为当组件被销毁时,观察者应该被垃圾收集。
    你可以摆弄我在 SFC Playground 中做的这个实验,尝试创建内存泄漏。

代码示例

<script setup>
import { ref, onMounted, onUnmounted } from "vue";

const el = ref(null);

const observer = new IntersectionObserver((entries, observer) => {
  console.log(entries)
});

onMounted(() => {
  observer.observe(el.value)
})

// Probably optional
onUnmounted(() => {
  observer.disconnect()
})
</script>

<template>
  <div ref="el">
    I'm the target!
  </div>
</template>
Run Code Online (Sandbox Code Playgroud)

使用querySelector

或者,您仍然可以使用querySelector. 同样的生命周期注意事项也适用。

<nav class="home-menu ...">
Run Code Online (Sandbox Code Playgroud)
onMounted(() => {
  const target = document.querySelector(".home-menu");
  observer.observe(target);
})
Run Code Online (Sandbox Code Playgroud)

代码示例

<script setup>
import { onMounted, onUnmounted } from "vue";

const observer = new IntersectionObserver((entries, observer) => {
  console.log(entries)
});

onMounted(() => {
  const target = document.querySelector(".target");
  observer.observe(target);
})

// Probably optional
onUnmounted(() => {
  observer.disconnect()
})
</script>

<template>
  <div class="target">
    I'm the target!
  </div>
</template>
Run Code Online (Sandbox Code Playgroud)

其他文档

这是生命周期文档中的图表:

Vue 生命周期图

旁注

console.log(target)记录对象的原因是因为 Vue ref一个对象。实际值是通过value属性访问的。
这样做的技术原因是,Vue 可以检测何时访问该属性,并发挥其反应魔法;包括完全重新分配值的情况。


ste*_*206 5

您可以使用该ref方法,调用与模板中声明的 ref 同名的变量:

const navbar = ref(null);
Run Code Online (Sandbox Code Playgroud)

但是,您应该等待组件安装后才能观察到:

onMounted(() => {
  observer.observe(target);
})
Run Code Online (Sandbox Code Playgroud)

卸载组件时还记得断开连接:

onBeforeUnmount(() => {
  observer.disconnect();
})
Run Code Online (Sandbox Code Playgroud)