使用useSearchParams或router.replace拼接地址栏——解决tab标签页刷新状态丢失问题

问题描述

  • 日常我们使用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...

在线示例效果和代码仓库

欢迎Star呦😄😄😄

相关推荐
Y42582 小时前
本地多语言切换具体操作代码
前端·javascript·vue.js
fruge4 小时前
React 2025 完全指南:核心原理、实战技巧与性能优化
javascript·react.js·性能优化
不想上班只想要钱6 小时前
vue3+vite创建的项目,运行后没有 Network地址
前端·javascript·vue.js
岁月宁静7 小时前
在富文本编辑器中封装实用的 AI 写作助手功能
前端·vue.js·人工智能
浮游本尊7 小时前
React 18.x 学习计划 - 第四天:React Hooks深入
前端·学习·react.js
533_10 小时前
[vue] dayjs 显示实时时间
前端·javascript·vue.js
fox_11 小时前
深入理解React中的不可变性:原理、价值与实践
前端·react.js
武天11 小时前
Vue项目中有封装过axios吗?怎么封装的?
vue.js
jiangzhihao051512 小时前
升级到webpack5
前端·javascript·vue.js
橘子海全栈攻城狮12 小时前
【源码+文档+调试讲解】基于SpringBoot + Vue的知识产权管理系统 041
java·vue.js·人工智能·spring boot·后端·安全·spring