🧩 问题背景
在项目中使用 <el-link> 实现页面内锚点导航,点击后希望滚动到对应内容区域,但发现:
- 页面地址栏自动更新为
#bypass、#risk等; - 虽然实现了跳转效果,但 URL 的 hash 部分被修改;
- 影响用户体验(如刷新页面会回到锚点位置)、SEO 或与其他路由逻辑冲突。
🔍 问题定位
原始代码(存在缺陷)
<el-link
v-for="(item, i) in anchors"
:key="i"
class="anchor-item"
:class="item.choose ? 'anchor-item-click' : ''"
@click="anchorsClick(item)"
:underline="false"
:title="item.name"
:href="`#${item.anchor}`"
>
{{ item.name }}
</el-link>
❌ 为什么会导致 URL 改变?
:href="#${item.anchor}"是原生 HTML 锚点行为;- 浏览器默认会执行
location.hash = '#bypass'; - 即使绑定了
@click,默认行为不会被阻止,除非显式阻止; - 导致地址栏变为
...#bypass,影响后续操作或状态管理。
✅ 解决方案
✅ 目标
- 点击链接后滚动到对应元素;
- 不改变浏览器地址栏中的 hash;
- 保持 UI 交互体验一致;
- 可选:支持当前项高亮(
choose状态控制);
✅ 修改方式
✅ 方法一:使用 @click.prevent + 移除 href(推荐)
最简洁、最可控的方式。
<el-link
v-for="(item, i) in anchors"
:key="i"
class="anchor-item"
:class="item.choose ? 'anchor-item-click' : ''"
@click.prevent="anchorsClick(item)"
:underline="false"
:title="item.name"
href="javascript:void(0)" <!-- 可选,防止警告 -->
>
{{ item.name }}
</el-link>
✅ 优点:
- 不触发浏览器锚点跳转;
- 完全由 JS 控制;
- 地址栏不变;
✅ 方法二:手动控制滚动逻辑
确保 anchorsClick 函数能正确滚动并更新状态:
const anchorsClick = (item) => {
const target = document.getElementById(item.anchor)
if (target) {
target.scrollIntoView({ behavior: 'smooth' })
// 更新当前选中状态(可选)
anchors.value.forEach(i => i.choose = false)
item.choose = true
}
}
✅ 数据结构示例
// 锚点数据
const anchors = ref([
{
name: "策略命中占比分析",
anchor: "bypass",
chartShow: false,
choose: true,
},
{
name: "平均风险值区间占比分析",
anchor: "risk",
chartShow: false,
choose: false,
},
{
name: "分值区间占比分析",
anchor: "pie",
chartShow: false,
choose: false,
},
{
name: "规则命中率分析",
anchor: "table",
chartShow: false,
choose: false,
}
])
✅ 对应 DOM 元素需有
id="bypass"、id="risk"等。
🧱 最终完整示例
<template>
<div class="model-container">
<el-link
v-for="(item, i) in anchors"
:key="i"
class="anchor-item"
:class="item.choose ? 'anchor-item-click' : ''"
@click.prevent="anchorsClick(item)"
:underline="false"
:title="item.name"
href="javascript:void(0)"
>
{{ item.name }}
</el-link>
</div>
<!-- 示例内容 -->
<div id="bypass" class="chart-box">
<div class="chart-title">策略命中占比分析</div>
<!-- 图表内容 -->
</div>
<div id="risk" class="chart-box">
<div class="chart-title">平均风险值区间占比分析</div>
</div>
<!-- 其他图表 -->
</template>
<script setup>
import { ref } from 'vue'
const anchors = ref([
{
name: "策略命中占比分析",
anchor: "bypass",
chartShow: false,
choose: true,
},
{
name: "平均风险值区间占比分析",
anchor: "risk",
chartShow: false,
choose: false,
},
{
name: "分值区间占比分析",
anchor: "pie",
chartShow: false,
choose: false,
},
{
name: "规则命中率分析",
anchor: "table",
chartShow: false,
choose: false,
}
])
const anchorsClick = (item) => {
const target = document.getElementById(item.anchor)
if (target) {
target.scrollIntoView({ behavior: 'smooth' })
// 更新选择状态
anchors.value.forEach(i => i.choose = false)
item.choose = true
}
}
</script>
💡 小贴士
| 问题 | 建议 |
|---|---|
是否需要 href? |
不需要时直接去掉,或设为 javascript:void(0) |
| 是否要支持键盘导航? | 可加 tabindex="0" 和 @keydown.enter |
| 是否要支持无障碍? | 保留 aria-label 或 title 提供语义 |
| 是否要支持动态锚点? | 可将 anchor 设为计算属性或响应式 |
✅ 总结
| 关键点 | 实现方式 |
|---|---|
| ❌ 避免 URL 改变 | 使用 @click.prevent |
| ✅ 滚动到目标 | element.scrollIntoView({behavior: 'smooth'}) |
| ✅ 控制样式 | 通过 choose 字段绑定类名 |
| ✅ 保持交互 | 使用 el-link 自定义样式和事件 |
✅ 结论 :
不要依赖href="#xxx"实现锚点跳转 ,而是通过@click.prevent+ 手动滚动来完全控制行为,避免副作用。
📌 附注 :若未来需要支持 el-anchor 的自动激活功能,可考虑使用 el-anchor-link 并自定义 active-name,但需注意其仍可能受 hash 影响。本方案更适合"无副作用"的场景。