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

如何在Next.js中实现组件级路由?点击Tab切换内容且路由不刷新

实现无刷新的侧边栏Tab路由切换

核心思路是利用单页应用(SPA)的前端路由机制:通过拦截浏览器的默认跳转行为,用JavaScript更新页面内容和URL,避免整页刷新。下面分框架和原生JS两种场景给出实现方案:

React 实现方案(React Router)

  1. 安装依赖
npm install react-router-dom
  1. 配置根路由组件
    在App.js中包裹路由容器,并定义Tab对应的路由规则:
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Profile from './Profile';
import Settings from './Settings';
import Insights from './Insights';
import Sidebar from './Sidebar';

function App() {
  return (
    <Router>
      <div style={{ display: 'flex' }}>
        <Sidebar />
        <Routes>
          <Route path="/" element={<Profile />} /> {/* 默认显示Profile */}
          <Route path="/profile" element={<Profile />} />
          <Route path="/settings" element={<Settings />} />
          <Route path="/insights" element={<Insights />} />
        </Routes>
      </div>
    </Router>
  );
}

export default App;
  1. 实现侧边栏Tab
    用Link组件替代普通<a>标签,点击时更新路由而不刷新页面,同时通过useLocation判断当前激活Tab:
import { Link, useLocation } from 'react-router-dom';

function Sidebar() {
  const location = useLocation();

  const getTabStyle = (path) => ({
    textDecoration: 'none',
    color: location.pathname === path ? 'blue' : 'black',
    fontWeight: location.pathname === path ? 'bold' : 'normal',
    display: 'block',
    marginBottom: '12px'
  });

  return (
    <div style={{ width: '200px', padding: '20px', backgroundColor: '#f5f5f5' }}>
      <Link to="/profile" style={getTabStyle('/profile')}>Profile</Link>
      <Link to="/settings" style={getTabStyle('/settings')}>Settings</Link>
      <Link to="/insights" style={getTabStyle('/insights')}>Insights</Link>
    </div>
  );
}

export default Sidebar;
  1. 编写对应内容组件
    比如Profile.js:
function Profile() {
  return (
    <div style={{ padding: '20px', flex: 1 }}>
      <h2>个人资料</h2>
      <p>这里是你的个人信息页面</p>
    </div>
  );
}

export default Profile;

Vue 实现方案(Vue Router)

  1. 安装依赖(Vue3版本)
npm install vue-router@4
  1. 配置路由规则
    创建router/index.js:
import { createRouter, createWebHistory } from 'vue-router';
import Profile from '../views/Profile.vue';
import Settings from '../views/Settings.vue';
import Insights from '../views/Insights.vue';

const routes = [
  { path: '/', component: Profile },
  { path: '/profile', component: Profile },
  { path: '/settings', component: Settings },
  { path: '/insights', component: Insights }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;
  1. 在入口文件注册路由
    main.js:
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

createApp(App).use(router).mount('#app');
  1. 实现侧边栏和内容渲染
    App.vue:
<template>
  <div style="display: flex;">
    <Sidebar />
    <router-view />
  </div>
</template>

<script setup>
import Sidebar from './components/Sidebar.vue';
</script>

Sidebar.vue:

<template>
  <div style="width: 200px; padding: 20px; background-color: #f5f5f5;">
    <router-link 
      to="/profile" 
      :style="{
        textDecoration: 'none',
        color: $route.path === '/profile' ? 'blue' : 'black',
        fontWeight: $route.path === '/profile' ? 'bold' : 'normal',
        display: 'block',
        marginBottom: '12px'
      }"
    >Profile</router-link>
    <router-link 
      to="/settings" 
      :style="{
        textDecoration: 'none',
        color: $route.path === '/settings' ? 'blue' : 'black',
        fontWeight: $route.path === '/settings' ? 'bold' : 'normal',
        display: 'block',
        marginBottom: '12px'
      }"
    >Settings</router-link>
    <router-link 
      to="/insights" 
      :style="{
        textDecoration: 'none',
        color: $route.path === '/insights' ? 'blue' : 'black',
        fontWeight: $route.path === '/insights' ? 'bold' : 'normal',
        display: 'block'
      }"
    >Insights</router-link>
  </div>
</template>

原生JavaScript 实现方案

如果不用框架,通过history API手动拦截跳转和更新内容:

HTML结构:

<div id="sidebar">
  <a href="/profile" class="tab-link">Profile</a>
  <a href="/settings" class="tab-link">Settings</a>
  <a href="/insights" class="tab-link">Insights</a>
</div>
<div id="content"></div>

JavaScript逻辑:

const sidebarLinks = document.querySelectorAll('.tab-link');
const contentArea = document.getElementById('content');

// 根据路径渲染对应内容
function renderContent(path) {
  switch(path) {
    case '/profile':
      contentArea.innerHTML = '<h2>个人资料</h2><p>这里是你的个人信息页面</p>';
      break;
    case '/settings':
      contentArea.innerHTML = '<h2>设置</h2><p>调整你的账户配置</p>';
      break;
    case '/insights':
      contentArea.innerHTML = '<h2>数据洞察</h2><p>查看你的数据分析</p>';
      break;
    default:
      contentArea.innerHTML = '<h2>个人资料</h2><p>这里是你的个人信息页面</p>';
  }
  // 更新激活Tab样式
  sidebarLinks.forEach(link => {
    const isActive = link.getAttribute('href') === path;
    link.style.color = isActive ? 'blue' : 'black';
    link.style.fontWeight = isActive ? 'bold' : 'normal';
  });
}

// 拦截链接点击,更新路由和内容
sidebarLinks.forEach(link => {
  link.addEventListener('click', (e) => {
    e.preventDefault();
    const path = link.getAttribute('href');
    history.pushState({ path }, '', path);
    renderContent(path);
  });
});

// 处理浏览器前进后退
window.addEventListener('popstate', (e) => {
  const path = e.state?.path || '/';
  renderContent(path);
});

// 初始渲染
renderContent(window.location.pathname);

内容的提问来源于stack exchange,提问作者Dinesh Basnet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:19:54