Inertia.js 持久布局实现原理
这段代码是 Inertia.js 专属的持久布局方案 ,核心原理是:把布局组件作为页面组件的静态属性挂载,让 Inertia 框架在渲染时复用同一个布局,而非每次切换页面都重新创建 / 销毁布局。
jsx
import Layout from './Layout'
const Welcome = ({ user }) => {
return (
<>
<h1>Welcome</h1>
<p>Hello {user.name}, welcome to your first Inertia app!</p>
</>
)
}
Welcome.layout = Layout
export default Welcome
1. 先看代码做了什么
jsx
// 1. 导入布局组件(整个页面的外壳:导航、侧边栏、页脚等)
import Layout from './Layout'
// 2. 定义页面组件(只有页面内容:欢迎语)
const Welcome = ({ user }) => {
return (
<>
<h1>Welcome</h1>
<p>Hello {user.name}, welcome to your first Inertia app!</p>
</>
)
}
// 3. 关键:把 Layout 赋值给 Welcome 的静态属性 layout
Welcome.layout = Layout
// 4. 导出页面组件
export default Welcome
核心动作 :给页面组件 Welcome 绑定了一个静态属性 layout,值就是你的布局组件。
2. 底层核心原理(Inertia 渲染机制)
Inertia 是单页应用(SPA) 框架,它不会像传统多页应用那样刷新整个浏览器 ,而是通过客户端路由局部更新页面内容。
它的渲染流程是这样的:
-
框架层统一渲染:Inertia 有一个根渲染器,负责渲染所有页面;
-
读取页面布局 :渲染前,先检查当前页面组件是否有
layout静态属性; -
嵌套渲染:
- 有
layout→ 用布局组件包裹页面组件渲染; - 无
layout→ 直接渲染页面组件;
- 有
-
持久化关键:
- 切换页面时,布局组件只会创建一次;
- 只有布局内部的页面内容(子组件)会被替换;
- 布局的状态、DOM 节点、事件监听完全保留,不销毁、不重建。
3. 为什么这叫「持久布局」?
对比两种渲染方式,你立刻就懂:
❌ 传统方案(非持久)
每个页面自己写布局:
jsx
// Welcome 页面
const Welcome = () => {
return (
<Layout> {/* 每次渲染都新建一个 Layout */}
<h1>Welcome</h1>
</Layout>
)
}
切换页面时:旧布局销毁 → 新布局创建,导航 / 侧边栏会重新渲染,状态丢失,体验差。
✅ Inertia 方案(持久)
jsx
Welcome.layout = Layout
切换页面时:
- 布局组件始终保留在 DOM 中(不卸载、不重绘);
- 只有
<h1>Welcome</h1>这部分内容被替换; - 布局的状态(如折叠侧边栏、滚动位置)完全保留。
这就是持久布局 的本质:布局只初始化一次,全局复用,页面切换不影响布局。
4. 补充:Layout 组件长什么样?
为了让你彻底理解,布局组件通常是这样的:
jsx
// Layout.js
const Layout = ({ children }) => {
return (
<div className="layout">
{/* 公共导航栏(持久不变) */}
<nav>导航栏</nav>
{/* 页面内容(切换页面时这里会变) */}
<main>{children}</main>
{/* 公共页脚(持久不变) */}
<footer>页脚</footer>
</div>
)
}
export default Layout
children就是你的页面组件(Welcome 等);- 导航 / 页脚是持久部分 ,
children是动态切换部分。
5. 极简总结
-
原理一句话:
给页面组件绑定静态
layout属性,Inertia 框架识别后,全局复用布局组件,只更新页面内容
-
核心优势:
布局不销毁、不重建,状态保留,页面切换更流畅,是 SPA 最佳实践。
-
为什么用静态属性:
不污染组件实例,让框架能直接读取布局配置,简洁高效。
总结
- 实现方式:
页面组件.layout = 布局组件(静态属性绑定) - 核心原理:Inertia 统一渲染,布局复用,内容替换
- 最终效果:真正的持久化布局,SPA 流畅体验
彻底搞懂 JS 静态属性、实例属性、静态方法、实例方法
JS 新手最容易混淆的知识点。
先给你一个总纲,记住这个就不会乱:
- 静态:属于类本身,直接用 类名。调用
- 实例:属于对象,必须 new 之后,用 对象。调用
一、先看最核心的区别(一句话)
| 类型 | 归属 | 调用方式 | 关键词 |
|---|---|---|---|
| 静态属性 / 方法 | 属于类 / 构造函数本身 | 类名.属性 类名.方法() |
static |
| 实例属性 / 方法 | 属于new 出来的对象 | 对象.属性 对象.方法() |
无 / this |
二、用最简单的代码讲清楚
我们用一个 User 类来举例:
1. 静态属性 / 静态方法
加了 static → 属于类,不属于某个具体对象
所有对象共享这一个属性 / 方法。
jsx
class User {
// 静态属性
static className = "用户类";
// 静态方法
static getInfo() {
return "我是静态方法,属于 User 类";
}
}
// ✅ 直接用 类名. 调用
console.log(User.className); // "用户类"
console.log(User.getInfo()); // "我是静态方法..."
// ❌ 不能用对象调用(会报错/undefined)
const user = new User();
console.log(user.className); // undefined
2. 实例属性 / 实例方法
不加 static → 属于 new 出来的对象
每个对象都有自己独立的一份。
jsx
class User {
// 实例属性
name = "张三";
// 实例方法
sayHi() {
return `你好,我是 ${this.name}`;
}
}
// ❌ 不能用类名调用
console.log(User.name); // 不是你想要的
// ✅ 必须 new 出对象,用 对象. 调用
const user = new User();
console.log(user.name); // "张三"
console.log(user.sayHi()); // "你好,我是张三"
三、回到React 组件的静态属性
jsx
const Welcome = () => { ... }
// 给 Welcome 这个函数,挂一个静态属性 layout
Welcome.layout = Layout;
这里的本质:
- Welcome 是一个函数(组件本质就是函数 / 类)
Welcome.layout就是给函数本身挂一个静态属性- 不属于组件渲染出来的对象 ,属于组件函数本身
- Inertia 直接读取
Welcome.layout就能拿到布局,不需要渲染组件
这就是为什么要用静态属性:
想让框架在渲染组件之前,就能读取到组件的配置(布局)
四、最关键的一张图
类/函数(Welcome)
↳ 静态属性/方法(Welcome.layout)
↑ 直接访问
↳ new 创建实例(组件渲染对象)
↳ 实例属性/方法(this.xxx)
↑ 必须用对象访问
五、常见使用场景
1. 静态属性 / 方法 用在什么地方?
- 工具方法(不需要创建对象就能用)
- 全局共享配置
- 组件配置(React/Vue 里的 layout、title、权限)
- 例子:
axios.defaults、Math.random()都是静态
2. 实例属性 / 方法 用在什么地方?
- 每个对象独立的数据(用户姓名、年龄、状态)
- 组件内部的
this.state、this.props - 组件里的事件处理函数
六、你最容易混淆的 3 个问题
1. 静态属性能被实例继承 / 访问吗?
不能!
实例访问不到静态属性,静态属性只属于类。
2. 静态方法里能用 this 吗?
能用,但 this 指向的是类,不是实例!
jsx
class User {
static className = "123";
static fn() {
console.log(this.className); // 这里 this = User
}
}
3. 为什么 React 组件要用静态属性?
因为:
- 我们不想把布局变成组件的内部状态
- 我们想让框架直接读取组件本身的配置
- 这是一种组件元信息(描述组件自身的信息)
最终极简总结
-
静态(static) :属于类 / 函数本身 ,直接
类名.调用,共享一份 -
实例 :属于new 出来的对象 ,必须
对象.调用,每个对象独立 -
你的代码
Welcome.layout = Layout:就是给 Welcome 组件函数挂一个静态属性,让 Inertia 框架直接读取。