在Vue Composition API中使用querySelector()

jtw3ybtb  于 2023-06-24  发布在  Vue.js
关注(0)|答案(2)|浏览(260)

我是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);

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);

记录对象。
ref是在Composition API中获取DOM元素的方式吗?
我现在可以在观察对象中使用target了吗?
是否等同于querySelector
我尽力了

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

const target = ref("navbar");
observer.observe(target);

但是得到了这个错误:
未捕获的类型错误:IntersectionObserver.observe:参数% 1未实现接口Element。

js4nwp54

js4nwp541#

document.querySelector返回null的原因是DOM还不包含该元素。script setup在组件 * 创建 * 时运行,因此组件的DOM尚未创建。
您可以使用onMounted生命周期钩子在组件挂载后运行代码。我创建了一个Playground来演示这一点。
the Lifecycle docs
例如,onMounted钩子可用于在组件完成初始呈现并创建DOM节点之后运行代码

**然后有两种方法可以实现您想要的。**您可以使用继续使用querySelector,或者您可以使用template refs。就我个人而言,我对静态元素(如导航栏等)使用模板引用,对动态选择使用querySelector

使用模板引用

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

步骤

  • 创建参照:
const navbar = ref(null);

这将被用来指代元素。

  • 通过将元素上的ref属性设置为用于模板参照的名称,将模板参照连接到元素:
<nav ref="navbar" ...>

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

  • 安装元件时连接观察器:
onMounted(() => {
  observer.observe(navbar.value);
})

再次解释文档:
请注意,您只能在组件挂载后访问ref。如果您尝试在此之前访问navbar,则它将是null。这是因为元素直到第一次渲染之后才存在!

  • 或者(参见下文),在卸载组件时断开观察器:
onBeforeUnmount(() => {
  observer.disconnect();
})

注意,我不认为这在技术上是必要的,因为当组件被销毁时,观察者应该被垃圾收集。
您可以随意摆弄我在SFC操场上做的这个实验,试图创建一个内存泄漏。

代码示例

<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>

使用querySelector

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

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

代码示例

<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>

其他单据

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

旁注

console.log(target)记录对象的原因是Vue ref * 是 * 对象。实际值通过value属性访问。
这样做的技术原因是Vue可以检测到该属性何时被访问,并发挥其React性魔力;包括当它是值的完全重新分配时。

wribegjk

wribegjk2#

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

const navbar = ref(null);

但是,您应该等待组件被挂载以观察:

onMounted(() => {
  observer.observe(target);
})

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

onBeforeUnmount(() => {
  observer.disconnect();
})

相关问题