React19 路由方案与原理详解

React19 路由方案与原理详解

相关资料

相关面试真题

React Router 路由历史的几种模式及其实现原理

Browser History

Browser History 使用的是 HTML5的 history.pushState 和 history.replaceState APl。这种模式能够创建真实的 URL结构(例如 example.com/about),而不会重新加载页面。

实现原理
  • history.pushState:用于向历史堆栈中添加一个新条目,并跳转到对应的 URL。
  • history.replaceState:用于替换当前的历史条目,而不会创建新的记录。
  • popstate 事件:当用户点击浏览器的后退/前进按钮时触发,React Router 会监听这个事件并相应地更新页面。
优点
  • URL 与服务器路由一致,利于 SEO 和用户体验。
  • 可以使用浏览器的前进和后退功能。
缺点
  • 需要服务器配置以支持所有应用内路由
Hash History

Hash History 使用 URL 的hash 部分来模拟不同的路径(例如 example.com/#/about)。这种模式不需要服务器配置,因为 hash 部分不会被发送到服务器。

实现原理
  • window.location.hash:用于获取和设置 URL 的 hash部分。
  • hashchange 事件:当 URL 的hash部分变化时触发,React Router 会监听这个事件并相应地更新页面。
优点
  • 简单易用,不需要服务器配置。
  • 在老旧浏览器上兼容性好。
缺点
  • URL结构不美观,不利于 SEO
Memory History

Memory History 将历史记录保存在内存中,而不与浏览器的地址栏同步。通常用于非浏览器环境,例如 React Native 或测试环境。

实现原理
  • 维护一个内部堆栈来管理历史记录。
  • 无需依赖浏览器的历史 API,完全在内存中操作。
优点
  • 适用于非浏览器环境。
  • 不依赖于 URL,可以自由操作历史记录。
缺点
  • 不能通过地址栏直接访问特定页面。
Static History

Static History 为了支持SSR而引入的一种历史模式,主要运用在服务端渲染应用中,它与前端的 Browser History 不同,它主要用于在服务器端生成页面时模拟浏览器的行为。 访客

实现原理
  • createStaticHandler 和 createStaticRouter 提供了静态版本的路由处理和路由器配置,专为SSF 设计。
  • 它们允许在服务器端解析路由,并生成对应的路由状态,以便在服务端渲染时使用。
优点
  • createstaticHandler:用于创建静态路由处理器,它不依赖于浏览器环境,可以在服务器端解析路径,生成路由匹配结果。
  • createstaticRouter:用于创建静态路由器,同样适用于服务器端,它根据提供的初始路径和路由配置来初始化路由器状态。
  • StaticRouterProvider:结合 StaticRouter,它负责在服务器端提供路由上下文,使得 useRoutes 和其他路由钩子能够正常工作。
缺点
  • 灵活性不足:静态路由无法在运行时动态添加新路由,限制了应用的动态扩展能力。
  • 维护困难:随着应用规模增长,静态路由表变得庞大,管理维护成本增加。
  • 处理动态路由能力有限:不适合处理复杂的动态路由需求,如RESTful风格的路由,可能需要预先定义大量参数情况。
  • SEO挑战:在复杂应用中,静态路由可能影响SEO,尤其是动态生成内容时。
  • 测试复杂性:需要为每个路由编写测试用例,路由数量增加导致测试维护困难。
  • 性能影响:初始加载时加载所有路由信息,可能增加加载时间,尤其是在路由数量多时。

react-router、react-router-dom、react-router-native 的联系与设计原因

联系
  • react-router:核心库,提供了路由的核心功能,不依赖于具体的平台。可以用于任何环境下实现路由功能。
  • react-router-dom:基于 react-router,专门为 Web 环境设计,包含 BrowserRouter 和 HashRouter 等适用于浏览器的组件。
  • react-router-native: #F react-router 专门为 React Native 环境设计,包含 NativeRouter 于移动应用的组件。
设计原因
  • 模块化设计:将核心功能与平台特定实现分离,使得 react-router 能够独立于平台工作,增强了灵活性和可移植性。
  • 复用核心逻辑:通过共享 react-router 的核心逻辑, react-router-dom 和 react-routernative 能够复用基本的路由机制,减少了重复代码,提高了维护性。
  • 适应不同环境:不同平台有不同的需求,例如浏览器环境需要处理URL,而移动应用则处理组件状态。将平台特定实现分离出来,使得每个模块可以专注于解决特定环境的问题。

动态路由的使用和实现原理

动态路由是指在路径中包含变量部分的路由,例如 /users/:id。React Router 通过路径参数实现动态路由。

实现原理
  • 路径匹配:React Router 使用路径模式匹配的方式来解析 URL 中的变量部分。例如,路径 /users/:id 匹配 URL /users/123,并将 123 提取为 id 参数。
  • useParams Hook:useParams 是一个 React Hook,用于访问当前匹配的路径参数。它返回一个对象,其中包含所有路径参数的键值对。
  • 路由配置:通过定义带有变量部分的路径模式(如 :id),React Router 能够自动解析和提取 URL 中的对应部分,并将其传递给对应的组件。
优点
  • 路由定义更加灵活,能够处理复杂的 URL结构。
  • 易于实现基于参数的页面,例如用户详情页、文章详情页等。

React Router 基础使用

  • 因为在早期,路由使用来定位资源的,url(统一资源定位符/ Uniform Resource Locators)、uri (Uniform Resource Identifier/统一资源标识符),之前的路由是真实跟静态资源映射的。
  • 在后来,SPA应用出现后,前端想要自己控制路由的跳转以及路由所对应资源的处理,于是乎出现了框架对应的路由,React 的React-Router, Vue 的Vue-Router
  • React Router 是 React 应用程序中用于管理路由的标准库。以下是对 React Router v6.23.1版本的基础使用的详细说明。

详细 API 说明

基础组件
BrowserRouter
  • BrowserRouter 使用 HTML5 history API(如 pushState、replacestate)来保持UI 与URL 同步。适用于普通的 web 应用程序。
Routes 和 Route
  • Routes: 包含应用中所有路由定义的容器。用于包裹多个 Route 组件。
  • Route:用于定义路径和对应的组件。

[###### Outlet

  • Outlet 组件用于渲染匹配的子路由组件。它是嵌套路由的占位符。
useParams
  • useParams 返回当前路由的参数。例如在路径 /users/:id , id 是一个参数。
useNavigate
  • useNavigate 返回一个路由跳转函数,可以使用这个函数轻松实现路由跳转
redirect
  • redirect 是一个工具函数,在应用中任何位置都可以调用,用于重定向到给定页面。
redirectDocument
  • redirectDocument 是一个工具函数,在应用中任何位置都可以调用,用于重定向到给定页面,需要注意的是, 这个方法是文档级别的重定向,整体表现接近于 window.location。
useBlocker
  • 当跳转到其他路由的时候,类似于路由守卫
useBeforeUnload
  • 页面离开的时候

进阶功能

动态路由
  • 动态路由允许在路径中包含变量。例如,路径 /users/:id,匹配 URL /users/123,并将 123 提取为 id参数
路由保护
  • 通过使用自定义组件和逻辑,可以实现路由保护,例如验证用户是否已登录。
其它定义形式的用法
基于 JSON 配置(推荐)
  • 新版 React-Router 整体使用相对灵活,我们可以基于json 配置数据使用路由,也可以通过 createRoutesFromELements
基于 createRoutesFromElements
组件式定义

因为在早期,路由使用来定位资源的,url(统一资源定位符/ Uniform Resource Locators)、uri (Uniform Resource Identifier/统一资源标识符),之前的路由是真实跟静态资源映射的。
在后来,SPA应用出现后,前端想要自己控制路由的跳转以及路由所对应资源的处理,于是乎出现了框架对应的路由,React 的React-Router, Vue 的Vue-Router

多类型历史记录栈

react-router 为了满足开发者更多路由历史存储场景,提供了以下几种模式

  • 浏览器原生历史记录浏览器
  • hash
  • 内存型
  • 服务端记录
  • createBrowserRouter:浏览器提供的历史管理
  • createHashRouter(不推荐):基于 hash的路由管理,#hello,但是呢通常 #又可以作为锚链接
  • createMemoryRouter:内存型路由,路由的管理存储在内存中
  • createStaticRouter(用于 SSR):SSR 服务端的

createBrowserRouter

通过浏览器原生路由进行路由态管理,页面跳转通过 pushState、popState 方法实现

需要注意的是,使用 browserRouter,一般都需要使用类似 Nginx做静态资源代理,另外需要注意404的情况,一般都需要添加 try_files处理

createHashRouter

他的用武之地就在于,我们没有Nginx 作为静态资源代理,我们可能就无法使用浏览器历史作为我们路由状态的存储,这时可以选择 hash router 方案,但是注意,真的非常不推荐。

createMemoryRouter

用于创建一个内存型路田,路由表与历史记录栈存储在内存中,当页面刷新时,路由信息丢失。
其实这种内存型历史记录,我们自己通过状态管理都能够轻松实现,他这就类似于我们定义了集中状态,然后当状态更新时渲染不同页面。而这里只是多了一些关于路由操作方法的实现,比如:push、pop 等。

createStaticRouter

如果我们需要实现服务端渲染,那么在服务端的路由处理则需要使用该 api,因为我们知道客户端的路由是基于浏览器的 history,而服务端是没有浏览器环境的。

React Router 实现原理剖析

React-Router 实现最需要关注的就以下几方面:

  • 路由值到视图的映射规则
  • 对于路由变更的监听
  • 路由操作方法
  • 路由记录存储与操作

BrowserRouter 实现流程

History 是整个浏览器路由历史记录大对象,其中包含长度等属性
Location 是单一页面所对应的资源定位对象,我们可以理解为当页面跳转时,先生成 Location,然后将 Location push El History.
浏览器路由实现,最主要的两个概念是变更路由与监听路由变更。

  • 历史操作,(注:此操作不会触发 popState)
  • history.pushState
  • history.replaceState
  • 监听变更
  • window.addEventListener ("popstate", () => ({})
  • 操作,(注:以下操作会触发 popState)
  • history.back()
  • history.forward()
  • history.go()
    以下是基于 BrowserRouter 实现流程的代码示例,按照您提到的五个步骤逐一实现。每个步骤的代码都清晰地对应了其功能,并附带注释以便理解。
创建 Router

首先,我们需要创建一个 Router 组件。它将负责管理应用的路由状态,并提供上下文供子组件访问路由信息。

javascript 复制代码
import React, { createContext, useState, useEffect } from 'react';
// 创建路由上下文
export const RouterContext = createContext();
// Router 组件
export function Router({ children }) {
// 状态管理:location 和 history
const [location, setLocation] = useState(window.location.pathname);
// 提供上下文给子组件
return (
<RouterContext.Provider value={{ location, setLocation }}>
{children}
</RouterContext.Provider>
);
}
承载 history

BrowserRouter 中,我们使用浏览器的 history API 来管理路由历史记录。这里我们将封装一个简单的 history 对象。

javascript 复制代码
// 创建 history 对象
export const createBrowserHistory = () => {
const history = {
// 当前路径
location: window.location.pathname,
// 历史记录栈
stack: [window.location.pathname],
index: 0,
// 推入新路径
push(path) {
this.location = path;
this.stack.push(path);
this.index++;
window.history.pushState({}, '', path);
},
// 替换当前路径
replace(path) {
this.location = path;
this.stack[this.index] = path;
window.history.replaceState({}, '', path);
},
// 返回上一页
goBack() {
if (this.index > 0) {
this.index--;
this.location = this.stack[this.index];
window.history.back();
}
},
// 前进到下一页
goForward() {
if (this.index < this.stack.length - 1) {
this.index++;
this.location = this.stack[this.index];
window.history.forward();
}
},
};
return history;
};
确定 location

location 是当前的 URL 路径。我们需要监听 popstate 事件来同步浏览器的历史记录和应用的状态。

javascript 复制代码
export function BrowserRouter({ children }) {
// 创建 history 对象
const history = createBrowserHistory();
// 使用 Router 组件管理 location
return (
<Router>
<RouterContext.Consumer>
{({ setLocation }) => {
// 监听 popstate 事件
useEffect(() => {
const handlePopState = () => {
setLocation(window.location.pathname);
};
window.addEventListener('popstate', handlePopState);
return () => window.removeEventListener('popstate', handlePopState);
}, [setLocation]);
return children;
}}
</RouterContext.Consumer>
</Router>
);
}
历史记录栈变更监听

我们需要确保每次路由变化时,history 的状态与 location 同步。这可以通过在 pushreplace 方法中触发更新来实现。

javascript 复制代码
export const useHistory = () => {
const { location, setLocation } = React.useContext(RouterContext);
const history = createBrowserHistory();
// 封装 push 方法
const push = (path) => {
history.push(path);
setLocation(path);
};
// 封装 replace 方法
const replace = (path) => {
history.replace(path);
setLocation(path);
};
return { location, push, replace, goBack: history.goBack, goForward: history.goForward };
};
处理 popState 逻辑

popstate 事件会在用户点击浏览器的前进或后退按钮时触发。我们需要在此事件中更新应用的状态。

javascript 复制代码
export function usePopState() {
const { setLocation } = React.useContext(RouterContext);
useEffect(() => {
const handlePopState = () => {
setLocation(window.location.pathname);
};
window.addEventListener('popstate', handlePopState);
return () => window.removeEventListener('popstate', handlePopState);
}, [setLocation]);
}
完整的代码整合
javascript 复制代码
import React, { createContext, useState, useEffect } from 'react';
// 创建路由上下文
export const RouterContext = createContext();
// Router 组件
export function Router({ children }) {
const [location, setLocation] = useState(window.location.pathname);
return (
<RouterContext.Provider value={{ location, setLocation }}>
{children}
</RouterContext.Provider>
);
}
// 创建 history 对象
export const createBrowserHistory = () => {
const history = {
location: window.location.pathname,
stack: [window.location.pathname],
index: 0,
push(path) {
this.location = path;
this.stack.push(path);
this.index++;
window.history.pushState({}, '', path);
},
replace(path) {
this.location = path;
this.stack[this.index] = path;
window.history.replaceState({}, '', path);
},
goBack() {
if (this.index > 0) {
this.index--;
this.location = this.stack[this.index];
window.history.back();
}
},
goForward() {
if (this.index < this.stack.length - 1) {
this.index++;
this.location = this.stack[this.index];
window.history.forward();
}
},
};
return history;
};
// BrowserRouter 组件
export function BrowserRouter({ children }) {
const history = createBrowserHistory();
return (
<Router>
<RouterContext.Consumer>
{({ setLocation }) => {
useEffect(() => {
const handlePopState = () => {
setLocation(window.location.pathname);
};
window.addEventListener('popstate', handlePopState);
return () => window.removeEventListener('popstate', handlePopState);
}, [setLocation]);
return children;
}}
</RouterContext.Consumer>
</Router>
);
}
// 自定义 hook:useHistory
export const useHistory = () => {
const { location, setLocation } = React.useContext(RouterContext);
const history = createBrowserHistory();
const push = (path) => {
history.push(path);
setLocation(path);
};
const replace = (path) => {
history.replace(path);
setLocation(path);
};
return { location, push, replace, goBack: history.goBack, goForward: history.goForward };
};

MemoryRouter 的实现流程

  1. 创建 History 实例
    MemoryRouter 使用 createMemoryHistory 方法创建一个内存型的 history 对象。这个对象负责管理路由状态,包括路径栈、当前路径等。
  2. 封装 Router
    MemoryRouter 是对 Router 组件的封装,它将 history 对象传递给 Router,从而实现路由功能。
  3. 统一接口协议
    无论是 MemoryRouter 还是 BrowserRouter,它们都遵循相同的接口协议,开发者可以无缝切换路由类型,而无需修改业务逻辑代码。

代码示例

以下是一个完整的 MemoryRouter 实现示例:

jsx 复制代码
import React from "react";
import { Router, createMemoryHistory } from "react-router-dom";
// 自定义 MemoryRouter 组件
function MemoryRouter({ initialEntries = ["/"], initialIndex, children }) {
// 创建内存型 history 对象
const history = createMemoryHistory({ initialEntries, initialIndex });
return (
// 将 history 传递给 Router
<Router history={history}>
{children}
</Router>
);
}
// 示例:使用 MemoryRouter
function App() {
return (
<MemoryRouter initialEntries={["/", "/about", "/contact"]} initialIndex={0}>
<div>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
{/* 路由匹配 */}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
</MemoryRouter>
);
}
// 页面组件
function Home() {
return <h2>Home Page</h2>;
}
function About() {
return <h2>About Page</h2>;
}
function Contact() {
return <h2>Contact Page</h2>;
}
export default App;

代码解析
  1. createMemoryHistory
  • createMemoryHistory 是 React-Router 提供的一个工具函数,用于创建内存型的 history 对象。
  • 参数:
  • initialEntries: 初始路径栈,例如 ["/", "/about", "/contact"]
  • initialIndex: 初始路径索引,默认为 0
  1. <Router>** 组件**
  • Router 是 React-Router 的核心组件,负责接收 history 对象并管理路由状态。
  • MemoryRouter 通过将 history 传递给 Router,实现了内存型路由的功能。
  1. 统一接口协议
  • MemoryRouterBrowserRouter 都遵循相同的接口协议,开发者可以通过 <Link><Routes><Route> 等组件实现路由跳转和匹配。

适用场景
  • 测试环境 : 在单元测试或集成测试中,MemoryRouter 可以模拟路由行为,而无需依赖浏览器环境。
  • React Native : 在移动端开发中,MemoryRouter 可以替代 BrowserRouter,因为移动端没有浏览器的历史记录 API。
  • 嵌套应用 : 在微前端架构中,子应用可能需要独立管理路由状态,MemoryRouter 是一个理想的选择。

总结

MemoryRouter 的核心在于通过 createMemoryHistory 创建内存型的路由历史记录,并将其封装到 Router 中。它的设计体现了抽象封装的魅力,使得开发者可以在不同环境中灵活使用路由功能,同时保持一致的 API 接口。

更多 React 路由库方案

@tanstack/router 是一个现代化的路由库,旨在为前端应用提供高效、灵活且可扩展的路由解决方案。它以其简洁的设计和强大的功能受到开发者的青睐。以下是对其主要特性的详细扩写:

基础使用示例

@tanstack/router 提供了直观且易于上手的 API,使得开发者可以快速集成路由功能到项目中。以下是一个简单的基础使用示例:

javascript 复制代码
import { createRouter, createRoute } from '@tanstack/router'
// 创建路由实例
const rootRoute = createRoute({
path: '/',
component: () => <h1>Welcome to the Home Page</h1>,
})
const aboutRoute = createRoute({
path: '/about',
component: () => <h1>About Us</h1>,
})
const router = createRouter({
routes: [rootRoute, aboutRoute],
})
// 在应用中使用路由
function App() {
return <router.Router />
}

通过上述代码可以看出,@tanstack/router 的 API 设计非常直观,开发者只需定义路由路径和对应的组件,即可轻松实现页面跳转和渲染。


约定式路由(基于文件自动生成)

@tanstack/router 支持约定式路由(Convention-based Routing),这是一种基于文件结构自动生成路由配置的方式。这种方式极大地简化了路由管理,尤其适用于中大型项目,能够显著减少手动配置的工作量。

约定式路由的特点:
  • 文件即路由:开发者只需按照约定的目录结构组织文件,路由会自动根据文件路径生成。例如:
plain 复制代码
src/
pages/
index.js -> 路径: '/'
about.js -> 路径: '/about'
users/
index.js -> 路径: '/users'
[id].js -> 动态路径: '/users/:id'

在这种结构下,@tanstack/router 会自动解析 pages 目录中的文件,并生成对应的路由配置。

  • 动态路由支持 :通过文件命名约定(如 [id].js),可以轻松实现动态路由。动态参数会自动解析并传递给组件,方便处理用户详情、文章详情等场景。
  • 嵌套路由:约定式路由天然支持嵌套结构,开发者可以通过文件夹层级定义嵌套路由。例如:
plain 复制代码
src/
pages/
users/
profile.js -> 路径: '/users/profile'

这种方式使得路由的嵌套关系清晰可见,便于维护。

  • 无需手动维护路由表:传统的路由配置需要手动编写路由表,而约定式路由完全省去了这一步骤。开发者只需专注于页面逻辑,路由配置由框架自动生成。
示例:约定式路由的实际应用

假设项目中有如下文件结构:

plain 复制代码
src/
pages/
index.js
about.js
products/
index.js
[id].js

通过 @tanstack/router 的约定式路由功能,以下路由配置会自动生成:

  • / -> 渲染 index.js
  • /about -> 渲染 about.js
  • /products -> 渲染 products/index.js
  • /products/:id -> 渲染 products/[id].js
    开发者无需手动编写路由表,只需专注于页面组件的开发即可。

总结

@tanstack/router 的核心优势在于其简洁的 API 和强大的功能支持。无论是通过基础使用示例快速上手,还是利用约定式路由简化复杂项目的路由管理,它都能为开发者提供高效的解决方案。对于现代前端应用而言,@tanstack/router 是一个值得尝试的路由库,尤其适合追求开发效率和代码可维护性的团队。
原理浅析
wouter 相较于 react-router,同样有他的一些优势,包括但不限于以下几点:

  1. 轻量化设计与零依赖性
    wouter 的核心设计理念是追求极致的轻量化。相较于 react-router 这样功能全面但相对复杂的路由库,wouter 的体积更小(通常只有几 KB),并且没有任何外部依赖。这种特性使得它非常适合用于小型项目、快速原型开发或需要严格控制 bundle size 的场景。开发者无需担心引入庞大的第三方库对项目性能造成额外负担。
  2. 简单易用的 API
    wouter 提供了更加简洁和直观的 API 设计,降低了学习成本。例如,它的 <Router><Route> 组件使用方式与 HTML 原生标签非常接近,初学者可以快速上手而无需深入理解复杂的路由概念。此外,wouter 支持基于 Hook 的编程模式,通过 useRoute 等自定义 Hook,开发者能够以更灵活的方式管理路由状态,同时保持代码的可读性和维护性。
  3. 无缝集成现代 React 特性
    wouter 充分利用了 React 的最新特性,例如 Hooks 和 Context API,从而实现了高效的路由管理。与 react-router 不同的是,wouter 并未采用复杂的内部架构,而是直接依赖 React 的原生能力来完成路由逻辑。这不仅减少了冗余代码,还提高了运行效率。对于熟悉 React 新特性的开发者来说,这种实现方式显得更加自然且易于调试。
  4. 动态路由支持与灵活性
    尽管 wouter 的体积较小,但它仍然提供了强大的动态路由支持。通过简单的路径匹配规则,开发者可以轻松定义嵌套路由、参数化路由以及通配符路由。与此同时,wouter 允许用户根据需求自由扩展其功能,例如结合自定义中间件或拦截器实现特定的业务逻辑。这种灵活性使其在应对多样化需求时表现出色。
  5. 默认支持 Suspense 和懒加载
    在现代前端开发中,性能优化是一个重要课题。wouter 内置了对 React Suspense 和懒加载的支持,使得开发者可以方便地延迟加载组件,从而进一步提升应用的初始渲染速度。相比之下,react-router 虽然也支持类似的特性,但往往需要额外配置才能达到同样的效果。
  6. 社区活跃度与生态友好性
    虽然 wouter 的生态规模不及 react-router,但其开源社区始终保持较高的活跃度,并且文档详尽、示例丰富。对于大多数常见问题,开发者都可以快速找到解决方案。此外,wouter 设计之初就考虑到了与其他工具链的兼容性,因此无论是 Next.js、Gatsby 还是普通的 CRA 项目,都能够无障碍地集成 wouter。
    综上所述,wouter 凭借其轻量级、易用性和高效性,在某些场景下展现出独特的优势。尽管它可能无法完全取代 react-router 在大型复杂项目中的地位,但对于中小型项目或需要快速迭代的团队而言,无疑是一个值得尝试的选择。

wouter

特点
  • 最小依赖,仅2.1KB (gzip 压缩后)对比 React Router 的18.7 KB。
  • 同时支持 React和 Preact!阅读"Preact 支持"部分以了解更多详情。
  • 没有顶级的 组件,它是完全可选的。
  • 模仿 React Router 的最佳实践,提供熟悉的 Route、Link、Switch 和 Redirect 组件。
  • 拥有基于 hook 的 API,用于更细粒度地控制路由(如动画):useLocation、 useRoute 和 useRouter .
原理代码](https://link.juejin.cn?target= "")

相关推荐
Oriel5 分钟前
Strapi对接OSS:私有链接导致富文本图片过期问题的解决方案
前端
noodb软件工作室14 分钟前
支持中文搜索的markdown轻量级笔记flatnotes来了
前端·后端
xiaominlaopodaren17 分钟前
React 服务端组件(RSC):从入门到原理的全面解析
react.js
张童瑶19 分钟前
Vue Electron 使用来给若依系统打包成exe程序,出现登录成功但是不跳转页面(已解决)
javascript·vue.js·electron
火柴就是我31 分钟前
每日见闻之<script type="module"> 的含义与作用
javascript
Catfood_Eason33 分钟前
HTML5 盒子模型
前端·html
小李小李不讲道理38 分钟前
「Ant Design 组件库探索」二:Tag组件
前端·react.js·ant design
1024小神42 分钟前
在rust中执行命令行输出中文乱码解决办法
前端·javascript
wordbaby43 分钟前
React Router v7 中的 `Layout` 组件工作原理
前端·react.js
旺仔牛仔QQ糖44 分钟前
Vue为普通函数添加防抖功能(基于Pinia 插件为action 配置防抖功能 引发思考)
前端·vue.js