[{"data":1,"prerenderedAt":1007},["ShallowReactive",2],{"page-\u002Fplugin\u002Fpinia的设计模式":3},{"id":4,"title":5,"body":6,"description":12,"extension":997,"meta":998,"navigation":106,"path":1003,"seo":1004,"stem":1005,"__hash__":1006},"content\u002Fplugin\u002FPinia的设计模式.md","Pinia的设计模式",{"type":7,"value":8,"toc":992},"minimark",[9,13,17,20,31,34,306,309,312,315,318,321,324,503,506,636,639,642,649,657,660,678,988],[10,11,12],"p",{},"pinia的核心原理是使用vue的核心响应式系统包装一个状态对象，用闭包管理store实例，这个和composable的思想是一致的，用插件机制扩展能力",[14,15,16],"h2",{"id":16},"单例模式的实现",[10,18,19],{},"Pinia是通过单例模式实现，无论在应用的哪个组件调用useStore，拿到的都是同一个store实例，状态共享、响应式同步，它的单例实现比较巧妙，核心是用全局变量缓存已经创建的store实例，而不是靠javascript的类单例或者模块单例。",[10,21,22,23,27,28,30],{},"Pinia会在内部维护一个全局的Map，比如",[24,25,26],"code",{},"pinia._s","用来缓存所有已经创建了的store，当调用useStore的时候，会通过id去",[24,29,26],{},"里查找，如果有就返回，没有就创建，这样无论调用多少次都用于返回一个实例。",[10,32,33],{},"下面是一个简化后的逻辑：",[35,36,41],"pre",{"className":37,"code":38,"language":39,"meta":40,"style":40},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F Pinia 内部简化逻辑\nfunction createPinia() {\n  const pinia = {\n    _s: new Map(),  \u002F\u002F 全局缓存：store id → store 实例\n\n    install(app) {\n      \u002F\u002F 把 pinia 挂到 app 上，供全局访问\n      app.config.globalProperties.$pinia = pinia\n    },\n  }\n  return pinia\n}\n\nfunction useStore(id) {\n  const pinia = getCurrentPinia()  \u002F\u002F 获取当前应用的 pinia 实例\n\n  \u002F\u002F 1. 先查缓存\n  if (pinia._s.has(id)) {\n    return pinia._s.get(id)\n  }\n\n  \u002F\u002F 2. 没有就创建\n  const store = createStore(id)\n  pinia._s.set(id, store)  \u002F\u002F 存入缓存\n  return store\n}\n","ts","",[24,42,43,52,67,83,101,108,124,130,142,148,154,162,168,173,188,206,211,217,232,247,252,257,263,278,293,301],{"__ignoreMap":40},[44,45,48],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"sJ8bj","\u002F\u002F Pinia 内部简化逻辑\n",[44,53,55,59,63],{"class":46,"line":54},2,[44,56,58],{"class":57},"szBVR","function",[44,60,62],{"class":61},"sScJk"," createPinia",[44,64,66],{"class":65},"sVt8B","() {\n",[44,68,70,73,77,80],{"class":46,"line":69},3,[44,71,72],{"class":57},"  const",[44,74,76],{"class":75},"sj4cs"," pinia",[44,78,79],{"class":57}," =",[44,81,82],{"class":65}," {\n",[44,84,86,89,92,95,98],{"class":46,"line":85},4,[44,87,88],{"class":65},"    _s: ",[44,90,91],{"class":57},"new",[44,93,94],{"class":61}," Map",[44,96,97],{"class":65},"(),  ",[44,99,100],{"class":50},"\u002F\u002F 全局缓存：store id → store 实例\n",[44,102,104],{"class":46,"line":103},5,[44,105,107],{"emptyLinePlaceholder":106},true,"\n",[44,109,111,114,117,121],{"class":46,"line":110},6,[44,112,113],{"class":61},"    install",[44,115,116],{"class":65},"(",[44,118,120],{"class":119},"s4XuR","app",[44,122,123],{"class":65},") {\n",[44,125,127],{"class":46,"line":126},7,[44,128,129],{"class":50},"      \u002F\u002F 把 pinia 挂到 app 上，供全局访问\n",[44,131,133,136,139],{"class":46,"line":132},8,[44,134,135],{"class":65},"      app.config.globalProperties.$pinia ",[44,137,138],{"class":57},"=",[44,140,141],{"class":65}," pinia\n",[44,143,145],{"class":46,"line":144},9,[44,146,147],{"class":65},"    },\n",[44,149,151],{"class":46,"line":150},10,[44,152,153],{"class":65},"  }\n",[44,155,157,160],{"class":46,"line":156},11,[44,158,159],{"class":57},"  return",[44,161,141],{"class":65},[44,163,165],{"class":46,"line":164},12,[44,166,167],{"class":65},"}\n",[44,169,171],{"class":46,"line":170},13,[44,172,107],{"emptyLinePlaceholder":106},[44,174,176,178,181,183,186],{"class":46,"line":175},14,[44,177,58],{"class":57},[44,179,180],{"class":61}," useStore",[44,182,116],{"class":65},[44,184,185],{"class":119},"id",[44,187,123],{"class":65},[44,189,191,193,195,197,200,203],{"class":46,"line":190},15,[44,192,72],{"class":57},[44,194,76],{"class":75},[44,196,79],{"class":57},[44,198,199],{"class":61}," getCurrentPinia",[44,201,202],{"class":65},"()  ",[44,204,205],{"class":50},"\u002F\u002F 获取当前应用的 pinia 实例\n",[44,207,209],{"class":46,"line":208},16,[44,210,107],{"emptyLinePlaceholder":106},[44,212,214],{"class":46,"line":213},17,[44,215,216],{"class":50},"  \u002F\u002F 1. 先查缓存\n",[44,218,220,223,226,229],{"class":46,"line":219},18,[44,221,222],{"class":57},"  if",[44,224,225],{"class":65}," (pinia._s.",[44,227,228],{"class":61},"has",[44,230,231],{"class":65},"(id)) {\n",[44,233,235,238,241,244],{"class":46,"line":234},19,[44,236,237],{"class":57},"    return",[44,239,240],{"class":65}," pinia._s.",[44,242,243],{"class":61},"get",[44,245,246],{"class":65},"(id)\n",[44,248,250],{"class":46,"line":249},20,[44,251,153],{"class":65},[44,253,255],{"class":46,"line":254},21,[44,256,107],{"emptyLinePlaceholder":106},[44,258,260],{"class":46,"line":259},22,[44,261,262],{"class":50},"  \u002F\u002F 2. 没有就创建\n",[44,264,266,268,271,273,276],{"class":46,"line":265},23,[44,267,72],{"class":57},[44,269,270],{"class":75}," store",[44,272,79],{"class":57},[44,274,275],{"class":61}," createStore",[44,277,246],{"class":65},[44,279,281,284,287,290],{"class":46,"line":280},24,[44,282,283],{"class":65},"  pinia._s.",[44,285,286],{"class":61},"set",[44,288,289],{"class":65},"(id, store)  ",[44,291,292],{"class":50},"\u002F\u002F 存入缓存\n",[44,294,296,298],{"class":46,"line":295},25,[44,297,159],{"class":57},[44,299,300],{"class":65}," store\n",[44,302,304],{"class":46,"line":303},26,[44,305,167],{"class":65},[10,307,308],{},"每个store定义的时候都有一个唯一的id，比如defineStore('counter', ...)里面的 coutner，这个Id就是缓存的key，同id的store永远只有一个实例，缓存挂在pinia实例上，而不是模块级的变量。这样就算一个页面里有多个Vue应用，每个应用也可以有独立的Pinia实例，互相不干扰。",[14,310,311],{"id":311},"ssr支持",[10,313,314],{},"pinia是支持ssr的，服务端渲染的时候，每个请求都会创建独立的pinia实例，避免不同请求之间的状态串扰。什么叫做pinia每个请求都会创建独立的pinia实例，ssr下，你什么时候又支持这个代码会在服务端执行？",[10,316,317],{},"因为ssr下，同一个vue应用的代码会在两个地方执行，首次请求是服务端，执行vue组件代码生成html字符串，首次响应之后客户端接管服务器生成的html，继续交互，后续导航也是在客户端执行。",[10,319,320],{},"我们知道，在一个vue应用，我们会",[10,322,323],{},"我们在vue组件的setup位置里执行的代码比如下面：",[35,325,329],{"className":326,"code":327,"language":328,"meta":40,"style":40},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup>\nimport { useCounterStore } from '@\u002Fstores\u002Fcounter'\n\nconst counter = useCounterStore()  \u002F\u002F ← 这行在服务端会执行\n\n\u002F\u002F 服务端会执行：获取数据\nawait counter.fetchData()          \u002F\u002F ← 这行在服务端会执行\n\n\u002F\u002F 客户端才会执行：操作 DOM\nonMounted(() => {\n  console.log('只在客户端执行')    \u002F\u002F ← 服务端不执行\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>{{ counter.count }}\u003C\u002Fdiv>   \u003C!-- 服务端会渲染成 HTML -->\n\u003C\u002Ftemplate>\n","vue",[24,330,331,346,361,365,383,387,392,408,412,417,430,449,454,463,467,476,495],{"__ignoreMap":40},[44,332,333,336,340,343],{"class":46,"line":47},[44,334,335],{"class":65},"\u003C",[44,337,339],{"class":338},"s9eBZ","script",[44,341,342],{"class":61}," setup",[44,344,345],{"class":65},">\n",[44,347,348,351,354,357],{"class":46,"line":54},[44,349,350],{"class":57},"import",[44,352,353],{"class":65}," { useCounterStore } ",[44,355,356],{"class":57},"from",[44,358,360],{"class":359},"sZZnC"," '@\u002Fstores\u002Fcounter'\n",[44,362,363],{"class":46,"line":69},[44,364,107],{"emptyLinePlaceholder":106},[44,366,367,370,373,375,378,380],{"class":46,"line":85},[44,368,369],{"class":57},"const",[44,371,372],{"class":75}," counter",[44,374,79],{"class":57},[44,376,377],{"class":61}," useCounterStore",[44,379,202],{"class":65},[44,381,382],{"class":50},"\u002F\u002F ← 这行在服务端会执行\n",[44,384,385],{"class":46,"line":103},[44,386,107],{"emptyLinePlaceholder":106},[44,388,389],{"class":46,"line":110},[44,390,391],{"class":50},"\u002F\u002F 服务端会执行：获取数据\n",[44,393,394,397,400,403,406],{"class":46,"line":126},[44,395,396],{"class":57},"await",[44,398,399],{"class":65}," counter.",[44,401,402],{"class":61},"fetchData",[44,404,405],{"class":65},"()          ",[44,407,382],{"class":50},[44,409,410],{"class":46,"line":132},[44,411,107],{"emptyLinePlaceholder":106},[44,413,414],{"class":46,"line":144},[44,415,416],{"class":50},"\u002F\u002F 客户端才会执行：操作 DOM\n",[44,418,419,422,425,428],{"class":46,"line":150},[44,420,421],{"class":61},"onMounted",[44,423,424],{"class":65},"(() ",[44,426,427],{"class":57},"=>",[44,429,82],{"class":65},[44,431,432,435,438,440,443,446],{"class":46,"line":156},[44,433,434],{"class":65},"  console.",[44,436,437],{"class":61},"log",[44,439,116],{"class":65},[44,441,442],{"class":359},"'只在客户端执行'",[44,444,445],{"class":65},")    ",[44,447,448],{"class":50},"\u002F\u002F ← 服务端不执行\n",[44,450,451],{"class":46,"line":164},[44,452,453],{"class":65},"})\n",[44,455,456,459,461],{"class":46,"line":170},[44,457,458],{"class":65},"\u003C\u002F",[44,460,339],{"class":338},[44,462,345],{"class":65},[44,464,465],{"class":46,"line":175},[44,466,107],{"emptyLinePlaceholder":106},[44,468,469,471,474],{"class":46,"line":190},[44,470,335],{"class":65},[44,472,473],{"class":338},"template",[44,475,345],{"class":65},[44,477,478,481,484,487,489,492],{"class":46,"line":208},[44,479,480],{"class":65},"  \u003C",[44,482,483],{"class":338},"div",[44,485,486],{"class":65},">{{ counter.count }}\u003C\u002F",[44,488,483],{"class":338},[44,490,491],{"class":65},">   ",[44,493,494],{"class":50},"\u003C!-- 服务端会渲染成 HTML -->\n",[44,496,497,499,501],{"class":46,"line":213},[44,498,458],{"class":65},[44,500,473],{"class":338},[44,502,345],{"class":65},[10,504,505],{},"里面的useCounterStore在服务端，可能就表现为：",[35,507,511],{"className":508,"code":509,"language":510,"meta":40,"style":40},"language-js shiki shiki-themes github-light github-dark","app.get('*', async (req, res) => {\n  const app = createSSRApp(App)       \u002F\u002F 1. 创建 Vue 应用\n  const pinia = createPinia()          \u002F\u002F 2. 每个请求新建 Pinia 实例\n  app.use(pinia)                       \u002F\u002F 3. 把 Pinia 挂到应用上\n\n  const html = await renderToString(app)  \u002F\u002F 4. 执行组件 setup()，这里会调用 useCounterStore()\n  res.send(html)\n})\n","js",[24,512,513,549,567,582,596,600,621,632],{"__ignoreMap":40},[44,514,515,518,520,522,525,528,531,534,537,539,542,545,547],{"class":46,"line":47},[44,516,517],{"class":65},"app.",[44,519,243],{"class":61},[44,521,116],{"class":65},[44,523,524],{"class":359},"'*'",[44,526,527],{"class":65},", ",[44,529,530],{"class":57},"async",[44,532,533],{"class":65}," (",[44,535,536],{"class":119},"req",[44,538,527],{"class":65},[44,540,541],{"class":119},"res",[44,543,544],{"class":65},") ",[44,546,427],{"class":57},[44,548,82],{"class":65},[44,550,551,553,556,558,561,564],{"class":46,"line":54},[44,552,72],{"class":57},[44,554,555],{"class":75}," app",[44,557,79],{"class":57},[44,559,560],{"class":61}," createSSRApp",[44,562,563],{"class":65},"(App)       ",[44,565,566],{"class":50},"\u002F\u002F 1. 创建 Vue 应用\n",[44,568,569,571,573,575,577,579],{"class":46,"line":69},[44,570,72],{"class":57},[44,572,76],{"class":75},[44,574,79],{"class":57},[44,576,62],{"class":61},[44,578,405],{"class":65},[44,580,581],{"class":50},"\u002F\u002F 2. 每个请求新建 Pinia 实例\n",[44,583,584,587,590,593],{"class":46,"line":85},[44,585,586],{"class":65},"  app.",[44,588,589],{"class":61},"use",[44,591,592],{"class":65},"(pinia)                       ",[44,594,595],{"class":50},"\u002F\u002F 3. 把 Pinia 挂到应用上\n",[44,597,598],{"class":46,"line":103},[44,599,107],{"emptyLinePlaceholder":106},[44,601,602,604,607,609,612,615,618],{"class":46,"line":110},[44,603,72],{"class":57},[44,605,606],{"class":75}," html",[44,608,79],{"class":57},[44,610,611],{"class":57}," await",[44,613,614],{"class":61}," renderToString",[44,616,617],{"class":65},"(app)  ",[44,619,620],{"class":50},"\u002F\u002F 4. 执行组件 setup()，这里会调用 useCounterStore()\n",[44,622,623,626,629],{"class":46,"line":126},[44,624,625],{"class":65},"  res.",[44,627,628],{"class":61},"send",[44,630,631],{"class":65},"(html)\n",[44,633,634],{"class":46,"line":132},[44,635,453],{"class":65},[10,637,638],{},"setup里的pinia的代码可能就会在服务端里创建这个实例，就会执行setup，创建和填充store，然后收集了所有的store状态之后，把状态序列化后注入html，返回给浏览器。",[10,640,641],{},"如果我们手写server.js，那么注入的是自己控制，如果在nuxt中的话，我们不需要手动序列化和注入，内部会有nitro和payload机制自动完成，具体是nuxt会在服务端执行页面组件之后，pinia的store状态会被nuxt的payload系统收集，我们只需要在nuxt.config.ts里面配置pinia模块就行。注入的位置可能是_prelaod.json或者内联__NUXT__脚本。",[10,643,644,645,648],{},"Nuxt 把状态合并进了它自己的 payload 系统，不会单独暴露一个 ",[24,646,647],{},"__PINIA_STATE__","。你可能会在 HTML 里看到类似：",[35,650,655],{"className":651,"code":653,"language":654},[652],"language-text","\u003Cscript type=\"application\u002Fjson\" id=\"__NUXT_DATA__\">[...]\u003C\u002Fscript>\n","text",[24,656,653],{"__ignoreMap":40},[14,658,659],{"id":659},"pinia的持久化",[10,661,662,663,669,670,673,674,677],{},"Pinia 官方没有内置持久化，但社区有成熟的插件 ",[664,665,666],"strong",{},[24,667,668],{},"pinia-plugin-persistedstate","，它把 store 状态自动同步到 ",[24,671,672],{},"localStorage"," 或 ",[24,675,676],{},"sessionStorage","。",[35,679,681],{"className":37,"code":680,"language":39,"meta":40,"style":40},"import { createPinia } from 'pinia'\nimport piniaPluginPersistedstate from 'pinia-plugin-persistedstate'\n\nconst pinia = createPinia()\npinia.use(piniaPluginPersistedstate)\napp.use(pinia)\n\n\u002F\u002F store里启用\nexport const useCounterStore = defineStore('counter', {\n  state: () => ({ count: 0, name: 'Alice' }),\n  persist: true,  \u002F\u002F 整个 store 都持久化\n})\n\n\u002F\u002F 精细控制\nexport const useUserStore = defineStore('user', {\n  state: () => ({\n    token: '',\n    profile: {},\n    tempData: {},\n  }),\n  persist: {\n    key: 'my-user',              \u002F\u002F 存储的 key，默认是 store id\n    storage: sessionStorage,     \u002F\u002F 存储方式，默认 localStorage\n    pick: ['token', 'profile'],  \u002F\u002F 只持久化这两个字段\n    \u002F\u002F 或者用 omit 排除\n    \u002F\u002F omit: ['tempData'],\n    serializer: {                \u002F\u002F 自定义序列化\n      serialize: JSON.stringify,\n      deserialize: JSON.parse,\n    },\n  },\n})\n",[24,682,683,695,707,711,724,734,743,747,752,775,800,814,818,822,827,847,858,869,874,879,884,889,903,911,930,935,940,949,961,972,977,983],{"__ignoreMap":40},[44,684,685,687,690,692],{"class":46,"line":47},[44,686,350],{"class":57},[44,688,689],{"class":65}," { createPinia } ",[44,691,356],{"class":57},[44,693,694],{"class":359}," 'pinia'\n",[44,696,697,699,702,704],{"class":46,"line":54},[44,698,350],{"class":57},[44,700,701],{"class":65}," piniaPluginPersistedstate ",[44,703,356],{"class":57},[44,705,706],{"class":359}," 'pinia-plugin-persistedstate'\n",[44,708,709],{"class":46,"line":69},[44,710,107],{"emptyLinePlaceholder":106},[44,712,713,715,717,719,721],{"class":46,"line":85},[44,714,369],{"class":57},[44,716,76],{"class":75},[44,718,79],{"class":57},[44,720,62],{"class":61},[44,722,723],{"class":65},"()\n",[44,725,726,729,731],{"class":46,"line":103},[44,727,728],{"class":65},"pinia.",[44,730,589],{"class":61},[44,732,733],{"class":65},"(piniaPluginPersistedstate)\n",[44,735,736,738,740],{"class":46,"line":110},[44,737,517],{"class":65},[44,739,589],{"class":61},[44,741,742],{"class":65},"(pinia)\n",[44,744,745],{"class":46,"line":126},[44,746,107],{"emptyLinePlaceholder":106},[44,748,749],{"class":46,"line":132},[44,750,751],{"class":50},"\u002F\u002F store里启用\n",[44,753,754,757,760,762,764,767,769,772],{"class":46,"line":144},[44,755,756],{"class":57},"export",[44,758,759],{"class":57}," const",[44,761,377],{"class":75},[44,763,79],{"class":57},[44,765,766],{"class":61}," defineStore",[44,768,116],{"class":65},[44,770,771],{"class":359},"'counter'",[44,773,774],{"class":65},", {\n",[44,776,777,780,783,785,788,791,794,797],{"class":46,"line":150},[44,778,779],{"class":61},"  state",[44,781,782],{"class":65},": () ",[44,784,427],{"class":57},[44,786,787],{"class":65}," ({ count: ",[44,789,790],{"class":75},"0",[44,792,793],{"class":65},", name: ",[44,795,796],{"class":359},"'Alice'",[44,798,799],{"class":65}," }),\n",[44,801,802,805,808,811],{"class":46,"line":156},[44,803,804],{"class":65},"  persist: ",[44,806,807],{"class":75},"true",[44,809,810],{"class":65},",  ",[44,812,813],{"class":50},"\u002F\u002F 整个 store 都持久化\n",[44,815,816],{"class":46,"line":164},[44,817,453],{"class":65},[44,819,820],{"class":46,"line":170},[44,821,107],{"emptyLinePlaceholder":106},[44,823,824],{"class":46,"line":175},[44,825,826],{"class":50},"\u002F\u002F 精细控制\n",[44,828,829,831,833,836,838,840,842,845],{"class":46,"line":190},[44,830,756],{"class":57},[44,832,759],{"class":57},[44,834,835],{"class":75}," useUserStore",[44,837,79],{"class":57},[44,839,766],{"class":61},[44,841,116],{"class":65},[44,843,844],{"class":359},"'user'",[44,846,774],{"class":65},[44,848,849,851,853,855],{"class":46,"line":208},[44,850,779],{"class":61},[44,852,782],{"class":65},[44,854,427],{"class":57},[44,856,857],{"class":65}," ({\n",[44,859,860,863,866],{"class":46,"line":213},[44,861,862],{"class":65},"    token: ",[44,864,865],{"class":359},"''",[44,867,868],{"class":65},",\n",[44,870,871],{"class":46,"line":219},[44,872,873],{"class":65},"    profile: {},\n",[44,875,876],{"class":46,"line":234},[44,877,878],{"class":65},"    tempData: {},\n",[44,880,881],{"class":46,"line":249},[44,882,883],{"class":65},"  }),\n",[44,885,886],{"class":46,"line":254},[44,887,888],{"class":65},"  persist: {\n",[44,890,891,894,897,900],{"class":46,"line":259},[44,892,893],{"class":65},"    key: ",[44,895,896],{"class":359},"'my-user'",[44,898,899],{"class":65},",              ",[44,901,902],{"class":50},"\u002F\u002F 存储的 key，默认是 store id\n",[44,904,905,908],{"class":46,"line":265},[44,906,907],{"class":65},"    storage: sessionStorage,     ",[44,909,910],{"class":50},"\u002F\u002F 存储方式，默认 localStorage\n",[44,912,913,916,919,921,924,927],{"class":46,"line":280},[44,914,915],{"class":65},"    pick: [",[44,917,918],{"class":359},"'token'",[44,920,527],{"class":65},[44,922,923],{"class":359},"'profile'",[44,925,926],{"class":65},"],  ",[44,928,929],{"class":50},"\u002F\u002F 只持久化这两个字段\n",[44,931,932],{"class":46,"line":295},[44,933,934],{"class":50},"    \u002F\u002F 或者用 omit 排除\n",[44,936,937],{"class":46,"line":303},[44,938,939],{"class":50},"    \u002F\u002F omit: ['tempData'],\n",[44,941,943,946],{"class":46,"line":942},27,[44,944,945],{"class":65},"    serializer: {                ",[44,947,948],{"class":50},"\u002F\u002F 自定义序列化\n",[44,950,952,955,958],{"class":46,"line":951},28,[44,953,954],{"class":65},"      serialize: ",[44,956,957],{"class":75},"JSON",[44,959,960],{"class":65},".stringify,\n",[44,962,964,967,969],{"class":46,"line":963},29,[44,965,966],{"class":65},"      deserialize: ",[44,968,957],{"class":75},[44,970,971],{"class":65},".parse,\n",[44,973,975],{"class":46,"line":974},30,[44,976,147],{"class":65},[44,978,980],{"class":46,"line":979},31,[44,981,982],{"class":65},"  },\n",[44,984,986],{"class":46,"line":985},32,[44,987,453],{"class":65},[989,990,991],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":40,"searchDepth":54,"depth":54,"links":993},[994,995,996],{"id":16,"depth":54,"text":16},{"id":311,"depth":54,"text":311},{"id":659,"depth":54,"text":659},"md",{"date":999,"tags":1000},"2026-10-11",[1001,1002],"plugin","pinia","\u002Fplugin\u002Fpinia的设计模式",{"description":12},"plugin\u002FPinia的设计模式","Bn1PRPBv-JwoczXvxxTwJ0lmeeTLPM3GPKJg_wTY-CI",1791740440629]