vue-page-store 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +334 -84
- package/dist/index.cjs.js +202 -110
- package/dist/index.d.ts +95 -71
- package/dist/index.esm.js +202 -110
- package/dist/index.umd.js +202 -110
- package/dist/index.umd.min.js +13 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# vue-page-store
|
|
2
2
|
|
|
3
|
-
> Vue 2.6 页面级作用域运行时容器 ——
|
|
3
|
+
> Vue 2.6 页面级作用域运行时容器 —— source、state、getters、actions、watch、init/enter/leave,一个页面作用域全收。
|
|
4
4
|
|
|
5
5
|
## 它是什么
|
|
6
6
|
|
|
@@ -8,26 +8,30 @@
|
|
|
8
8
|
|
|
9
9
|
一个 `definePageStore` 定义一个 **Page Scope** —— 它统一管理这个页面作用域内的:
|
|
10
10
|
|
|
11
|
-
- **
|
|
11
|
+
- **source** — 页面输入 / 原始返回(如路由参数、接口响应)
|
|
12
|
+
- **state** — 响应式业务状态
|
|
12
13
|
- **getters** — 派生计算
|
|
13
14
|
- **actions** — 业务逻辑
|
|
14
15
|
- **watch** — 声明式副作用
|
|
15
|
-
- **
|
|
16
|
+
- **init** — 一次性初始化(拉字典、注册事件监听等)
|
|
17
|
+
- **enter / leave** — 页面可见性生命周期
|
|
18
|
+
- **$setInterval** — 页面级定时器托管
|
|
16
19
|
- **event bus** — 页面内作用域通信
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
页面离开时可以自动清理页面级定时器,页面销毁时 `$destroy` 一键回收,不污染全局。
|
|
19
22
|
|
|
20
23
|
## 它不是什么
|
|
21
24
|
|
|
22
|
-
- **不是 Vuex / Pinia 替代品** — 全局状态(用户信息、权限、路由)请继续用 Vuex
|
|
25
|
+
- **不是 Vuex / Pinia 替代品** — 全局状态(用户信息、权限、路由)请继续用 Vuex / Pinia
|
|
23
26
|
- **不是全局状态管理方案** — 它的作用域是"页面",不是"应用"
|
|
27
|
+
- **不是大而全的框架** — 它只解决复杂页面的页面层状态编排
|
|
24
28
|
|
|
25
|
-
| | Vuex | vue-page-store |
|
|
29
|
+
| | Vuex / Pinia | vue-page-store |
|
|
26
30
|
|---|---|---|
|
|
27
31
|
| 作用域 | 全局 | 页面 |
|
|
28
|
-
| 生命周期 | 跟随应用 |
|
|
32
|
+
| 生命周期 | 跟随应用 | 跟随页面可见性 / 页面实例 |
|
|
29
33
|
| 适合 | 用户信息、权限、路由状态 | 仪表盘、漏斗详情、大型配置页 |
|
|
30
|
-
| 销毁 | 通常不销毁 |
|
|
34
|
+
| 销毁 | 通常不销毁 | 页面离开 / 销毁时可回收 |
|
|
31
35
|
|
|
32
36
|
## 安装
|
|
33
37
|
|
|
@@ -42,48 +46,85 @@ npm install vue-page-store
|
|
|
42
46
|
### 1. 定义 store
|
|
43
47
|
|
|
44
48
|
```js
|
|
45
|
-
// stores/
|
|
49
|
+
// stores/order-list.js
|
|
46
50
|
import { definePageStore } from 'vue-page-store'
|
|
47
51
|
|
|
48
|
-
export const
|
|
52
|
+
export const useOrderStore = definePageStore('orderList', {
|
|
53
|
+
source: () => ({
|
|
54
|
+
response: null,
|
|
55
|
+
query: {},
|
|
56
|
+
}),
|
|
57
|
+
|
|
49
58
|
state: () => ({
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
keyword: '',
|
|
60
|
+
page: 1,
|
|
61
|
+
pageSize: 20,
|
|
62
|
+
selectedIds: [],
|
|
63
|
+
deleteDialogVisible: false,
|
|
53
64
|
}),
|
|
54
65
|
|
|
55
66
|
getters: {
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
list() {
|
|
68
|
+
return this.$source.response?.list || []
|
|
69
|
+
},
|
|
70
|
+
total() {
|
|
71
|
+
return this.$source.response?.total || 0
|
|
72
|
+
},
|
|
73
|
+
hasSelection() {
|
|
74
|
+
return this.selectedIds.length > 0
|
|
75
|
+
},
|
|
76
|
+
showEmpty() {
|
|
77
|
+
return !this.$loading.search && this.list.length === 0
|
|
78
|
+
}
|
|
58
79
|
},
|
|
59
80
|
|
|
60
81
|
actions: {
|
|
61
|
-
async
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
async search() {
|
|
83
|
+
const res = await api.getOrders({
|
|
84
|
+
keyword: this.keyword,
|
|
85
|
+
page: this.page,
|
|
86
|
+
pageSize: this.pageSize,
|
|
87
|
+
})
|
|
88
|
+
this.$source.response = res
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async batchDelete() {
|
|
92
|
+
await api.deleteOrders(this.selectedIds)
|
|
93
|
+
this.selectedIds = []
|
|
94
|
+
this.deleteDialogVisible = false
|
|
95
|
+
this.search()
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
openDeleteDialog() {
|
|
99
|
+
this.deleteDialogVisible = true
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
closeDeleteDialog() {
|
|
103
|
+
this.deleteDialogVisible = false
|
|
68
104
|
}
|
|
69
105
|
},
|
|
70
106
|
|
|
71
107
|
watch: {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.fetchData()
|
|
75
|
-
},
|
|
76
|
-
// 对象写法 — 显式 deep
|
|
77
|
-
'filters': {
|
|
78
|
-
handler(val) { this.fetchData() },
|
|
79
|
-
deep: true
|
|
108
|
+
keyword() {
|
|
109
|
+
this.page = 1
|
|
80
110
|
}
|
|
81
111
|
},
|
|
82
112
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
113
|
+
// 只执行一次:拉下拉框选项、注册事件监听等
|
|
114
|
+
init() {
|
|
115
|
+
this.loadDictOptions()
|
|
116
|
+
this.$on('child:refresh', () => this.search())
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
// 每次页面可见时执行
|
|
120
|
+
enter() {
|
|
121
|
+
this.$source.query = this.$vm.$route.query
|
|
122
|
+
this.search()
|
|
123
|
+
this.$setInterval(() => this.search(), 5000)
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
leave() {
|
|
127
|
+
// interval 会自动清理
|
|
87
128
|
}
|
|
88
129
|
})
|
|
89
130
|
```
|
|
@@ -91,13 +132,13 @@ export const useFunnelStore = definePageStore('funnelDetail', {
|
|
|
91
132
|
### 2. 页面组件中使用
|
|
92
133
|
|
|
93
134
|
```js
|
|
94
|
-
//
|
|
95
|
-
import {
|
|
135
|
+
// OrderListPage.vue
|
|
136
|
+
import { useOrderStore } from './stores/order-list'
|
|
96
137
|
|
|
97
138
|
export default {
|
|
98
139
|
created() {
|
|
99
|
-
// 传入 this →
|
|
100
|
-
this.pageStore =
|
|
140
|
+
// 传入 this → 自动绑定 init/enter/leave + 自动 provide + 页面销毁时自动回收
|
|
141
|
+
this.pageStore = useOrderStore(this)
|
|
101
142
|
}
|
|
102
143
|
}
|
|
103
144
|
```
|
|
@@ -105,16 +146,17 @@ export default {
|
|
|
105
146
|
### 3. 子组件中使用
|
|
106
147
|
|
|
107
148
|
```js
|
|
108
|
-
// FilterPanel.vue — 不需要 import
|
|
149
|
+
// FilterPanel.vue — 不需要 import store 文件
|
|
109
150
|
export default {
|
|
110
151
|
inject: ['pageStore'],
|
|
111
152
|
mounted() {
|
|
112
|
-
this.pageStore.
|
|
153
|
+
this.pageStore.search()
|
|
113
154
|
}
|
|
114
155
|
}
|
|
115
156
|
```
|
|
116
157
|
|
|
117
|
-
所有页面统一用 `this.pageStore`,所有子组件统一 `inject: ['pageStore']
|
|
158
|
+
所有页面统一用 `this.pageStore`,所有子组件统一 `inject: ['pageStore']`。
|
|
159
|
+
不需要知道父页面用的哪个 store 定义,零耦合。
|
|
118
160
|
|
|
119
161
|
## API
|
|
120
162
|
|
|
@@ -126,11 +168,14 @@ export default {
|
|
|
126
168
|
|
|
127
169
|
| 字段 | 类型 | 说明 |
|
|
128
170
|
|---|---|---|
|
|
129
|
-
| `state` | `() => Object` |
|
|
171
|
+
| `state` | `() => Object` | **必填**,业务状态工厂函数 |
|
|
172
|
+
| `source` | `() => Object` | 页面输入 / 原始返回工厂函数 |
|
|
130
173
|
| `getters` | `{ [key]: function }` | 派生计算,`this` 指向 store |
|
|
131
174
|
| `actions` | `{ [key]: function }` | 业务方法,`this` 指向 store |
|
|
132
175
|
| `watch` | `{ [path]: handler \| options }` | 声明式 watcher,支持 dot-path |
|
|
133
|
-
| `
|
|
176
|
+
| `init` | `function` | store 创建后一次性调用,`$vm` 已可用。适合拉字典、注册事件监听 |
|
|
177
|
+
| `enter` | `function` | 页面进入可见 / 可交互状态时触发 |
|
|
178
|
+
| `leave` | `function` | 页面离开可见 / 可交互状态时触发 |
|
|
134
179
|
|
|
135
180
|
### Store 实例属性与方法
|
|
136
181
|
|
|
@@ -138,11 +183,15 @@ export default {
|
|
|
138
183
|
|---|---|
|
|
139
184
|
| `store.xxx` | 直接访问 state 字段 |
|
|
140
185
|
| `store.$state` | 原始响应式 state 对象 |
|
|
186
|
+
| `store.$source` | 原始响应式 source 对象 |
|
|
187
|
+
| `store.$loading` | action loading 状态对象,如 `store.$loading.search` |
|
|
141
188
|
| `store.$status` | `{ mounted, active }` 响应式状态 |
|
|
142
189
|
| `store.$disposed` | store 是否已销毁 |
|
|
143
190
|
| `store.$id` | store 唯一标识 |
|
|
191
|
+
| `store.$vm` | 绑定的页面组件实例(只读逃生口) |
|
|
144
192
|
| `store.$patch(partial \| fn)` | 批量更新 state(浅合并) |
|
|
145
|
-
| `store.$reset()` | 重置到 `state()` 初始值,清除动态字段 |
|
|
193
|
+
| `store.$reset()` | 重置到 `state()` + `source()` 初始值,清除动态字段 |
|
|
194
|
+
| `store.$setInterval(fn, delay)` | 注册页面级 interval,leave / destroy 自动清理 |
|
|
146
195
|
| `store.$emit(event, payload)` | 发射事件(当前 store 作用域) |
|
|
147
196
|
| `store.$on(event, handler)` | 订阅事件,返回取消函数 |
|
|
148
197
|
| `store.$off(event, handler?)` | 取消订阅 |
|
|
@@ -165,19 +214,208 @@ watch: {
|
|
|
165
214
|
}
|
|
166
215
|
```
|
|
167
216
|
|
|
168
|
-
##
|
|
217
|
+
## source 与 state
|
|
218
|
+
|
|
219
|
+
v0.4 引入了 `source`,用于把"页面输入 / 原始返回"和"业务状态"分开。
|
|
220
|
+
|
|
221
|
+
### 推荐分工
|
|
222
|
+
|
|
223
|
+
- **source**:路由参数、接口原始响应、页面输入上下文
|
|
224
|
+
- **state**:keyword、分页、选中项、弹窗状态、表单草稿等业务状态
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
source: () => ({
|
|
228
|
+
response: null,
|
|
229
|
+
query: {},
|
|
230
|
+
}),
|
|
231
|
+
|
|
232
|
+
state: () => ({
|
|
233
|
+
keyword: '',
|
|
234
|
+
page: 1,
|
|
235
|
+
selectedIds: [],
|
|
236
|
+
})
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 为什么要分开
|
|
240
|
+
|
|
241
|
+
- 原始返回不再和业务状态混在一起
|
|
242
|
+
- getters 可以同时基于 `this.$source` 和 `this.xxx` 计算
|
|
243
|
+
- `$reset()` 时 source / state 一起恢复,更清晰
|
|
244
|
+
|
|
245
|
+
## init / enter / leave
|
|
246
|
+
|
|
247
|
+
v0.4 用 `enter / leave` 替换了 v0.3 的 `lifecycle.mount / unmount / activate / deactivate`。
|
|
248
|
+
|
|
249
|
+
v0.4.1 新增 `init`,用于 store 创建后的一次性初始化。
|
|
250
|
+
|
|
251
|
+
### 语义
|
|
252
|
+
|
|
253
|
+
- **init**:store 创建后一次性调用,`$vm` 已可用,DOM 未就绪
|
|
254
|
+
- **enter**:页面进入可见 / 可交互状态
|
|
255
|
+
- **leave**:页面离开可见 / 可交互状态
|
|
256
|
+
|
|
257
|
+
### 执行时序
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
created() 开始
|
|
261
|
+
└→ useStore(this)
|
|
262
|
+
└→ createStoreInstance() ← state/source/getters/actions 就绪
|
|
263
|
+
└→ bindTo(this) ← $vm 赋值
|
|
264
|
+
└→ ★ init() ← $vm 可用,只执行一次
|
|
265
|
+
└→ created() 剩余代码
|
|
266
|
+
mounted()
|
|
267
|
+
└→ ★ enter() ← DOM 就绪,每次可见都执行
|
|
268
|
+
|
|
269
|
+
--- keep-alive 切走 ---
|
|
270
|
+
deactivated()
|
|
271
|
+
└→ clearAllIntervals()
|
|
272
|
+
└→ ★ leave()
|
|
273
|
+
|
|
274
|
+
--- keep-alive 切回 ---
|
|
275
|
+
activated()
|
|
276
|
+
└→ ★ enter() ← 重新开轮询、刷数据
|
|
277
|
+
|
|
278
|
+
--- 页面销毁 ---
|
|
279
|
+
beforeDestroy()
|
|
280
|
+
└→ ★ leave()(如果还没 leave)
|
|
281
|
+
└→ $destroy()
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 分工原则
|
|
285
|
+
|
|
286
|
+
| 钩子 | 执行次数 | $vm | DOM | 典型场景 |
|
|
287
|
+
|---|---|---|---|---|
|
|
288
|
+
| `init` | 一次 | ✅ | ❌ | 拉下拉框选项、注册事件监听、从 localStorage 恢复配置、初始化 WebSocket |
|
|
289
|
+
| `enter` | 每次可见 | ✅ | ✅ | 读路由参数、刷列表数据、开轮询 |
|
|
290
|
+
| `leave` | 每次离开 | ✅ | ✅ | 通常不需要写,interval 已自动清理 |
|
|
291
|
+
|
|
292
|
+
### keep-alive 行为
|
|
293
|
+
|
|
294
|
+
- 首次 `mounted` → `enter`
|
|
295
|
+
- `activated` → `enter`
|
|
296
|
+
- `deactivated` → `leave`
|
|
297
|
+
- `beforeDestroy` → 如果当前还没 leave,先 leave,再 `$destroy`
|
|
298
|
+
|
|
299
|
+
### 适合放在 init 里的逻辑
|
|
300
|
+
|
|
301
|
+
- 拉下拉框 / 字典选项(只需要一次)
|
|
302
|
+
- 注册 `$on` 监听 store 内部事件
|
|
303
|
+
- 从 localStorage 恢复上次的筛选条件
|
|
304
|
+
- 初始化 WebSocket / EventSource 连接
|
|
305
|
+
- 根据用户权限裁剪 columns / 按钮配置
|
|
306
|
+
|
|
307
|
+
### 适合放在 enter 里的逻辑
|
|
308
|
+
|
|
309
|
+
- 根据 `$route` 初始化 source / state(keep-alive 切回时路由参数可能变了)
|
|
310
|
+
- 首屏加载 / 刷新列表数据
|
|
311
|
+
- 启动页面轮询
|
|
312
|
+
|
|
313
|
+
```js
|
|
314
|
+
init() {
|
|
315
|
+
this.loadDictOptions()
|
|
316
|
+
this.$on('child:refresh', () => this.search())
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
enter() {
|
|
320
|
+
this.$source.query = this.$vm.$route.query
|
|
321
|
+
this.search()
|
|
322
|
+
this.$setInterval(() => this.search(), 5000)
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
leave() {
|
|
326
|
+
// interval 自动清理
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## `$setInterval`
|
|
331
|
+
|
|
332
|
+
后台页面经常有轮询 / 倒计时需求,v0.4 提供 `$setInterval(fn, delay)` 统一托管页面级 interval。
|
|
333
|
+
|
|
334
|
+
### 特性
|
|
335
|
+
|
|
336
|
+
- 返回 `stop` 函数,可手动停止
|
|
337
|
+
- `leave` 时自动清理所有已注册 interval
|
|
338
|
+
- `$destroy()` 时兜底清理
|
|
339
|
+
- `enter` 时**不会自动恢复**,需要你自己重新注册
|
|
340
|
+
|
|
341
|
+
```js
|
|
342
|
+
enter() {
|
|
343
|
+
this.$setInterval(() => {
|
|
344
|
+
this.search()
|
|
345
|
+
}, 5000)
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## 异步 action 与 `$loading`
|
|
350
|
+
|
|
351
|
+
v0.4 对返回 Promise 的 action 自动追踪 loading 状态。
|
|
352
|
+
|
|
353
|
+
你不需要额外包装器,直接写普通 async 函数即可:
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
actions: {
|
|
357
|
+
async search() {
|
|
358
|
+
const res = await api.getOrders(...)
|
|
359
|
+
this.$source.response = res
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
模板中可以直接使用:
|
|
365
|
+
|
|
366
|
+
```html
|
|
367
|
+
<!-- 搜索:只显示 loading -->
|
|
368
|
+
<el-button
|
|
369
|
+
:loading="pageStore.$loading.search"
|
|
370
|
+
@click="pageStore.search"
|
|
371
|
+
>
|
|
372
|
+
搜索
|
|
373
|
+
</el-button>
|
|
374
|
+
|
|
375
|
+
<!-- 保存:UI 层自己决定是否禁用 -->
|
|
376
|
+
<el-button
|
|
377
|
+
:loading="pageStore.$loading.save"
|
|
378
|
+
:disabled="pageStore.$loading.save"
|
|
379
|
+
@click="pageStore.save"
|
|
380
|
+
>
|
|
381
|
+
保存
|
|
382
|
+
</el-button>
|
|
383
|
+
```
|
|
169
384
|
|
|
170
|
-
|
|
385
|
+
### 说明
|
|
386
|
+
|
|
387
|
+
- 框架只做 **loading 追踪**
|
|
388
|
+
- **不自动跳过重复调用**
|
|
389
|
+
- 是否防重复,由 UI 层通过 `:disabled="pageStore.$loading.xxx"` 自己决定
|
|
390
|
+
|
|
391
|
+
## State / Source Shape 规则
|
|
392
|
+
|
|
393
|
+
### state
|
|
394
|
+
|
|
395
|
+
`state()` 返回值定义了推荐的业务状态边界:
|
|
171
396
|
|
|
172
397
|
- **推荐**:在 `state()` 中声明完整字段,即使初始值为 `null` 或空数组
|
|
173
398
|
- **允许**:通过 `$patch` 动态新增字段(会写入 `$state`,但不会自动成为 `store.xxx` 顶层代理)
|
|
174
399
|
- **注意**:`$reset()` 会清除所有不在 `state()` 中的动态字段
|
|
175
400
|
|
|
401
|
+
### source
|
|
402
|
+
|
|
403
|
+
`source()` 返回值定义了页面输入 / 原始返回的初始 shape:
|
|
404
|
+
|
|
405
|
+
- **推荐**:把常见 source 字段预先声明出来,如 `response`、`query`
|
|
406
|
+
- **允许**:运行时动态给 `$source` 增加字段
|
|
407
|
+
- **注意**:`$reset()` 同样会清除所有不在 `source()` 中的动态字段
|
|
408
|
+
|
|
176
409
|
```js
|
|
410
|
+
source: () => ({
|
|
411
|
+
response: null,
|
|
412
|
+
query: {},
|
|
413
|
+
}),
|
|
414
|
+
|
|
177
415
|
state: () => ({
|
|
178
416
|
filters: {},
|
|
179
|
-
|
|
180
|
-
detail: null
|
|
417
|
+
selectedIds: [],
|
|
418
|
+
detail: null,
|
|
181
419
|
})
|
|
182
420
|
```
|
|
183
421
|
|
|
@@ -203,15 +441,15 @@ state: () => ({
|
|
|
203
441
|
|
|
204
442
|
## 适用场景
|
|
205
443
|
|
|
206
|
-
- 仪表盘页面
|
|
207
|
-
-
|
|
208
|
-
- 大型配置页
|
|
209
|
-
- keep-alive 业务页
|
|
210
|
-
- 微前端子应用
|
|
444
|
+
- 仪表盘页面 —— 多模块共享筛选条件、加载状态
|
|
445
|
+
- 漏斗 / 留存等分析详情页 —— 复杂交互 + 异步数据 + 页面可见性管理
|
|
446
|
+
- 大型配置页 —— 多 tab / 多步骤表单的状态统一管理
|
|
447
|
+
- keep-alive 业务页 —— 需要 init / enter / leave 感知的页面
|
|
448
|
+
- 微前端子应用 —— 页面作用域隔离,不污染宿主全局状态
|
|
211
449
|
|
|
212
450
|
## 不适用场景
|
|
213
451
|
|
|
214
|
-
- 全局用户信息、权限、路由等 → 用 Vuex
|
|
452
|
+
- 全局用户信息、权限、路由等 → 用 Vuex / Pinia
|
|
215
453
|
- 简单页面的小 data 管理 → 用组件 data 就够了
|
|
216
454
|
- 需要同 id 多实例并存 → 当前版本不支持
|
|
217
455
|
|
|
@@ -222,11 +460,9 @@ state: () => ({
|
|
|
222
460
|
```js
|
|
223
461
|
actions: {
|
|
224
462
|
async fetchData() {
|
|
225
|
-
this.loading = true
|
|
226
463
|
const data = await api.getData()
|
|
227
464
|
// 即使页面已销毁,下面的赋值也会被自动静默,不会报错
|
|
228
|
-
this.
|
|
229
|
-
this.loading = false
|
|
465
|
+
this.$source.response = data
|
|
230
466
|
}
|
|
231
467
|
}
|
|
232
468
|
```
|
|
@@ -246,52 +482,66 @@ storeRegistry.forEach((store, id) => {
|
|
|
246
482
|
})
|
|
247
483
|
```
|
|
248
484
|
|
|
249
|
-
## 从 v0.
|
|
485
|
+
## 从 v0.3.x 升级
|
|
250
486
|
|
|
251
487
|
### Breaking Changes
|
|
252
488
|
|
|
253
|
-
**1.
|
|
254
|
-
|
|
255
|
-
v0.2.x:只恢复已有字段的值,动态新增字段会残留。
|
|
256
|
-
|
|
257
|
-
v0.3.0:完全恢复到 `state()` 的 shape,动态字段会被移除。
|
|
258
|
-
|
|
259
|
-
**2. `watch` 默认不再 deep**
|
|
489
|
+
**1. `lifecycle` 被移除,改为 `init` / `enter` / `leave`**
|
|
260
490
|
|
|
261
|
-
v0.
|
|
262
|
-
|
|
263
|
-
v0.3.0:默认 `deep: false`。如果你的 watcher 依赖深层变化检测,需要显式加 `deep: true`。
|
|
491
|
+
v0.3.x:
|
|
264
492
|
|
|
265
493
|
```js
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
494
|
+
lifecycle: {
|
|
495
|
+
mount() {},
|
|
496
|
+
unmount() {},
|
|
497
|
+
activate() {},
|
|
498
|
+
deactivate() {}
|
|
269
499
|
}
|
|
500
|
+
```
|
|
270
501
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
502
|
+
v0.4.x:
|
|
503
|
+
|
|
504
|
+
```js
|
|
505
|
+
init() {
|
|
506
|
+
// 只执行一次的初始化(拉字典、注册事件等)
|
|
507
|
+
},
|
|
508
|
+
enter() {
|
|
509
|
+
// 每次可见时执行(替代 mount + activate)
|
|
510
|
+
},
|
|
511
|
+
leave() {
|
|
512
|
+
// 每次离开时执行(替代 deactivate + unmount)
|
|
277
513
|
}
|
|
278
514
|
```
|
|
279
515
|
|
|
280
|
-
|
|
516
|
+
迁移关系:
|
|
517
|
+
|
|
518
|
+
- `lifecycle.mount` → `enter`(如果包含一次性逻辑,拆到 `init`)
|
|
519
|
+
- `lifecycle.unmount` → `leave`
|
|
520
|
+
- `lifecycle.activate` → `enter`
|
|
521
|
+
- `lifecycle.deactivate` → `leave`
|
|
522
|
+
|
|
523
|
+
**2. `$reset()` 现在同时重置 source 和 state**
|
|
524
|
+
|
|
525
|
+
v0.4.0 中:
|
|
281
526
|
|
|
282
|
-
`
|
|
527
|
+
- `state` 恢复到 `state()` 初始值
|
|
528
|
+
- `source` 恢复到 `source()` 初始值
|
|
529
|
+
- 不在初始 shape 中的动态字段会被移除
|
|
283
530
|
|
|
284
531
|
### New Features
|
|
285
532
|
|
|
286
|
-
- `
|
|
287
|
-
- `
|
|
288
|
-
-
|
|
533
|
+
- `source`:页面输入 / 原始返回与业务状态分离
|
|
534
|
+
- `init`:store 创建后一次性钩子,`$vm` 已可用(v0.4.1)
|
|
535
|
+
- `enter / leave`:更简单的页面可见性生命周期
|
|
536
|
+
- `$setInterval()`:页面级 interval 托管
|
|
537
|
+
- `$loading.xxx`:返回 Promise 的 action 自动追踪 loading
|
|
538
|
+
- `$vm`:只读逃生口,可在 init / enter 中访问 `$route / $router`
|
|
289
539
|
|
|
290
540
|
## Roadmap
|
|
291
541
|
|
|
292
|
-
- **Plugin system** — 可扩展能力(logger、persist、loading tracker)
|
|
293
542
|
- **Keyed instance** — `useStore(vm, scopeKey)` 支持同定义多实例
|
|
294
|
-
- **Page cache strategy** — TTL、revalidate、stale-while-
|
|
543
|
+
- **Page cache strategy** — TTL、revalidate、stale-while-enter
|
|
544
|
+
- **More page runtime helpers** — 在不增加心智负担的前提下继续补页面层能力
|
|
295
545
|
|
|
296
546
|
## License
|
|
297
547
|
|