实现锚点定位功能(React/Vue)

前言

最近接到一个需求,修改某某页面,增加XXX功能,并实现个锚点功能。做产品就是不断优化,增加功能的过程。实现锚点的方式很多, 很多UI库也提供了组件,可以根据自己的需求调整一下组件库也可以实现,也可以用<a href="XX" /> 标签实现,还可以基于scrollIntoView api实现。

使用a标签

<a> 标签的 href 属性值以 # 开头,后面跟着目标元素的 id。点击链接时,浏览器会滚动到具有对应 id 的元素位置。

这种方式的优势在于不需要额外的 JavaScript 代码,但缺点是默认的滚动行为可能会比较突兀。如果需要更平滑的滚动效果,你可以使用 JavaScript 来自定义滚动行为,或者使用 CSS 属性 scroll-behavior: smooth

javascript 复制代码
import React from 'react';

function YourComponent() {
  return (
    <div>
      <a href="#anchor1">Go to Anchor 1</a>
      <div id="anchor1">Anchor 1 Content</div>

      <a href="#anchor2">Go to Anchor 2</a>
      <div id="anchor2">Anchor 2 Content</div>
    </div>
  );
}

export default YourComponent;

使用scrollIntoView

scrollIntoView 是一个用于滚动元素到可见区域的 JavaScript 方法。它是在 Element 接口中定义的。

使用方法

javascript 复制代码
element.scrollIntoView([options]);
  • options(可选)是一个包含滚动行为的对象,可以包括以下属性:
    • behavior: 定义滚动的过渡效果。可以是 "auto""smooth" 或者不指定。
    • block: 定义垂直方向上的对齐方式,可以是 "start""center""end" 或者 "nearest"
    • inline: 定义水平方向上的对齐方式,可以是 "start""center""end" 或者 "nearest"

示例

javascript 复制代码
const element = document.getElementById('myElement');

// 将元素滚动到可见区域,默认滚动行为
element.scrollIntoView();

// 平滑滚动到可见区域
element.scrollIntoView({ behavior: 'smooth' });

// 将元素滚动到可见区域,垂直方向上对齐到底部
element.scrollIntoView({ block: 'end' });

// 将元素滚动到可见区域,水平和垂直方向上对齐到中心
element.scrollIntoView({ block: 'center', inline: 'center' });

使用scrollIntoView实现锚点定位,以下是个简单例子,给目标元素设置了一个 id 属性为 "yourAnchorId",然后在 scrollToAnchor 函数中,通过 document.getElementById 获取目标元素,并使用 scrollIntoView 方法将页面滚动到该元素位置。

使用 id 属性的方式更为简单,但需要确保 id 是唯一的,不会重复在页面中出现。

js 复制代码
import React from 'react';

function YourComponent() {
  const scrollToAnchor = () => {
    const anchorElement = document.getElementById('yourAnchorId');

    if (anchorElement) {
      anchorElement.scrollIntoView({ behavior: 'smooth' });
    }
  };

  return (
    <div>
      <button onClick={scrollToAnchor}>Scroll to Anchor</button>
      <div id="yourAnchorId">This is the anchor content</div>
    </div>
  );
}

export default YourComponent;

封装useScrollIntoView

可能不止一个页面需要做这种锚点的功能,考虑到通用性,可以封装一个自定义 Hook useScrollIntoView。我这里是使用的React框架,下面是相应的实现:

javascript 复制代码
import { useRef, useEffect } from 'react';

function useScrollIntoView() {
  const targetRef = useRef(null);

  function scrollToTarget() {
    if (targetRef.current) {
      targetRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }

  useEffect(() => {
    // 在组件挂载后立即滚动到目标元素
    scrollToTarget();
  }, []);

  return {
    targetRef,
    scrollToTarget,
  };
}

export default useScrollIntoView;

然后, 在React 组件中使用这个 hook,如下所示:

js 复制代码
import React from 'react';
import useScrollIntoView from './useScrollIntoView'; // 请替换成实际的路径

function YourComponent() {
  const { targetRef: anchor1, scrollToTarget: scrollToAnchor1 } = useScrollIntoView();
  const { targetRef: anchor2, scrollToTarget: scrollToAnchor2 } = useScrollIntoView();

  return (
    <div>
      <div ref={anchor1}>Anchor 1</div>
      <div ref={anchor2}>Anchor 2</div>
      <button onClick={scrollToAnchor1}>Scroll to Anchor 1</button>
      <button onClick={scrollToAnchor2}>Scroll to Anchor 2</button>
    </div>
  );
}

export default YourComponent;

Vue中使用自定义指令

最近也在用vue,既然写到了,就想到也可以使用vue的自定义指令实现一个锚点功能。当然实现的方式多种多样,我这里就举个例子。

将自定义指令放在一个独立的文件中,然后在 main.js 文件中引入和注册这个指令。

javascript 复制代码
// directive/ScrollTo.js

export const scrollToDirective = {
  mounted(el, binding) {
    el.addEventListener('click', () => {
      const targetId = binding.value;
      const targetElement = document.getElementById(targetId);

      if (targetElement) {
        targetElement.scrollIntoView({ behavior: 'smooth' });
      }
    });
  }
};
javascript 复制代码
// main.js

import { createApp } from 'vue';
import App from './App.vue';
import { scrollToDirective } from './directive/ScrollTo';

const app = createApp(App);

// 注册全局指令
app.directive('scroll-to', scrollToDirective);

app.mount('#app');

使用

javascript 复制代码
<!-- App.vue -->

<template>
  <div>
    <h1>Scroll to Section</h1>
    <button v-scroll-to="'section1'">Scroll to Section 1</button>
    <button v-scroll-to="'section2'">Scroll to Section 2</button>

    <div id="section1" class="section">
      <h2>Section 1</h2>
      <p>This is the content of Section 1.</p>
    </div>

    <div id="section2" class="section">
      <h2>Section 2</h2>
      <p>This is the content of Section 2.</p>
    </div>
  </div>
</template>

<script>
export default {
  // ...
};
</script>

<style>
.section {
  margin-top: 500px; /* Add some space to make scrolling noticeable */
}
</style>

效果:

相关推荐
passerby606140 分钟前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼2 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
吹牛不交税2 小时前
admin.net-v2 框架使用笔记-netcore8.0/10.0版
vue.js·.netcore