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

如何在Vue.js单文件组件根元素显示(v-show切换后)时设置焦点

实现侧边导航的自动聚焦与失焦隐藏

我来帮你搞定这个需求,核心就是两个关键点:显示时自动聚焦侧边栏根元素,以及通过失焦事件判断是否隐藏侧边栏。下面分步骤给你详细说明:

1. 让侧边栏根div支持聚焦

div元素默认是不能被聚焦的,所以首先要给侧边栏的根div添加tabindex="-1"属性。这个值的作用是:允许通过JavaScript手动聚焦该元素,但不会让它被Tab键遍历到(避免影响页面的无障碍体验)。

同时,我们需要给这个div添加ref,方便后续在脚本中获取DOM元素:

<template>
  <div 
    v-show="isSideNavVisible"
    ref="sideNavRoot"
    tabindex="-1"
    @blur="handleSideNavBlur"
    class="side-nav"
  >
    <!-- 这里放你的侧边导航内容 -->
    <h3>导航菜单</h3>
    <ul>
      <li>菜单项1</li>
      <li>菜单项2</li>
    </ul>
  </div>
</template>

2. 监听Vuex状态变化,显示时自动聚焦

当Vuex中的显示标志变为true时,我们需要在DOM更新完成后(因为v-show是控制元素的display属性,需要等元素真正显示出来),调用focus()方法聚焦根div。

Vue3 版本(Composition API)

<script setup>
import { ref, watch, computed, nextTick } from 'vue'
import { useStore } from 'vuex'

const store = useStore()
const sideNavRoot = ref(null)

// 从Vuex获取侧边栏显示状态
const isSideNavVisible = computed(() => store.state.isSideNavVisible)

// 监听显示状态变化
watch(isSideNavVisible, (newVisibleState) => {
  if (newVisibleState) {
    // 用nextTick确保DOM已经更新完成,元素处于显示状态
    nextTick(() => {
      sideNavRoot.value?.focus()
    })
  }
})
</script>

Vue2 版本(Options API)

export default {
  computed: {
    isSideNavVisible() {
      return this.$store.state.isSideNavVisible
    }
  },
  watch: {
    isSideNavVisible(newVisibleState) {
      if (newVisibleState) {
        this.$nextTick(() => {
          this.$refs.sideNavRoot.focus()
        })
      }
    }
  }
}

3. 处理失焦事件,判断是否隐藏侧边栏

直接监听根div的blur事件会有一个问题:当你点击侧边栏内部的元素时,焦点会从根div转移到内部元素,这时候也会触发blur事件,但我们不希望此时隐藏侧边栏。

所以我们需要通过事件对象的relatedTarget属性,判断失焦后焦点是否还在侧边栏内部:

  • 如果relatedTarget是侧边栏的子元素,说明是内部切换焦点,不隐藏
  • 如果relatedTarget是外部元素或者null,说明点击了侧边栏外部,触发隐藏

继续完善脚本部分:

Vue3 补充handleSideNavBlur方法

const handleSideNavBlur = (e) => {
  // 检查失焦后的目标元素是否不在侧边栏内部
  if (!sideNavRoot.value?.contains(e.relatedTarget)) {
    // 提交Vuex mutation修改显示状态为false
    store.commit('SET_SIDE_NAV_VISIBLE', false)
  }
}

Vue2 补充handleSideNavBlur方法

methods: {
  handleSideNavBlur(e) {
    if (!this.$refs.sideNavRoot.contains(e.relatedTarget)) {
      this.$store.commit('SET_SIDE_NAV_VISIBLE', false)
    }
  }
}

最后:Vuex的mutation配置

别忘了在你的Vuex store中定义对应的mutation,用来修改显示状态:

// store/index.js
export default new Vuex.Store({
  state: {
    isSideNavVisible: false
  },
  mutations: {
    SET_SIDE_NAV_VISIBLE(state, payload) {
      state.isSideNavVisible = payload
    }
  }
})

注意事项

  • 如果你的侧边栏内部有需要用户手动聚焦的元素(比如输入框),可以根据需求调整聚焦逻辑,比如优先聚焦内部元素而不是根div
  • 可以给根div添加:focus-visible样式,让用户能看到当前焦点的位置(提升无障碍体验)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:21:46