问题描述
- 日常我们使用tab标签页组件的时候,可以点击tab进行标签页的切换
- 但是,假若我们刷新浏览器页面
- tab标签页会恢复回到默认的高亮的tab
- 但是,某些情况下,我们可能想要页面刷新后,依旧保持在当前高亮的tab标签页上
- 本文通过react和vue的示例
- 对应使用useSearchParams或router.replace将高亮的key拼接在地址栏上
- 这样的话,当我们刷新网页的时候
- 就会停留在我们当前的高亮tab页签上了
当然,也可以把高亮的tab存储在sessionStorage或者localStorage中,这里不赘述了,思想是一样的
效果图

- 分析上图,初始状态,高亮的是Tab 1
- 切换tab后,刷新,高亮状态保留
思路分析
React中的控制
- 在React中,我们可以使用
useSearchParams
这个hook进行地址栏的查询参数的读取和修改 - 如下基础用法
js
import { useSearchParams } from 'react-router-dom';
function UserProfile() {
// 获取查询参数对象和修改函数
const [searchParams, setSearchParams] = useSearchParams();
// 读取查询参数
const name = searchParams.get('name'); // 获取 name 参数值
const age = searchParams.get('age'); // 获取 age 参数值
// 修改查询参数
const handleUpdateParams = () => {
setSearchParams({ name: 'Alice', age: '25' });
};
return (
<div>
<p>Name: {name} --- Age: {age}</p>
<button onClick={handleUpdateParams}>
Update Parameters
</button>
</div>
);
}
- 即,当页面didMounted的时候获取地址栏tab参数
- 若有高亮的tab的key的值,就直接修改tab组件的高亮值(没有就指定默认的,比如默认高亮第一个)
- 同时也要做searchParams的数据收集依赖监听,这样控制就可以做到当用户手动修改浏览器地址栏高亮tab的时候
- 切换到对应的tab
- 同时,当用户点击tab组件的时候,在onChange事件中,也要做对应浏览器地址栏参数的修改
两个控制:1. 修改地址栏tab高亮参数,要切换标签页;2. 点击tab组件,也要切换标签页,同时修改地址栏参数
React代码
tab数据:
js
const items: TabsProps['items'] = [
{
key: '1',
label: 'Tab 1',
children: 'Content of Tab Pane 1',
},
{
key: '2',
label: 'Tab 2',
children: 'Content of Tab Pane 2',
},
{
key: '3',
label: 'Tab 3',
children: 'Content of Tab Pane 3',
},
];
逻辑控制代码
js
import React, { useState, useEffect } from 'react'
import { Tabs } from 'antd';
// useLocation用于获取完成地址栏信息,useSearchParams用于获取查询query信息,并返回可读写的searchParams对象
import { useSearchParams } from 'react-router-dom'
import type { TabsProps } from 'antd';
export default function TabStatus() {
const [searchParams, setSearchParams] = useSearchParams()
// 1. 默认高亮第一个tab
const [activeKey, setActiveKey] = useState('1')
useEffect(() => {
// 2. 当页面didMounted的时候获取地址栏tab参数,并修改tab高亮
const queryObj = Object.fromEntries(searchParams.entries())
setActiveKey(queryObj.tab || '1')
// 3. 后续当地址栏参数发生变化的时候,也去获取地址栏tab参数,并修改tab高亮
}, [searchParams]) // 也可以只单独监听tab [searchParams.get('tab')] 不过最好提取出来
const onChange = (key: string) => {
console.log('onChange', key);
// 4. 当tab高亮发生变化时,修改地址栏参数
const queryObj = Object.fromEntries(searchParams.entries())
queryObj['tab'] = key
setSearchParams(queryObj)
// setSearchParams({tab: key}) // 注意不要只修改tab把别的地址栏参数覆盖掉了
};
return (
<div>
<h2>TabStatus------刷新依旧保留当前tab状态</h2>
<Tabs activeKey={activeKey} items={items} onChange={onChange} />
</div>
)
}
Vue中的控制
- Vue就更加简单好控制了
- 页面加载时,检查query参数中的tab值,如果有,则设置activeName为该值
- 当tabChange的时候
- 保留原本的query参数同时,再拼接tab参数,这样刷新页面后,仍然可以保持在当前tab页
Vue代码
html结构:
html
<template>
<div class="boxWrap">
<h3>tab标签刷新页面,保留当前tab停留的状态页</h3>
<br>
<el-tabs v-model="activeName" @tab-change="tabChange">
<el-tab-pane label="first" name="first">first</el-tab-pane>
<el-tab-pane label="second" name="second">second</el-tab-pane>
<el-tab-pane label="third" name="third">third</el-tab-pane>
<el-tab-pane label="fourth" name="fourth">fourth</el-tab-pane>
</el-tabs>
</div>
</template>
js代码:
js
<script setup>
import { ref, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
const router = useRouter();
const route = useRoute();
const query = route.query;
// 默认第一个tab页
const activeName = ref("first");
onMounted(() => {
/**
* 页面加载时,检查query参数中的tab值,如果有,则设置activeName为该值
* */
if (query.tab) {
activeName.value = query.tab;
}
});
const tabChange = (tabName) => {
/**
* 保留原本的query参数同时,再拼接tab参数,这样刷新页面后,仍然可以保持在当前tab页
* */
router.replace({ query: { ...query, tab: tabName } });
};
</script>
- 上述是基于React和Vue的路由提供的钩子进行的控制
- 这些路由钩子的底层实际上也就是基于history.pushState和history.replaceState实现的
- 当然,也可直接用原生js去书写
history.pushState更新地址栏
思想是一样的,这里不赘述,如下示例思路代码:
js
// 不刷新页面拼接地址栏query参数【前提是本身就有 ?key=value 】
export const updateUrl = (q: string) => {
var url = window.location.href; // 获取当前URL
var newUrl = url + '&' + q; // 拼接新的URL q: name=tom
history.pushState(null, '', newUrl); // 修改地址栏URL
}
updateUrl(`tab=${tab}`)
- 同样的,比如页面中有一个dialog是打开的状态,我们也可以通过上述的控制
- 保留dialog的打开状态(地址栏拼接对应的dialog的开启关闭的布尔值之类的)
A good memory is better than a bad pen. Record it down...
在线示例效果和代码仓库
- 在线示例1 ashuai.site/reactExampl...
- 在线示例2 ashuai.work:8890/32
- 代码仓库1 github.com/shuirongshu...
- 代码仓库2 github.com/shuirongshu...
欢迎Star呦😄😄😄