返回介绍

互访 Store

发布于 2024-09-11 01:11:55 字数 6428 浏览 0 评论 0 收藏 0

新建一个模型类,代码如下所示:

src/model/ModelMessage.ts

import { ModalBase } from './ModalBase';

export class ModelMessage extends ModalBase {
  createTime?: number;
  receiveTime?: number;
  messageContent?: string;
  chatId?: string;
  fromName?: string;
  avatar?: string;
  // 是否为传入消息
  isInMsg?: boolean;
}

创建 useMessageStore,用于管理消息的状态数据,代码如下:

src/renderer/store/useMessageStore.ts

import { ModelChat } from '../../model/ModelChat';
import { ModelMessage } from '../../model/ModelMessage';
import { defineStore } from 'pinia';
import { ref, Ref } from 'vue';

export const useMessageStore = defineStore('message', () => {
  let data: Ref<ModelMessage[]> = ref([]);
  const msg1 = `醉里挑灯看剑,梦回吹角连营。八百里分麾下灸,五十弦翻塞外声。沙场秋点兵。马作的卢飞快,弓如霹雳弦惊。了却君王天下事,嬴得生前身后名。可怜白发生`;
  const msg2 = `怒发冲冠,凭栏处,潇潇雨歇。抬望眼,仰天长啸,壮怀激烈。 三十功名尘与土,八千里路云和月。莫等闲,白了少年头,空悲切! 靖康耻,犹未雪;臣子恨,何时灭?驾长车,踏破贺兰山缺! 壮志饥餐胡虏肉,笑谈渴饮匈奴血。待从头,收拾旧山河,朝天阙!`;
  const initData = (chat: ModelChat) => {
    let result = [];
    for (let i = 0; i < 10; i++) {
      let model = new ModelMessage();
      model.createTime = Date.now();
      model.isInMsg = i % 2 === 0;
      model.messageContent = model.isInMsg ? msg1 : msg2;
      model.fromName = model.isInMsg ? chat.fromName : "我";
      model.avatar = chat.avatar;
      model.chatId = chat.id;
      result.push(model);
    }
    data.value = result;
  };
  return { data, initData };
});

消息数据是模拟出来的,这里模拟了 10 条消息,预期用户切换会话的时候,执行 initData 方法,初始化当前会话的消息。

修改一下 MessageBoard 组件的的代码,如下所示:

src/renderer/window/WindowMain/chat/components/MessageBoard.vue

<template>
  <div class="MessageBord">
    <BarTop />
    <div class="MessageList">
      <MessageItem :data="item" v-for="item in messageStore.data" :key="item.id"></MessageItem>
    </div>
  </div>
</template>

<script lang="ts" setup>
import BarTop from '../../../../components/BarTop.vue';
import { ModelChat } from '../../../../../model/ModelChat';
import { useMessageStore } from '../../../../store/useMessageStore';
import { useChatStore } from '../../../../store/useChatStore';
import MessageItem from './MessageItem.vue';

const chatStore = useChatStore();
const messageStore = useMessageStore();

let curId = '';

chatStore.$subscribe((mutations, state) => {
  const item = state.data.find(v => v.isSelected) as ModelChat;
  if (item?.id !== curId) {
    messageStore.initData(item);
    curId = item?.id;
  }
})
</script>

<style scoped lang="scss">
.MessageBord {
  height: 100%;
  display: flex;
  flex: 1;
  flex-direction: column;
}
.MessageList {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  background: rgb(245, 245, 245);
}
</style>

当选中的聊天会话切换时,执行 messageStore 对象的 initData 方法,这样就初始化了 messageStore 内部的状态数据。

MessageItem 是新创建的一个 Vue 组件,这个组件用于显示一条消息的具体信息。代码如下所示:

src/renderer/window/WindowMain/chat/components/MessageItem.vue

<template>
  <template v-if="data.isInMsg">
    <div class="MessageItem left">
      <div class="avatar">
        <img :src="data.avatar" alt="" />
      </div>
      <div class="MessageBox">
        <div class="FromName">{{ data.fromName }}</div>
        <div class="MsgContent">{{ data.messageContent }}</div>
      </div>
    </div>
  </template>
  <template v-else>
    <div class="MessageItem right">
      <div class="MessageBox">
        <div class="MessageContent">{{ data.messageContent }}</div>
      </div>
      <div class="avatar">
        <img :src="data.avatar" alt="" />
      </div>
    </div>
  </template>
</template>

<script setup lang="ts">
import { ModelMessage } from '../../../../../model/ModelMessage';
defineProps<{ data: ModelMessage }>();
</script>

<style lang="scss" scoped>
.MessageItem {
  display: flex;
  padding-top: 8px;
  padding-bottom: 8px;
  position: relative;
}
.left {
  padding-right: 30%;
  &::after {
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-right: 6px solid #fff;
    position: absolute;
    left: 60px;
    top: 38px;
    content: "";
  }
}
.right {
  padding-left: 30%;
  &::after {
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-left: 6px solid rgb(149, 236, 105);
    position: absolute;
    right: 60px;
    top: 18px;
    content: "";
  }
  .MessageContent {
    background: rgb(149, 236, 105) !important;
  }
}
.avatar {
  width: 66px;
  text-align: center;
  img {
    width: 46px;
    height: 46px;
  }
}
.MessageBox {
  flex: 1;
}
.FromName {
  color: rgb(178, 178, 178);
  margin-bottom: 6px;
}
.MessageContent {
  background: #fff;
  border-radius: 3px;
  padding: 8px;
  line-height: 22px;
}
</style>

在切换选中的聊天会话时,直接初始化 messageStore 里的数据,就完全不需要在 MessageBord 组件里订阅 chatStore 的数据变更了。

pinia 是支持这种操作的,现在修改一下 useChatStore 的代码,如下所示:

import { defineStore } from 'pinia';
import { Ref, ref } from 'vue';
import { ModelChat } from '../../model/ModelChat';
import { useMessageStore } from './useMessageStore';

// mock data
const prepareData = () => {
  let result = [];
  for (let i = 0; i < 10; i++) {
    let model = new ModelChat();
    model.fromName = '聊天对象' + i;
    model.sendTime = '昨天';
    model.lastMsg = '这是此会话的最后一条消息' + i;
    model.avatar = 'https://pic3.zhimg.com/v2-306cd8f07a20cba46873209739c6395d_im.jpg?source=32738c0c';
    result.push(model);
  }
  return result;
};

export const useChatStore = defineStore('chat', () => {
  let data: Ref<ModelChat[]> = ref(prepareData());
  const selectItem = (item: ModelChat) => {
    if (item.isSelected) return;
    data.value.forEach((v) => (v.isSelected = false));
    item.isSelected = true;
    const messageStore = useMessageStore();
    messageStore.initData(item);
  };
  return { data, selectItem };
});

在 selectItem 方法内使用 messageStore 提供的方法。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文