You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js中document.querySelector返回null但元素已存在问题求助

问题:document.querySelector(".primary-navigation")返回null的原因及解决办法

我在跟着Kevin Powell的教程制作响应式导航栏时遇到问题:代码中的const primary_nav = document.querySelector(".primary-navigation")返回null值,但该类名对应的元素确实存在于模板中,这是什么原因导致的?

相关代码

<script setup lang="ts">
import { useRouter } from 'vue-router';

const router = useRouter();

const navigations = [
    { path: '/about', name: 'About' },
    { path: '/register', name: 'Create account' },
    { path: '/login', name: 'Login' },
];

const primary_nav = document.querySelector(".primary-navigation");
console.log('primary_nav: ', primary_nav);


const nav_toggle = () => {
    const visibility = primary_nav?.getAttribute("data-visible");
    console.log('visibility: ', visibility);
}

</script>

<template>
    <header class="primary-header flex">

        <div>
            <img class="logo" src="src/assets/Missandei-Logo.png" />
        </div>
        <button @click="nav_toggle" class="mobile-nav-toggle display-none" aria-controls="primary-navigation"
            aria-expanded="false">
            <span class="sr-only">
                Menu
            </span>
        </button>

        <nav>
            <ul id="primary-navigation" data-visible="false" class="primary-navigation flex">
                <li class="active" v-for="(navigation, index) in navigations" :key="index">
                    <a>
                        <span aria-hidden="true">{{ index }}</span>{{ navigation.name }}
                    </a>
                </li>
            </ul>
        </nav>

    </header>
</template>

原因分析

核心问题是Vue组件的生命周期时机:<script setup>中的代码会在组件实例创建后、DOM节点挂载到页面之前执行。此时模板里的元素还未被渲染到真实DOM中,document.querySelector自然找不到目标元素,返回null。

解决办法

方法1:使用onMounted生命周期钩子

将获取DOM的逻辑放到onMounted钩子中,此时组件已完成挂载,DOM元素已存在:

<script setup lang="ts">
import { useRouter, onMounted } from 'vue';
const router = useRouter();

const navigations = [
    { path: '/about', name: 'About' },
    { path: '/register', name: 'Create account' },
    { path: '/login', name: 'Login' },
];

let primary_nav: HTMLElement | null = null;

onMounted(() => {
  primary_nav = document.querySelector(".primary-navigation");
  console.log('primary_nav: ', primary_nav);
});

const nav_toggle = () => {
    const visibility = primary_nav?.getAttribute("data-visible");
    console.log('visibility: ', visibility);
}
</script>

方法2:使用Vue模板引用(推荐)

这是Vue官方推荐的操作DOM方式,更契合Vue的响应式机制:

<script setup lang="ts">
import { useRouter, ref } from 'vue';
const router = useRouter();

const navigations = [
    { path: '/about', name: 'About' },
    { path: '/register', name: 'Create account' },
    { path: '/login', name: 'Login' },
];

const primaryNavRef = ref<HTMLElement | null>(null);

const nav_toggle = () => {
    const visibility = primaryNavRef.value?.getAttribute("data-visible");
    console.log('visibility: ', visibility);
}
</script>

<template>
    <header class="primary-header flex">
        <div>
            <img class="logo" src="src/assets/Missandei-Logo.png" />
        </div>
        <button @click="nav_toggle" class="mobile-nav-toggle display-none" aria-controls="primary-navigation"
            aria-expanded="false">
            <span class="sr-only">Menu</span>
        </button>
        <nav>
            <!-- 给ul添加ref属性关联脚本中的变量 -->
            <ul ref="primaryNavRef" id="primary-navigation" data-visible="false" class="primary-navigation flex">
                <li class="active" v-for="(navigation, index) in navigations" :key="index">
                    <a>
                        <span aria-hidden="true">{{ index }}</span>{{ navigation.name }}
                    </a>
                </li>
            </ul>
        </nav>
    </header>
</template>

内容的提问来源于stack exchange,提问作者Gabby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 01:27:40