2026 前端状态管理全景:从 Pinia 到 Signals 的演进之路

4428 字
22 分钟
2026 前端状态管理全景:从 Pinia 到 Signals 的演进之路

前言#

前端状态管理是一个「永恒的话题」。从 Vuex 到 Pinia,从 Redux 到 Zustand,从 MobX 到 Signals——每隔几年就会出现新的范式和工具。到了 2026 年,状态管理领域已经形成了清晰的格局:轻量化、去中心化、细粒度响应式成为主流趋势。

本文将全面对比 Pinia、Zustand、Jotai 和 Signals 四种主流方案,从 API 设计、响应式原理到实际选型建议,帮助你在 2026 年做出最合适的选择。

一、状态管理的演进历程#

1.1 从集中式到去中心化#

2015-2018: 集中式 Store
├── Vuex (Vue 生态)
├── Redux (通用,但主要配合 React)
└── 特点: 单一 Store、严格的 mutation、boilerplate 多
2019-2022: 轻量化浪潮
├── Pinia (Vue 3 官方推荐)
├── Zustand (极简 API)
├── Jotai (原子化)
└── 特点: 更少的 boilerplate、更灵活的组织方式
2023-2026: 细粒度响应式
├── Signals (TC39 提案 / 各框架实现)
├── Vue Vapor Mode (编译时优化)
├── Solid.js Signals (先驱)
└── 特点: 编译器优化、无虚拟 DOM、极致性能

1.2 核心问题始终未变#

无论工具怎么变,状态管理要解决的核心问题是一样的:

  1. 状态在哪里存储?(全局 Store / 原子 / 组件本地)
  2. 状态如何更新?(直接修改 / Action / 不可变更新)
  3. 谁需要响应变化?(订阅机制 / 细粒度依赖追踪)
  4. 如何避免不必要的重渲染?(选择器 / 计算属性 / Signals)

二、Pinia:Vue 生态的标准答案#

2.1 核心设计#

Pinia 是 Vue 3 的官方状态管理方案,它的设计哲学是「像写组合式函数一样写 Store」:

stores/cart.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
export const useCartStore = defineStore('cart', () => {
// State - 就是 ref
const items = ref<CartItem[]>([]);
const couponCode = ref<string | null>(null);
const discount = ref(0);
// Getters - 就是 computed
const totalItems = computed(() =>
items.value.reduce((sum, item) => sum + item.quantity, 0)
);
const subtotal = computed(() =>
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
);
const total = computed(() => {
const sub = subtotal.value;
return sub - sub * (discount.value / 100);
});
const isEmpty = computed(() => items.value.length === 0);
// Actions - 就是普通函数
function addItem(product: Omit<CartItem, 'quantity'>) {
const existing = items.value.find(item => item.id === product.id);
if (existing) {
existing.quantity++;
} else {
items.value.push({ ...product, quantity: 1 });
}
}
function removeItem(id: string) {
items.value = items.value.filter(item => item.id !== id);
}
function updateQuantity(id: string, quantity: number) {
const item = items.value.find(item => item.id === id);
if (item) {
if (quantity <= 0) {
removeItem(id);
} else {
item.quantity = quantity;
}
}
}
async function applyCoupon(code: string) {
// 异步 action 直接 async/await
const response = await fetch(`/api/coupons/${code}`);
if (!response.ok) {
throw new Error('Invalid coupon code');
}
const data = await response.json();
couponCode.value = code;
discount.value = data.discount;
}
function clearCart() {
items.value = [];
couponCode.value = null;
discount.value = 0;
}
return {
items, couponCode, discount,
totalItems, subtotal, total, isEmpty,
addItem, removeItem, updateQuantity, applyCoupon, clearCart,
};
});

2.2 Pinia 的响应式原理#

Pinia 的响应式核心就是 Vue 3 的 Reactivity 系统。理解这一点很重要——Pinia 并没有发明新的响应式机制,它只是提供了一种组织全局状态的方式。

// Vue 3 响应式系统的核心:Proxy
// 当你写 ref([]) 时,Vue 做了什么?
// 简化版 ref 实现
function ref(rawValue) {
return {
get value() {
// 读取时收集依赖(track)
track(this, 'value');
return rawValue;
},
set value(newValue) {
rawValue = newValue;
// 写入时触发更新(trigger)
trigger(this, 'value');
},
};
}
// 简化版 reactive 实现(Pinia 内部用 reactive 包装 state)
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
track(target, key); // 收集依赖
// 如果结果是对象,递归代理(懒代理)
if (typeof result === 'object' && result !== null) {
return reactive(result);
}
return result;
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
if (oldValue !== value) {
trigger(target, key); // 触发更新
}
return result;
},
});
}

Pinia Store 创建时的内部流程:

// Pinia 内部(简化)
function defineStore(id, setup) {
return function useStore() {
const pinia = inject(piniaSymbol);
if (!pinia._stores.has(id)) {
// 在 effectScope 中执行 setup,确保所有响应式效果可统一清理
const scope = effectScope(true);
const store = scope.run(() => {
const result = setup();
// 将所有 ref 和 reactive 包装到统一的 reactive 对象中
return result;
});
pinia._stores.set(id, store);
}
return pinia._stores.get(id);
};
}

2.3 Pinia 插件系统#

plugins/persistedState.ts
import type { PiniaPluginContext } from 'pinia';
export function piniaPersistedState(context: PiniaPluginContext) {
const { store } = context;
// 从 localStorage 恢复状态
const savedState = localStorage.getItem(`pinia-${store.$id}`);
if (savedState) {
store.$patch(JSON.parse(savedState));
}
// 监听状态变化并持久化
store.$subscribe((mutation, state) => {
localStorage.setItem(`pinia-${store.$id}`, JSON.stringify(state));
}, { detached: true }); // detached: 组件卸载后仍保持订阅
}
// main.ts
import { createPinia } from 'pinia';
import { piniaPersistedState } from './plugins/persistedState';
const pinia = createPinia();
pinia.use(piniaPersistedState);

三、Zustand:极简主义的胜利#

3.1 核心理念#

Zustand 的哲学是极致简单——没有 Provider、没有 Context、没有 boilerplate。一个函数创建 Store,一个 Hook 消费状态。

stores/counter.ts
import { create } from 'zustand';
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
incrementBy: (amount: number) => void;
}
export const useCounterStore = create<CounterState>((set, get) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
incrementBy: (amount) => set((state) => ({ count: state.count + amount })),
}));

3.2 Zustand 的内部实现原理#

Zustand 的源码极其精简(核心不到 100 行),其核心是发布-订阅模式

// Zustand 核心实现(简化版)
type SetState<T> = (partial: Partial<T> | ((state: T) => Partial<T>)) => void;
type GetState<T> = () => T;
type Listener<T> = (state: T, prevState: T) => void;
function createStore<T>(createState: (set: SetState<T>, get: GetState<T>) => T) {
let state: T;
const listeners = new Set<Listener<T>>();
const getState: GetState<T> = () => state;
const setState: SetState<T> = (partial) => {
const prevState = state;
const nextPartial = typeof partial === 'function' ? partial(state) : partial;
// 浅合并(不是深合并!)
const nextState = Object.assign({}, state, nextPartial);
if (!Object.is(nextState, state)) {
state = nextState;
// 通知所有订阅者
listeners.forEach((listener) => listener(state, prevState));
}
};
const subscribe = (listener: Listener<T>) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
// 初始化状态
state = createState(setState, getState);
return { getState, setState, subscribe };
}

注意一个关键点:Zustand 使用浅合并(shallow merge),而不是像 Pinia 那样的 Proxy 深度响应式。这意味着嵌套对象的更新需要显式创建新引用:

// ❌ 这不会触发更新(直接修改嵌套对象)
set((state) => {
state.user.name = 'Alice'; // 浅合并检测不到嵌套变化
return state;
});
// ✅ 正确方式:创建新引用
set((state) => ({
user: { ...state.user, name: 'Alice' },
}));

3.3 中间件模式#

Zustand 的中间件采用高阶函数组合:

import { create } from 'zustand';
import { devtools, persist, subscribeWithSelector } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
interface TodoState {
todos: Array<{ id: number; text: string; done: boolean }>;
addTodo: (text: string) => void;
toggleTodo: (id: number) => void;
}
export const useTodoStore = create<TodoState>()(
devtools(
persist(
immer(
subscribeWithSelector((set) => ({
todos: [],
addTodo: (text) =>
set((state) => {
// immer 中间件允许直接修改(内部产生不可变更新)
state.todos.push({
id: Date.now(),
text,
done: false,
});
}),
toggleTodo: (id) =>
set((state) => {
const todo = state.todos.find((t) => t.id === id);
if (todo) todo.done = !todo.done;
}),
}))
),
{ name: 'todo-storage' } // persist 配置
),
{ name: 'TodoStore' } // devtools 配置
)
);
// 精确订阅:只在 todos 长度变化时触发
useTodoStore.subscribe(
(state) => state.todos.length,
(length, prevLength) => {
console.log(`Todo count changed: ${prevLength}${length}`);
}
);

四、Jotai:原子化状态管理#

4.1 原子化思想#

Jotai 的灵感来自 Recoil,但更加简洁。它的核心概念是原子(Atom)——每个状态都是一个独立的原子,原子之间可以组合派生。

import { atom } from 'jotai';
// 基础原子
const countAtom = atom(0);
const nameAtom = atom('World');
// 派生原子(只读)
const greetingAtom = atom((get) => {
const name = get(nameAtom);
const count = get(countAtom);
return `Hello, ${name}! You clicked ${count} times.`;
});
// 可写派生原子
const incrementAtom = atom(
null, // 读取值为 null(只写原子)
(get, set) => {
set(countAtom, get(countAtom) + 1);
}
);
// 异步原子
const userAtom = atom(async () => {
const response = await fetch('/api/user');
return response.json();
});
// 带缓存的异步原子
const userByIdAtom = atom(async (get) => {
const id = get(userIdAtom);
const response = await fetch(`/api/users/${id}`);
return response.json();
});

4.2 Jotai 的依赖追踪原理#

Jotai 的核心是一个基于图的依赖追踪系统

// Jotai 内部原理(简化)
class Store {
// 每个原子的当前值
private atomValues = new WeakMap<Atom, unknown>();
// 依赖图:原子 A 依赖了哪些原子
private atomDependencies = new WeakMap<Atom, Set<Atom>>();
// 反向依赖:谁依赖了原子 A
private atomDependents = new WeakMap<Atom, Set<Atom>>();
// 订阅者(UI 组件)
private atomSubscribers = new WeakMap<Atom, Set<() => void>>();
get<T>(atom: Atom<T>): T {
if (typeof atom.read === 'function') {
// 派生原子:执行 read 函数并追踪依赖
const dependencies = new Set<Atom>();
const getter = (depAtom: Atom) => {
dependencies.add(depAtom);
// 注册反向依赖
this.addDependent(depAtom, atom);
return this.get(depAtom);
};
const value = atom.read(getter);
this.atomDependencies.set(atom, dependencies);
this.atomValues.set(atom, value);
return value as T;
}
// 基础原子:直接返回值
return (this.atomValues.get(atom) ?? atom.init) as T;
}
set<T>(atom: Atom<T>, value: T): void {
const prevValue = this.atomValues.get(atom);
if (Object.is(prevValue, value)) return;
this.atomValues.set(atom, value);
// 通知所有依赖此原子的派生原子重新计算
this.notifyDependents(atom);
// 通知 UI 订阅者
this.notifySubscribers(atom);
}
private notifyDependents(atom: Atom): void {
const dependents = this.atomDependents.get(atom);
if (!dependents) return;
for (const dependent of dependents) {
// 重新计算派生原子
this.get(dependent);
// 递归通知
this.notifyDependents(dependent);
this.notifySubscribers(dependent);
}
}
}

4.3 实用模式#

import { atom } from 'jotai';
import { atomWithStorage, atomWithDefault, splitAtom } from 'jotai/utils';
// 持久化原子 - 自动同步到 localStorage
const themeAtom = atomWithStorage('theme', 'light');
// 带默认值的异步原子
const configAtom = atomWithDefault(async () => {
const res = await fetch('/api/config');
return res.json();
});
// 列表拆分 - 每个列表项成为独立原子
interface Todo {
id: number;
text: string;
done: boolean;
}
const todosAtom = atom<Todo[]>([]);
const todoAtomsAtom = splitAtom(todosAtom);
// todoAtomsAtom 的值是 Atom<Todo>[] —— 每个 todo 是独立原子
// 修改单个 todo 不会导致整个列表重新渲染
// 族原子 - 参数化创建
const todoAtomFamily = (id: number) =>
atom(
(get) => get(todosAtom).find((t) => t.id === id),
(get, set, update: Partial<Todo>) => {
set(todosAtom, (prev) =>
prev.map((t) => (t.id === id ? { ...t, ...update } : t))
);
}
);

五、Signals:响应式的未来#

5.1 什么是 Signals?#

Signals 是一种细粒度响应式原语,最早由 Solid.js 推广,现在已成为 TC39 Stage 1 提案,多个框架都提供了自己的实现。

Signals 的核心理念:值的变化应该自动、精确地传播到使用它的地方,无需虚拟 DOM diff。

// TC39 Signal 提案的 API(2026 年规范草案)
// 注意:实际语法可能随提案演进而变化
// 基础 Signal
const count = new Signal.State(0);
console.log(count.get()); // 0
count.set(1);
console.log(count.get()); // 1
// 计算 Signal(自动追踪依赖)
const doubled = new Signal.Computed(() => count.get() * 2);
console.log(doubled.get()); // 2
// 当 count 变化时,doubled 自动更新
count.set(5);
console.log(doubled.get()); // 10

5.2 Signals 的响应式原理#

Signals 的核心是自动依赖追踪 + 惰性求值 + 推拉混合更新

// Signals 内部原理(简化实现)
let currentComputed: Computed | null = null;
class Signal<T> {
private value: T;
private subscribers = new Set<Computed>();
private version = 0;
constructor(initialValue: T) {
this.value = initialValue;
}
get(): T {
// 如果当前有 Computed 正在执行,自动注册依赖
if (currentComputed) {
this.subscribers.add(currentComputed);
currentComputed.dependencies.add(this);
}
return this.value;
}
set(newValue: T): void {
if (Object.is(this.value, newValue)) return;
this.value = newValue;
this.version++;
// 通知所有依赖的 Computed:你的依赖变了,标记为脏
for (const sub of this.subscribers) {
sub.markDirty();
}
}
}
class Computed<T> {
private value: T | undefined;
private dirty = true;
private fn: () => T;
dependencies = new Set<Signal>();
private subscribers = new Set<Computed>();
constructor(fn: () => T) {
this.fn = fn;
}
get(): T {
// 自动依赖追踪
if (currentComputed) {
this.subscribers.add(currentComputed);
}
// 惰性求值:只在被读取且标记为脏时才重新计算
if (this.dirty) {
this.recompute();
}
return this.value!;
}
markDirty(): void {
if (!this.dirty) {
this.dirty = true;
// 级联标记下游为脏
for (const sub of this.subscribers) {
sub.markDirty();
}
}
}
private recompute(): void {
// 清除旧依赖
for (const dep of this.dependencies) {
dep.subscribers?.delete(this);
}
this.dependencies.clear();
// 设置当前追踪上下文
const prev = currentComputed;
currentComputed = this;
try {
this.value = this.fn();
} finally {
currentComputed = prev;
}
this.dirty = false;
}
}
// 效果(副作用)
class Effect {
private fn: () => void;
private dirty = true;
dependencies = new Set<Signal>();
constructor(fn: () => void) {
this.fn = fn;
this.run(); // 立即执行一次以收集依赖
}
run(): void {
const prev = currentComputed;
currentComputed = this as any;
try {
this.fn();
} finally {
currentComputed = prev;
}
this.dirty = false;
}
markDirty(): void {
if (!this.dirty) {
this.dirty = true;
// 调度异步执行(微任务)
queueMicrotask(() => {
if (this.dirty) this.run();
});
}
}
}

5.3 Vue 的 Signals 演进:Vapor Mode#

Vue 的 Vapor Mode 是 Signals 理念在 Vue 生态中的体现——编译时优化,绕过虚拟 DOM,直接操作 DOM

<!-- 传统 Vue 组件 -->
<script setup>
import { ref, computed } from 'vue';
const count = ref(0);
const doubled = computed(() => count.value * 2);
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Doubled: {{ doubled }}</p>
<button @click="count++">+1</button>
</div>
</template>
// Vapor Mode 编译后(概念性示例)
// 不再生成虚拟 DOM,直接生成 DOM 操作指令
import { ref, computed, renderEffect, setText, on } from 'vue/vapor';
export default () => {
const count = ref(0);
const doubled = computed(() => count.value * 2);
// 直接创建 DOM 节点
const div = document.createElement('div');
const p1 = document.createElement('p');
const p2 = document.createElement('p');
const button = document.createElement('button');
// 细粒度绑定:只更新变化的文本节点
renderEffect(() => setText(p1, `Count: ${count.value}`));
renderEffect(() => setText(p2, `Doubled: ${doubled.value}`));
button.textContent = '+1';
on(button, 'click', () => count.value++);
div.append(p1, p2, button);
return div;
};

5.4 Solid.js 的 Signals(成熟实现参考)#

虽然本文不聚焦 Solid.js 框架本身,但它的 Signals 实现是目前最成熟的参考:

// Solid.js 风格的 Signals(框架无关的理解)
import { createSignal, createMemo, createEffect, batch } from 'solid-js';
// 基础信号
const [count, setCount] = createSignal(0);
const [name, setName] = createSignal('World');
// 派生计算(自动追踪依赖)
const greeting = createMemo(() => `Hello ${name()}, count is ${count()}`);
// 副作用(自动追踪并在依赖变化时重新执行)
createEffect(() => {
console.log(greeting()); // 当 count 或 name 变化时自动执行
});
// 批量更新(避免中间状态触发多次计算)
batch(() => {
setCount(10);
setName('Alice');
// effect 只会执行一次
});

六、四大方案对比#

6.1 API 设计对比#

// === Pinia ===
// 定义
const useStore = defineStore('id', () => {
const count = ref(0);
const doubled = computed(() => count.value * 2);
const increment = () => count.value++;
return { count, doubled, increment };
});
// 使用(Vue 组件中)
const store = useStore();
store.increment();
console.log(store.count, store.doubled);
// === Zustand ===
// 定义
const useStore = create((set, get) => ({
count: 0,
doubled: () => get().count * 2, // 注意:不是自动计算的
increment: () => set((s) => ({ count: s.count + 1 })),
}));
// 使用
const count = useStore((s) => s.count); // 选择器
// === Jotai ===
// 定义
const countAtom = atom(0);
const doubledAtom = atom((get) => get(countAtom) * 2);
const incrementAtom = atom(null, (get, set) => {
set(countAtom, get(countAtom) + 1);
});
// 使用
const [count, setCount] = useAtom(countAtom);
const doubled = useAtomValue(doubledAtom);
// === Signals (TC39) ===
// 定义
const count = new Signal.State(0);
const doubled = new Signal.Computed(() => count.get() * 2);
// 使用
count.set(count.get() + 1);
console.log(doubled.get());

6.2 性能特性对比#

特性 | Pinia | Zustand | Jotai | Signals
-------------|------------|------------|------------|------------
响应式粒度 | 属性级 | Store 级 | 原子级 | 值级
依赖追踪 | 自动(Proxy)| 手动(选择器)| 自动 | 自动
更新传播 | Push | Pull | Push+Pull | Push+Pull(惰性)
虚拟DOM | 需要 | 需要 | 需要 | 不需要
SSR支持 | 优秀 | 良好 | 良好 | 框架依赖
DevTools | Vue DevTools| Redux DT | Jotai DT | 发展中
TypeScript | 优秀 | 优秀 | 优秀 | 优秀
包体积 | ~2KB | ~1KB | ~3KB | 0(原生)

6.3 更新性能的本质差异#

// 假设有 1000 个组件订阅了同一个 Store
// Store 中有 100 个属性,但只更新了 1 个属性
// Pinia (Vue):
// - Proxy 精确追踪到哪些组件用了哪个属性
// - 只有用到被修改属性的组件会重新渲染
// - 但仍需经过虚拟 DOM diff
// Zustand:
// - 依赖开发者写选择器来避免不必要的重渲染
// - 没写选择器 → 所有消费者都会被通知
// - 有 shallow 比较优化
// Jotai:
// - 每个原子独立,更新一个原子只影响订阅了它的组件
// - 天然细粒度,不需要手动优化
// Signals:
// - 最细粒度:更新直接传播到使用该值的 DOM 节点
// - 跳过虚拟 DOM diff
// - 理论上是性能最优的方案

七、选型建议#

7.1 决策树#

你用 Vue 吗?
├── 是 → Pinia(官方方案,生态最好)
│ └── 需要极致性能?→ 关注 Vue Vapor Mode
└── 否 → 你的状态结构是怎样的?
├── 集中式大 Store → Zustand(简单直接)
├── 分散的独立状态 → Jotai(原子化更自然)
└── 追求极致性能 → Signals(Solid.js 等)

7.2 具体场景建议#

// 场景 1: Vue 3 中大型项目
// 推荐: Pinia
// 理由: 官方支持、DevTools 完美集成、团队学习成本低
const useAuthStore = defineStore('auth', () => { /* ... */ });
const useCartStore = defineStore('cart', () => { /* ... */ });
// 场景 2: 需要跨框架共享状态
// 推荐: Zustand 或 Signals
// 理由: 框架无关,可以在任何环境中使用
const store = createStore((set) => ({
theme: 'light',
toggleTheme: () => set((s) => ({
theme: s.theme === 'light' ? 'dark' : 'light'
})),
}));
// 场景 3: 表单状态管理(大量独立字段)
// 推荐: Jotai
// 理由: 每个字段是独立原子,修改一个字段不会触发其他字段重渲染
const nameAtom = atom('');
const emailAtom = atom('');
const ageAtom = atom(0);
const formValidAtom = atom((get) => {
return get(nameAtom).length > 0 && get(emailAtom).includes('@');
});
// 场景 4: 高频更新的实时数据(如股票、游戏)
// 推荐: Signals
// 理由: 最小化更新开销,跳过虚拟 DOM
const price = new Signal.State(100.0);
const change = new Signal.Computed(() => {
const p = price.get();
return ((p - 100) / 100 * 100).toFixed(2) + '%';
});

八、未来趋势#

8.1 编译器驱动的优化#

2026 年的明确趋势是:运行时响应式正在向编译时优化迁移。

  • Vue Vapor Mode 在编译时分析模板,生成直接的 DOM 操作代码
  • Svelte 5 的 Runes 将响应式变成编译时特性
  • Signals TC39 提案一旦进入规范,所有框架都可以基于原生实现优化

8.2 状态管理的「消失」#

最好的状态管理是你感觉不到它的存在。随着框架和语言层面对细粒度响应式的支持越来越好,独立的状态管理库可能会变得越来越薄——它们会聚焦在组织结构开发体验上,而不是响应式机制本身。

总结#

方案适合场景核心优势主要局限
PiniaVue 生态官方支持、DX 好绑定 Vue
Zustand需要简单方案极简、灵活需手动优化选择器
Jotai分散独立状态原子化、自动优化心智模型较新
Signals追求极致性能最细粒度、无 VDOM生态尚在发展

没有银弹。选择状态管理方案的关键不是「哪个最好」,而是「哪个最适合你的项目、团队和场景」。理解每种方案的原理和取舍,才能做出真正有依据的决策。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

2026 前端状态管理全景:从 Pinia 到 Signals 的演进之路
https://boke.hackerdream.xyz/posts/frontend-state-management-2026/
作者
晴天
发布于
2026-03-18
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
晴天
Hello, I'm 晴天.
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
125
分类
17
标签
287
总字数
257,955
运行时长
0
最后活动
0 天前

目录