一次 vue 跨组件通信方法的选择

一次 vue 跨组件通信方法的选择

需求分析

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

  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
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
的方式, 没想到只是为了维护一个列表。有许多事件需要处理。

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