![](https://s2.loli.net/2022/09/12/vr3YeTIqUOztoFp.png)

需求分析

这是一个对话框页面。分为

  1. 对话列表
  2. 对话输入
  3. 角色选择

三个组件

对话列表(1)依赖对话输入(2)和角色选择(3)两个模块的内容。

在对话列表里面点击编辑的时候。 2 和 3 的内容也需要对应改变。

这样就形成了相互依赖

第一次尝试 - props

使用 props 传值。1 是父组件,2和3是子组件。设计一个 editId 用来表示是否在编辑某段话。如果editId 为0就表示新增。看起来挺简单也是挺符合要求的,但是写着写着,要处理的边界条件太多。props 一大堆。加上所有的状态都保存在1里面。导致代码十分长。不易于分辨。遂放弃这种方式

第二次尝试 - eventBus

由于没有事先在脑海里理清哪里需要传值。 一上来就写代码。导致后面越来越多的 on 和 emit。无法辨别值究竟是从哪里传过来的。又又放弃。

最后一次 - pinia

也就是用仓库的方式进行数据渲染。把状态, 事件什么的全丢 store 里面去。 这样方便管理多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { IDialog } from '@/types/Dialog';
import { defineStore } from 'pinia';
import { v4 as uuid } from 'uuid';
import { useRoleStore } from './role';

interface IState {
currentContent: string;
activeDialogId: string | null;
activeDialog: IDialog;
dialogList: IDialog[];
currentAction: 'insert' | 'delete' | 'edit' | 'upInsert' | 'downInsert';
}

export const useDialogStore = defineStore('dialog', {
state: (): IState => {
return {
currentContent: '',
activeDialogId: null,
activeDialog: {
roleAvatar: '',
roleId: 0,
roleName: '',
id: 0,
type: 'voiceover',
renderId: '',
content: '',
},
dialogList: [],
currentAction: 'insert',
};
},
getters: {
listLength(state) {
return state.dialogList.length;
},
},
actions: {
/** 当前编辑的对话框 ID */
changeActiveDialogId(value: string | null) {
this.$state.activeDialogId = value;
},
findRenderId() {
const renderId = this.$state.activeDialogId;
const index = this.$state.dialogList.findIndex(
(item) => item.renderId === renderId,
);
return index;
},
handleAction() {
const actionType = this.$state.currentAction;
const roleStore = useRoleStore();
const role = roleStore.activeRole;
const roleData = {
roleId: role.id,
roleName: role.name,
roleAvatar: role.avatar,
side: role.side,
};

const type = role.id === 0 ? 'voiceover' : 'text';

switch (actionType) {
case 'insert':
this.insert({
content: this.$state.currentContent,
renderId: uuid(),
...roleData,
type,
});
break;
case 'delete':
this.deleteDialog();
break;
case 'upInsert':
this.insertBefore({
content: this.$state.currentContent,
renderId: uuid(),
...roleData,
type,
});
break;
case 'downInsert':
this.insertAfter({
content: this.$state.currentContent,
renderId: uuid(),
...roleData,
type,
});
break;
case 'edit':
this.edit({
content: this.$state.currentContent,
renderId: this.$state.activeDialogId,
...roleData,
type,
})
break;
default:
break;
}
},
/** 删除一条对话 */
deleteDialog() {
const index = this.findRenderId();
if (index === -1) return;
this.$state.dialogList.splice(index, 1);
},
/** 最后插入一条 */
insert(data: IDialog) {
this.$state.dialogList.push(data);
this.$state.currentContent = '';
},
insertBefore(data: IDialog) {
const index = this.findRenderId();
if (index === -1) return;
this.$state.dialogList.splice(index, 0, data);
this.$state.currentContent = '';
},
insertAfter(data: IDialog) {
const index = this.findRenderId();
if (index === -1) return;
this.$state.dialogList.splice(index + 1, 0, data);
this.$state.currentContent = '';
},
edit(data: IDialog) {
const index = this.findRenderId();
if (index !== -1) {
this.$state.dialogList.splice(index, 1, data);
}
this.$state.currentContent = '';
this.$state.currentAction = 'insert';
},
},
});


为什么刚开始不选择 pinia。依照最前面说的。需求看起来挺简单的,所以没有直接选择 store 的方式, 没想到只是为了维护一个列表。有许多事件需要处理。

这是考虑不周的,在公司里的项目条件不算太多。 所有没有养成先文档后代码的习惯,现在到了自己的项目,要考虑的东西就多了起来,还是尽可能的先文档梳理一遍吧