1、前端怎么做到页面无刷新

前端无刷新更新页面,核心就是不重新加载整个 HTML 页面,只局部更新数据和视图,这也是现代 Web 应用(SPA)的核心能力。

  1. 原生 AJAX (XMLHttpRequest) —— 基础方案
    最经典的无刷新方式,通过异步请求后端数据,局部更新 DOM。
    适用:简单页面、局部数据刷新。
// 1. 创建请求对象
const xhr = new XMLHttpRequest();
// 2. 配置请求
xhr.open('GET', '/api/data', true);
// 3. 监听响应
xhr.onload = function() {
  if (xhr.status === 200) {
    const res = JSON.parse(xhr.responseText);
    // 无刷新更新页面DOM
    document.getElementById('content').innerHTML = res.msg;
  }
};
// 4. 发送请求
xhr.send();
  1. Fetch API —— 现代原生方案
    比 AJAX 更简洁,基于 Promise,现代浏览器默认支持,无需第三方库。
// 异步请求 + 无刷新渲染
fetch('/api/data')
  .then(res => res.json())
  .then(data => {
    // 只更新需要修改的部分,不刷新页面
    document.querySelector('#user-info').innerText = data.name;
  })
  .catch(err => console.error(err));
  1. Axios —— 企业最常用
    封装好的 HTTP 库,用得最多,支持拦截器、异常处理。
axios.get('/api/user')
  .then(res => {
    // 无刷新渲染
    document.getElementById('list').innerHTML = res.data.list.map(item => `<div>${item.name}</div>`).join('');
  });
  1. 前端路由 (SPA 核心) —— 无刷新切换页面

真正实现 “无刷新跳转页面”,通过改变 URL 但不请求新 HTML,只切换组件。

核心技术

  • hash 路由:url#/home(# 后面变化不会请求服务器)
  • history 路由:url/home(H5 API,更美观)

原生简单实现(hash 路由)

// 监听 URL 哈希变化
window.addEventListener('hashchange', () => {
  const hash = location.hash.slice(1);
  // 根据hash无刷新切换内容
  if(hash === 'home') {
    document.getElementById('view').innerHTML = '<h1>首页</h1>';
  } else if(hash === 'about') {
    document.getElementById('view').innerHTML = '<h1>关于页</h1>';
  }
});

框架路由(Vue/React)
这是现代无刷新页面的标准方案:

  • Vue:vue-router
  • React:react-router-dom

路由切换 → 组件更新 → 页面无刷新。

  1. WebSocket —— 实时无刷新推送
    适合聊天、通知、数据实时更新,服务端主动推送给前端。
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = function(e) {
  // 实时无刷新更新页面
  document.getElementById('msg').innerText = e.data;
};
  1. 异步更新 DOM(纯前端无刷新)
    不请求后端,仅前端交互无刷新:
  • 点击切换内容
  • 表单实时验证
  • 折叠 / 展开面板
// 点击按钮无刷新修改文字
document.getElementById('btn').onclick = () => {
  document.getElementById('text').innerText = '已更新';
};

总结

  • 无刷新核心:异步请求 / 路由切换 + 局部 DOM 更新
  • 现代开发:优先用 Axios + 前端路由(框架标配)
  • 实时场景:用 WebSocket
  • 所有方案都不会重新加载整个页面,体验更流畅

2、react实现一个钩子函数能够记录上次的state值

在 React 中,官方没有直接提供专门记录上一次 state 值的钩子,但最常用、最标准的方案是 useRef + useEffect 组合,手动封装一个自定义 Hook 来实现。

一、最简实现:封装 usePrevious 钩子

import { useRef, useEffect } from 'react';

// 自定义 Hook:获取上一次的值
function usePrevious(prevValue) {
  // 创建 ref 存储上一次值
  const prevRef = useRef();

  // 每次值变化后,更新 ref 存储当前值(作为下一次的“上一次值”)
  useEffect(() => {
    prevRef.current = prevValue;
  });

  // 返回的是**更新前**的值
  return prevRef.current;
}

export default usePrevious;

使用示例

import { useState } from 'react';
import usePrevious from './usePrevious';

function Demo() {
  const [count, setCount] = useState(0);
  // 获取上一次的 count
  const prevCount = usePrevious(count);

  return (
    <div>
      <p>当前值:{count}</p>
      <p>上一次值:{prevCount}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

二、原理说明(非常重要)
1)useRef

  • 有一个稳定不变的 .current 属性
  • 不会因为组件重新渲染而重置
  • 非常适合用来持久存储数据

2)useEffect

  • 会在组件渲染完成后执行
  • 所以先渲染新值 → 再更新 ref
  • 保证返回的永远是上一次渲染的值

3、Hash 路由 和 History 路由的核心区别

(1)Hash 路由
一、 什么是 Hash 路由

URL 中 # 号 后面的部分就是 hash 值。

https://xxx.com/#/home
# 后面的 /home 就是路由 hash

浏览器规定:
URL 里 # 及后面的哈希部分,改变时不会向服务器发请求,只会触发前端监听事件
前端路由就是利用这个特性,实现无刷新页面跳转。

二、核心底层原理
  • hash 变化不会触发页面重载
  • hash 改变不会请求后端接口
  • 前端通过监听 hashchange 事件,捕获 hash 变化,匹配对应组件渲染

涉及两个核心浏览器事件

  • hashchange
    后面路径变化时触发(路由切换、前进后退)
  • load
    页面首次加载时,读取初始 hash 进行首次路由匹配
三、Hash 路由的 URL 规则
http://domain/#/xxx/yyy
  • 浏览器只会把 http://domain/ 发给后端
  • #/xxx/yyy 完全留在浏览器本地,后端接收不到
  • 刷新页面,服务器只返回根路径的 index.html,前端再根据当前 hash 渲染对应页面,永远不会 404
四、原生 JS 简易手写 Hash 路由(看懂就是吃透原理)
// 监听 hash 变化
window.addEventListener('hashchange', () => {
  render()
})

// 首次进入页面执行
window.addEventListener('load', () => {
  render()
})

// 根据 hash 渲染对应页面
function render() {
  // 拿到 # 后面的路径
  const path = location.hash.slice(1) || '/'
  
  if(path === '/' || path === '/home') {
    document.body.innerHTML = '首页'
  } else if(path === '/about') {
    document.body.innerHTML = '关于页'
  }
}

核心 API:

  • location.hash:获取当前哈希值
  • hashchange:监听哈希变化
五、Hash 路由的特点
  • 无需后端配置
    不管部署在 Nginx、Apache、静态服务器,直接丢文件就能跑,刷新不 404。
  • 兼容性极强
    支持 IE 低版本,是老式项目、静态站点首选。
  • URL 自带 # 号
    地址栏有 #,不够优雅,不符合正规产品 URL 审美。
  • #原生是页面锚点
    hash 路由会和原生页面锚点功能冲突。
  • 路由跳转不刷新、不请求后端
    纯前端控制视图切换,性能快。
  • 可以传参
/#/detail?id=1001

可以通过 location.search 或手动解析获取参数。

六、优点
  • 部署简单,零后端配置
  • 刷新永远不会 404
  • 兼容性极好,兼容老旧浏览器
  • 实现简单,底层原理易懂
  • 本地调试、打包部署都不用额外处理
七、缺点
  • URL 带 #,不美观、不正式
  • 与页面原生锚点(跳到页面某位置)冲突
  • 部分第三方平台、微信分享、支付、登录对带 # 路径兼容不好
  • SEO 略差(搜索引擎对带 # 路径抓取不如 History 友好)
  • 无法使用浏览器 History 完整路径语义
八、适用场景
  • 静态网站、个人博客、Demo 项目
  • 后端无法配合配置 rewrite 规则
  • 需要兼容 IE 老旧浏览器
  • 临时快速上线、简单活动页
九、Vue / React 中 Hash 路由怎么开启

Vue Router

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [...]
})

React Router

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <Routes>...</Routes>
</HashRouter>
十、一句话总结核心

Hash 路由就是利用 URL # 号不请求服务器、只在本地变化的特性,监听 hashchange 事件,由前端自己匹配路径、渲染组件,不用后端配置、永不 404,但地址带 # 不好看。

(2)history 路由
一、概述

History 路由是前端 SPA(单页应用)的主流路由模式,基于 HTML5 History API 实现,URL 形如 /user/123(无#),更优雅、利于 SEO,但需后端配合解决刷新 404 问题。

二、核心原理

1、底层 API(HTML5 新增)

history.pushState(state, title, url)
新增历史记录,修改 URL 但不刷新页面。

  • state:关联的状态对象(popstate时可获取)
  • title:浏览器忽略,传’’
  • url:新路径(必须同源)

history.replaceState(state, title, url)
替换当前历史记录,不新增栈(无法后退到上一页)

popstate事件
点击前进 / 后退或调用history.back() / forward() / go(n)时触发,用于更新视图

2、前端实现流程

  • 拦截链接点击:阻止默认跳转,改用pushState
  • 监听popstate:前进 / 后退时更新视图
  • 初始渲染:页面加载时读取location.pathname渲染对应组件

极简伪代码:

// 跳转
function goto(path) {
  history.pushState({}, '', path);
  render(path); // 手动渲染(pushState不触发popstate)
}
// 监听前进/后退
window.addEventListener('popstate', () => render(location.pathname));
// 拦截站内链接
document.addEventListener('click', e => {
  const a = e.target.closest('a[href^="/"]');
  if (a) { e.preventDefault(); goto(a.href); }
});
三、优缺点

优点

  • ✅ URL 美观:无#,与传统页面一致
  • ✅ SEO 友好:可配合 SSR / 预渲染提升收录
  • ✅ 状态管理强:pushState可携带state对象传参
  • ✅ 无锚点冲突:路径与页面内锚点(#id)互不干扰

缺点

  • ❌ 需后端配置:刷新 / 直接访问子路径会 404,需服务器兜底到index.html
  • ❌ 兼容性有限:不支持 IE9 及以下
四、后端配置(解决 404)

Nginx

location / {
  try_files $uri $uri/ /index.html; # 所有请求指向index.html
}

Apache(.htaccess)

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.html [L]
五、框架中使用

Vue Router

import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
  history: createWebHistory(), // History模式
  routes: [...]
});

React(React Router)

import { createBrowserRouter } from 'react-router-dom';
const router = createBrowserRouter([...]);
六、常见问题
  • 刷新 404:后端未配置兜底,按上述 Nginx/Apache 配置解决
  • 静态资源 404:资源路径用绝对路径(如/js/main.js)
  • popstate不触发:pushState/replaceState不会触发,需手动渲染

History 路由是现代 SPA 的首选,URL 优雅、SEO 友好,核心依赖pushState/replaceState与popstate。使用时必须配置后端,否则刷新会 404。

4、路由守卫

一、什么是路由守卫?

路由守卫 = 路由跳转前后,提前设置的「拦截关卡」
在页面跳转前 / 跳转中 / 跳转后,拦截路由,做判断、放行、拦截、跳转。
就像过安检:要去某个页面,先过守卫检查,合格放行,不合格拦下跳登录页。

二、核心作用

  • 登录鉴权:没登录不让进首页、个人中心
  • 权限控制:普通用户不能进管理员页面
  • 页面标题动态修改:进哪个页改对应 title
  • 路由拦截、阻止跳转
  • 页面跳转记录、埋点

三、路由守卫分类(Vue 全套,面试常问)

  1. 全局守卫(整个项目所有路由都生效)
    ① 全局前置守卫 beforeEach
    跳转「之前」拦截,最常用
router.beforeEach((to, from, next) => {
  // to:要去的页面
  // from:从哪来
  // next:放行/拦截/强制跳转

  // 举例:没登录拦截去登录页
  const token = localStorage.getItem('token');
  if (!token && to.path !== '/login') {
    next('/login'); // 拦截,跳登录
  } else {
    next(); // 放行
  }
});

② 全局后置守卫 afterEach
跳转完成之后执行,没有 next
适合:改页面标题、页面访问埋点

router.afterEach((to, from) => {
  document.title = to.meta.title || '默认标题';
});
  1. 路由独享守卫(只给某一个路由单独设置)
    只针对当前这条路由生效,写在路由配置里:
const routes = [
  {
    path: '/admin',
    component: Admin,
    // 独享前置守卫
    beforeEnter: (to, from, next) => {
      // 判断是否是管理员
      if (isAdmin) next();
      else next('/404');
    }
  }
];
  1. 组件内守卫(写在组件页面内部)
    进入组件、离开组件时拦截:

    beforeRouteEnter 进入组件前
    beforeRouteUpdate 路由复用、参数变化时
    beforeRouteLeave 离开组件前

<script>
export default {
  // 进入前
  beforeRouteEnter(to, from, next) {
    next();
  },
  // 路由更新(同页面换参数)
  beforeRouteUpdate(to, from, next) {},
  // 离开当前页面前
  beforeRouteLeave(to, from, next) {
    // 比如未保存提示是否离开
  }
}
</script>

四、三个核心参数必懂

  • to:目标路由(你要去哪里)

  • from:当前路由(你从哪里来)

  • next():必须调用,控制路由走向

    next() 正常放行
    next(‘/login’) 强制跳转到指定页
    next(false) 阻止本次跳转

五、执行顺序(面试常考)

  • 全局前置 beforeEach
  • 路由独享 beforeEnter
  • 组件内 beforeRouteEnter
  • 组件渲染
  • 全局后置 afterEach

路由守卫就是路由跳转过程中的拦截关卡,可以在跳转前后做登录鉴权、权限控制、页面标题修改、跳转拦截等逻辑。
分为三类:全局守卫、路由独享守卫、组件内守卫;核心参数 to 目标路由、from 来源路由、next 控制放行或跳转,其中 beforeEach 全局前置守卫项目最常用。

5、单页面应用

一、什么是 SPA
SPA(Single Page Application)单页面应用:
整个网站只有一个 HTML 页面,所有页面跳转不刷新浏览器,通过前端路由切换组件、动态替换页面内容。
传统多页 MPA:
点链接 → 浏览器整页刷新 → 重新请求服务器 → 返回新 HTML
SPA 单页:
打开只加载一次 index.html,之后跳转页面不刷新、不请求新 HTML,只通过 JS 动态渲染不同组件。

二、核心原理

  • 项目只有一个入口 index.html
  • 页面跳转靠 前端路由(Hash / History)
  • 切换页面只替换局部组件内容,不重载整个页面
  • 页面数据通过 AJAX/Fetch 异步请求后端接口
  • 依靠 Vue / React / Angular 开发

三、SPA 怎么实现无刷新跳转

靠两个核心:

  • 前端路由:Hash 模式 / History 模式
  • 组件动态渲染:根据路径匹配对应组件,替换 区域

四、SPA 优点

  • 页面无刷新,体验流畅,像原生 APP
  • 前后端分离:前端负责页面,后端只给接口
  • 减少服务器压力:不用每次跳转都渲染整页 HTML
  • 组件复用性高,开发效率高
  • 适合做中后台管理系统、移动端 H5

五、SPA 缺点(面试必问)

  • 首屏加载慢
    一次性要加载 JS、CSS、路由、状态库,白屏时间长

  • SEO 天生不友好
    默认是客户端渲染 CSR,返回空 HTML,爬虫拿不到真实内容
    (解决:用 SSR / SSG / 预渲染)

  • 路由刷新 404(History 模式)
    需要后端 Nginx 配置兜底

  • 项目打包后体积大,需要做分包、懒加载优化

  • 不能用浏览器原生前进后退简单逻辑,要自己处理路由

SPA 单页面应用是整个项目只有一个 index.html,页面跳转依靠前端路由实现无刷新局部组件替换,不用每次请求服务端新页面;优点是页面跳转流畅、前后端分离、组件可复用;缺点是首屏加载慢、SEO 不友好、History 路由刷新会 404,常用 Vue、React 开发,可通过路由懒加载、SSR 解决缺点。

6、SPA和MPA的区别

SPA

  • 首次请求:返回唯一 index.html + 打包 js/css
  • 后续跳转:不再请求 html,只发 Ajax 接口拿数据,前端渲染组件

MPA

  • 每点一个页面
  • 浏览器重新请求服务器
  • 服务器重新渲染、返回全新 html
  • 整页刷新展示

SPA 优点

  • 页面跳转无刷新、体验丝滑
  • 前后端彻底分离,分工明确
  • 组件复用率高,开发效率高
  • 减少服务器页面渲染压力

SPA 缺点

  • 首屏加载慢,容易白屏
  • SEO 不友好(客户端渲染)
  • History 路由刷新 404,需要后端配置
  • 打包体积大,需要懒加载、分包优化

MPA 优点

  • 首屏打开快
  • 天然 SEO 友好
  • 架构简单,部署不用特殊配置,无 404 问题
  • 单页面资源独立,互相影响小

MPA 缺点

  • 每次跳转整页刷新,体验差
  • 前后端耦合,维护麻烦
  • 服务器压力大
  • 组件复用困难

SPA 单页面应用只有一个 HTML 入口,依靠前端路由实现无刷新局部组件切换,跳转体验好、前后端分离;缺点是首屏慢、SEO 不友好、History 路由刷新 404 需要后端配置。

MPA 多页面应用每个路由对应独立 HTML,跳转整页刷新、由后端返回页面;优点首屏快、天然 SEO 友好,缺点跳转体验差、前后端耦合、服务器压力大。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐