Vue Hash 路由与锚点导航区别及Hash路由下锚点导航的解决方式
Hash 路由用#标识页面改变的是「你要看哪一页」锚点导航用#标识位置改变的是「你要滚到哪里」Hash 路由 https://example.com/#/about ↑ 这是路由路径决定加载哪个组件 锚点导航 https://example.com/page.html#section-2 ↑ 这是页面内位置决定滚动到哪里两者看起来都用了#但背后的机制完全不同Hash 路由锚点导航作用模拟多页面切换视图组件同一页面内定位到某个元素#后面是什么路由路径/about、/user/1元素 IDsection-1、top谁在管理Vue Router 接管浏览器原生行为页面是否刷新否只替换组件否只是滚动URL 变化方式router.push()/router-linklocation.hash/a[href]/scrollIntoView监听机制hashchange事件被 Vue Router 拦截hashchange事件浏览器默认处理各自的工作原理Hash 路由用户点击 router-link → 路由匹配 → 加载对应组件 → 渲染到 router-view URL: /#/home → /#/about → /#/user/42 ↓ ↓ ↓ Home组件 About组件 User组件(42)// Vue Router 内部做的事简化 window.addEventListener(hashchange, () { // 解析 hash 里的路径/#/about → /about // 匹配路由表 // 渲染对应组件 })锚点导航用户点击 a href#section-2 → 浏览器查找 idsection-2 的元素 → 滚动过去 页面 DOM: div idsection-1.../div div idsection-2.../div ← 滚到这里 div idsection-3.../div// 浏览器原生行为没有任何框架参与 // 点击 a href#section-2 时 // 1. URL 变成 当前页面#section-2 // 2. 滚动到 idsection-2 的元素hash路由与锚点导航冲突在 Vue Hash 路由的应用中浏览器默认的锚点行为被 Vue Router 打破了!-- 你的 Vue 应用 -- a href#section-1跳到第一节/a !-- 你以为会发生的事 -- !-- ✅ 滚动到 idsection-1 的元素 -- !-- 实际发生的事 -- !-- ❌ Vue Router 把 #section-1 当成路由去匹配 -- !-- ❌ 路由表里没有 /section-1 这条规则 -- !-- ❌ 可能跳到 404 或者首页页面不会滚动 --根本原因Vue Router 启动后会劫持所有hashchange事件#后面的任何内容都会被当成路由路径解析浏览器的原生锚点滚动行为就失效了。如何让两者共存// router/index.js const router createRouter({ history: createWebHashHistory(), routes: [...], scrollBehavior(to, from, savedPosition) { // Vue Router 把路由的 # 和锚点的 # 统一放到 to.hash 里 // to.path → 路由路径 // to.hash → 锚点部分 if (to.hash) { return { el: to.hash, behavior: smooth, top: 80, } } return { top: 0 } }, })此时的URL拆解 https://example.com/#/docs#install Vue Router 解析为 ┌─────────────────────────────┐ │ to.path /docs │ → 加载 Docs 组件 │ to.hash #install │ → 滚动到 #install └─────────────────────────────┘template !-- 跨页面 锚点先路由跳转再滚动 -- router-link to/docs#install安装指南/router-link !-- 同页面锚点不涉及路由切换 -- router-link to/#features功能介绍/router-link /templateHash 路由 → 管「去哪一页」→ 切组件锚点导航 → 管「去哪个位置」→ 滚页面两者共用 # → 冲突 → 用 scrollBehavior 解决具体解决方案如下方案一scrollBehavior同页面 跨页面通用这是 Vue Router官方推荐的处理方式// router/index.js import { createRouter, createWebHashHistory } from vue-router const router createRouter({ history: createWebHashHistory(), routes: [ { path: /, component: () import(/views/Home.vue) }, { path: /about, component: () import(/views/About.vue) }, { path: /docs, component: () import(/views/Docs.vue) }, ], scrollBehavior(to, from, savedPosition) { // ① 有锚点 → 滚动到目标元素 if (to.hash) { return new Promise((resolve) { // 等待页面异步组件加载完成 setTimeout(() { resolve({ el: to.hash, // CSS 选择器如 #section-1 behavior: smooth, top: 80, // 偏移固定导航栏高度 }) }, 300) // 给异步组件加载留时间 }) } // ② 浏览器前进/后退 → 恢复上次滚动位置 if (savedPosition) { return savedPosition } // ③ 默认滚到顶部 return { top: 0, behavior: smooth } }, }) export default router模板写法template nav !-- 同页面锚点 -- router-link to/#intro简介/router-link router-link to/#features功能/router-link !-- 跨页面锚点 -- router-link to/about#team关于我们 - 团队/router-link router-link to/docs#install文档 - 安装/router-link /nav /template方案二同页面编程式导航更精细的控制同一个页面内的锚点跳转不涉及路由切换template div classpage nav classsidebar a v-fornav in navList :keynav.id :class[nav-item, { active: current nav.id }] clickgoTo(nav.id) {{ nav.label }} /a /nav main classcontent section v-fornav in navList :keynav.id :idnav.id classsection h2{{ nav.label }}/h2 p{{ nav.content }}/p /section /main /div /template script setup import { ref, onMounted, onUnmounted } from vue const navList [ { id: intro, label: 简介, content: ... }, { id: features, label: 功能, content: ... }, { id: pricing, label: 定价, content: ... }, { id: faq, label: 常见问题, content: ... }, ] const current ref(intro) // ---- 点击跳转 ---- function goTo(id) { const el document.getElementById(id) if (!el) return const offset 80 // 固定头部高度 const top el.getBoundingClientRect().top window.scrollY - offset window.scrollTo({ top, behavior: smooth }) // 手动同步更新 URL 的 hash但不触发路由跳转 history.replaceState(null, , #${id}) } // ---- 滚动监听自动高亮 ---- let ticking false function onScroll() { if (ticking) return ticking true requestAnimationFrame(() { const offset 120 for (let i navList.length - 1; i 0; i--) { const el document.getElementById(navList[i].id) if (el el.getBoundingClientRect().top offset) { current.value navList[i].id break } } ticking false }) } onMounted(() window.addEventListener(scroll, onScroll, { passive: true })) onUnmounted(() window.removeEventListener(scroll, onScroll)) /script style scoped .nav-item.active { color: var(--accent); font-weight: 600; } .section { scroll-margin-top: 80px; /* CSS 原生偏移兜底 */ min-height: 60vh; padding: 2rem 0; } /style方案三自定义指令复用场景多个页面都需要锚点导航时封装成指令// directives/anchor.js export const vAnchor { mounted(el, binding) { el.style.cursor pointer el.addEventListener(click, (e) { e.preventDefault() const targetId binding.value const target document.getElementById(targetId) if (!target) return target.scrollIntoView({ behavior: smooth, block: start }) // 用 replaceState 不触发 popstate history.replaceState(null, , #${targetId}) }) }, }// main.js import { vAnchor } from ./directives/anchor app.directive(anchor, vAnchor)template nav a v-anchorintro简介/a a v-anchorfeatures功能/a a v-anchorpricing定价/a /nav /template常见坑和解法坑 1固定导航栏遮挡目标区域/* 最优雅的解法CSS scroll-margin-top */ [id] { scroll-margin-top: 80px; }// JS 兼容方案 function scrollToWithOffset(id, offset 80) { const el document.getElementById(id) if (!el) return const y el.getBoundingClientRect().top window.scrollY - offset window.scrollTo({ top: y, behavior: smooth }) }坑 2scrollBehavior中元素还没渲染异步组件或数据驱动的页面目标元素可能还没挂载scrollBehavior(to) { if (to.hash) { return new Promise((resolve) { // 轮询等待目标元素出现 const tryScroll (retries 10) { const el document.querySelector(to.hash) if (el) { resolve({ el: to.hash, behavior: smooth, top: 80 }) } else if (retries 0) { setTimeout(() tryScroll(retries - 1), 100) } else { resolve({ top: 0 }) // 兜底 } } tryScroll() }) } return { top: 0 } }坑 3滚动监听与 Vue Router 导航冲突// 在滚动监听中避免在路由跳转过程中误触发 import { useRouter } from vue-router const router useRouter() const isNavigating ref(false) router.beforeEach(() { isNavigating.value true }) router.afterEach(() { setTimeout(() { isNavigating.value false }, 500) }) function onScroll() { if (isNavigating.value) return // 路由跳转期间不处理 // ... 正常的高亮逻辑 }

相关新闻

Agent-S3终极指南:首个超越人类性能的智能体框架深度解析

Agent-S3终极指南:首个超越人类性能的智能体框架深度解析

Agent-S3终极指南:首个超越人类性能的智能体框架深度解析 【免费下载链接】Agent-S Agent S: an open agentic framework that uses computers like a human 项目地址: https://gitcode.com/GitHub_Trending/ag/Agent-S 在计算机自动化领域,传统脚…

2026/10/6 5:24:22 阅读更多 →
uniapp 实现 骨架屏组件- u-skeleton

uniapp 实现 骨架屏组件- u-skeleton

u-skeleton UniApp 骨架屏组件 概览 什么是骨架屏 为什么需要骨架屏 组件特性 三种模式 插槽模式 遮罩模式 行列模式 模式决策流程 子组件 skeleton-item skeleton-text skeleton-avatar skeleton-image 参考 容器 Props 子组件 Props 动画说明 常见问题 …

2026/10/16 8:22:57 阅读更多 →
connect 断线重连

connect 断线重连

本篇核心内容:实现带自动断线重连功能的 TCP 客户端。 断线重连是线上长连接程序高频刚需,大家日常打游戏时就能直观感受到:本地网络波动、服务器崩溃、网络完全中断,游戏客户端都会自动重试连接;达到最大重试次数后&…

2026/9/26 11:26:03 阅读更多 →

最新新闻

PyTorch集成TensorBoard可视化实战指南

PyTorch集成TensorBoard可视化实战指南

1. 项目概述:为什么PyTorch用户现在必须掌握TensorBoard可视化 “PyTorch使用TensorBoard做可视化”——这八个字背后,不是一句轻飘飘的教程标题,而是一条横跨模型调试、团队协作、教学复现和工程落地的实操生命线。我带过三届某高校AI实验室…

2026/10/16 14:11:14 阅读更多 →
DeepSeek提示词实战指南:50个场景化指令提升AI写作与代码效率

DeepSeek提示词实战指南:50个场景化指令提升AI写作与代码效率

简介:这份PDF资源是一份面向DeepSeek及同类大语言模型工具的高阶提示词合集,聚焦职场办公、自媒体创作、电商运营、程序员开发、副业探索与个人成长等场景,精选50个可直接复制的实用指令,既能帮助新手掌握提问方式,也能…

2026/10/16 14:11:14 阅读更多 →
CTF逆向入门:静态分析、动态调试与Z3求解全流程

CTF逆向入门:静态分析、动态调试与Z3求解全流程

1. 项目概述:一道逆向题的完整解题路径,远不止“拖进IDA看一眼”那么简单 “moeCTF题解-0x01】Reverse”这个标题看似简单,实则浓缩了一个典型CTF逆向赛题的全部信息量。它不是某款商业软件的破解教程,也不是系统级漏洞分析&#…

2026/10/16 14:11:14 阅读更多 →
browser-use全家桶成形:操作完浏览器再操作视频,Agent的下一个接管对象是?

browser-use全家桶成形:操作完浏览器再操作视频,Agent的下一个接管对象是?

browser-use全家桶成形:操作完浏览器再操作视频,Agent的下一个接管对象是? 【免费下载链接】video-use Edit videos with coding agents 项目地址: https://gitcode.com/GitHub_Trending/vid/video-use 过去一年,AI Agent …

2026/10/16 14:11:14 阅读更多 →
DotNetBar2源码编译实战:从环境还原到控件定制

DotNetBar2源码编译实战:从环境还原到控件定制

简介:DevComponents.DotNetBar2是一套成熟的.NET界面控件库,专为Windows Forms与WPF桌面程序而设计,提供工具栏、菜单、Ribbon、气泡栏等多种复合组件,帮助开发者快速实现Office风格的现代界面,适合企业级项目或需要深…

2026/10/16 14:11:14 阅读更多 →
llama.cpp与GGUF:本地大模型推理的裸引擎实战指南

llama.cpp与GGUF:本地大模型推理的裸引擎实战指南

1. 为什么“裸引擎”这个说法值得认真对待很多人第一次接触本地大模型,脑子里想的都是“下载一个模型文件,双击运行,然后就能对话”。真上手之后才发现,事情远没有这么简单:模型文件有好几种格式,推理框架有…

2026/10/16 14:10:12 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →