侧边栏壁纸
  • 累计撰写 54 篇文章
  • 累计创建 4 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

滚动元素到可视区域

  1. 普通方法
<!-- 1. 目标元素设置id -->
<section id="section1">内容区域</section>

<!-- 2. 锚点链接 -->
<a href="#section1">跳转到第一节</a>

<!-- 3. 或通过JavaScript -->
location.hash = '#section1';

启用平滑滚动

/* 启用全局平滑滚动 */
html {
  scroll-behavior: smooth;
}
  1. JS 实现

    在单页面应用中,哈希滚动会与路由系统产生冲突,特别是当使用哈希路由模式时。

方案一

// 约定:路由哈希以 "/" 开头,锚点哈希以 "!" 开头
<a href="#!features">功能特性</a>

// 路由配置
const router = new VueRouter({
  mode: 'hash',
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
    { path: '/!*', redirect: to => {
      // 处理锚点跳转
      const hash = to.path.replace('/!', '');
      scrollToHash(`#${hash}`);
      return { path: '/' }; // 保持在当前路由
    }}
  ]
});

方案二:使用 query 参数代替 hash

// 使用 ?section=features 代替 #features
<a href="?section=features">功能特性</a>

// 路由处理
const router = new VueRouter({
  mode: 'hash',
  routes: [
    { path: '/', component: Home, props: route => ({ 
      section: route.query.section 
    })}
  ]
});

// 组件内监听
export default {
  props: ['section'],
  watch: {
    section(newSection) {
      if (newSection) {
        this.$nextTick(() => {
          const element = document.getElementById(newSection);
          if (element) element.scrollIntoView({ behavior: 'smooth' });
        });
      }
    }
  }
};

方案三:Vue Router 官方方案

// Vue Router 4.x
import { createRouter, createWebHashHistory } from 'vue-router';

const router = createRouter({
  history: createWebHashHistory(),
  routes: [...],
  
  // 处理哈希滚动
  scrollBehavior(to) {
    if (to.hash) {
      return {
        el: to.hash,
        behavior: 'smooth',
        top: 100  // 为固定导航栏预留空间
      };
    }
  }
});

// 在组件中使用
<template>
  <!-- 使用 vue-router 的滚动功能 -->
  <router-link :to="{ hash: '#section1' }">章节1</router-link>
</template>

方案四:React Router 解决方案

import { useNavigate, useLocation } from 'react-router-dom';

function AnchorLink({ to, children }) {
  const navigate = useNavigate();
  const location = useLocation();
  
  const handleClick = (e) => {
    e.preventDefault();
    const [path, hash] = to.split('#');
    
    if (location.pathname === path) {
      // 同页面滚动
      const element = document.getElementById(hash);
      if (element) {
        element.scrollIntoView({ behavior: 'smooth' });
        // 更新URL
        window.history.pushState(null, null, `#${hash}`);
      }
    } else {
      // 跨页面导航
      navigate(to);
    }
  };
  
  return (
    <a href={to} onClick={handleClick}>
      {children}
    </a>
  );
}

// 在目标页面添加滚动效果
function Page() {
  const location = useLocation();
  
  useEffect(() => {
    if (location.hash) {
      const element = document.getElementById(location.hash.substring(1));
      if (element) {
        setTimeout(() => {
          element.scrollIntoView({ behavior: 'smooth' });
        }, 100);
      }
    }
  }, [location]);
  
  return <div>...</div>;
}
0

评论区