创新项目实训--解题页面前端

这篇博客介绍的内容是有关于网页前端的

<template>
  <div class="chat-window">
    <div class="botoom">
      <div class="chat-content" ref="chatContent">
        <div class="chat-wrapper" v-for="(item, index) in chatList" :key="item.time">
          
          <div class="chat-friend" v-if="item.uid !== '1001'">
            <div class="info-time">
              <img :src="item.headImg" alt="" />
              <span>{{ item.name }}</span>
              <span>{{ item.time }}</span>
            </div>
            <div class="chat-text" v-if="item.chatType == 0">
              <template v-if="isSend && index == chatList.length - 1">
                <span class="flash_cursor"></span>
              </template>
              <template v-else><template><div v-hljs v-html="item.msg"></div></template></template>
            </div>
            <div class="chat-img" v-if="item.chatType == 1">
              <img :src="item.msg" alt="表情" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px" />
              <el-image :src="item.msg" :preview-src-list="srcImgList" v-else>
              </el-image>
            </div>
            <div class="chat-img" v-if="item.chatType == 2">
              <div class="word-file">
                <FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard>
              </div>
            </div>
          </div>
          <div class="chat-me" v-else>
            <div class="info-time">
              <span>{{ item.name }}</span>
              <span>{{ item.time }}</span>
              <img :src="item.headImg" alt="" />
            </div>
            <div class="chat-text" v-if="item.chatType == 0">
              {{ item.msg }}
            </div>
            <div class="chat-img" v-if="item.chatType == 1">
              <img :src="item.msg" alt="表情" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px" />
              <el-image style="max-width: 300px; border-radius: 10px" :src="item.msg" :preview-src-list="srcImgList"
                v-else>
              </el-image>
            </div>
            <div class="chat-img" v-if="item.chatType == 2">
              <div class="word-file">
                <FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="chatInputs">

该组件显示聊天记录,并支持文本、图片、文件等多种类型的消息。以下是代码的详细说明:

组件结构

  • chat-window: 顶层容器,包含聊天内容和输入区域。
  • chat-content: 聊天内容区域,使用ref="chatContent"进行引用,以便在其他地方访问。
  • chat-wrapper: 每条聊天记录的容器,通过v-for循环遍历chatList数组生成,使用消息的时间戳item.time作为键值key

聊天记录

聊天记录分为两种:对方的消息和用户自己的消息。

对方的消息(chat-friend)
  • info-time: 显示发送者的信息和发送时间,包括头像、名称和时间。
  • chat-text: 如果消息类型chatType为文本(0),则显示文本消息。支持代码高亮显示,如果消息正在发送并且是最后一条消息,显示闪烁光标。
  • chat-img: 如果消息类型为图片(1),则显示图片消息。根据扩展属性extend.imgType判断是普通图片还是需要预览的大图。
  • chat-img(文件类型): 如果消息类型为文件(2),则显示文件消息,通过FileCard组件展示文件信息。
用户自己的消息(chat-me)
  • info-time: 显示发送者的信息和发送时间,包括头像、名称和时间,但布局相对于对方的消息是反向的。
  • chat-text: 如果消息类型chatType为文本(0),则显示文本消息。
  • chat-img: 如果消息类型为图片(1),则显示图片消息。根据扩展属性extend.imgType判断是普通图片还是需要预览的大图。
  • chat-img(文件类型): 如果消息类型为文件(2),则显示文件消息,通过FileCard组件展示文件信息。

辅助功能

  • 代码高亮(v-hljs): 使用v-hljs指令实现代码高亮显示。
  • 图片预览(el-image): 使用el-image组件实现图片预览功能。
  • 文件展示(FileCard): 使用FileCard组件展示文件信息。

动态效果

  • 闪烁光标(flash_cursor): 在文本消息正在发送且为最后一条消息时,显示一个闪烁光标,表示正在输入或发送消息。
<script>
import Showdown from "showdown";
import { animation } from "@/util/util";
import { getChatMsg, resolve } from "@/api/getData";
import HeadPortrait from "@/components/HeadPortrait";
import Emoji from "@/components/Emoji";
import FileCard from "@/components/FileCard.vue";

export default {
  components: {
    HeadPortrait,
    Emoji,
    FileCard,
  },
  props: {
    frinedInfo: Object,
    default() {
      return {};
    },
  },
  watch: {
  },
  data() {
    return {
      chatList: [],
      inputMsg: "",
      showEmoji: false,
      friendInfo: {},
      srcImgList: [],
      isSend: false,
    };
  },
  mounted() {
    if(localStorage.getItem("resolve")==null){
      let resolve_history =[]
      localStorage.setItem("resolve", JSON.stringify(resolve_history));
    }else{
      let history = JSON.parse(localStorage.getItem("resolve"));
      this.chatList=history;
    }
    this.$nextTick(() => {
      const scrollDom = this.$refs.chatContent;
      scrollDom.scrollTop = scrollDom.scrollHeight;
    });
    
  },
  methods: {
    handleKeydown(event) {
      // 当按下Enter键且没有按Shift键时,调用sendText函数
      if (event.key === 'Enter' && !event.shiftKey) {
        if(this.isSend==true){
          this.$message("等待chatbot回复~🥳");
          return
        }
        event.preventDefault(); // 阻止默认行为,比如防止表单提交
        this.sendText();
      }
    },
    sendMsg(msgList) {
      this.chatList.push(msgList);
      this.scrollBottom();
    },
    //获取窗口高度并滚动至最底层
    scrollBottom() {
      this.$nextTick(() => {
        const scrollDom = this.$refs.chatContent;
        animation(scrollDom, scrollDom.scrollHeight - scrollDom.offsetHeight);
      });
    },
    //关闭标签框
    clickEmoji() {
      this.showEmoji = !this.showEmoji;
    },
    //发送文字信息
    sendText() {
      if (this.inputMsg) {
        let chatMsg = {
          headImg: require("@/assets/img/emoji/smiling-face-with-heart-eyes.png"),
          name: "user",
          time: new Date().toLocaleString(),
          msg: this.inputMsg,
          chatType: 0, //信息类型,0文字,1图片
          uid: "1001", //uid
        };
        this.sendMsg(chatMsg);
        // this.$emit('personCardSort', this.frinedInfo.id)
        this.inputMsg = "";
        let data = {"msgs":[]}
        for(let i=0;i<this.chatList.length;i++){
          data.msgs.push({"msg":this.chatList[i].msg})
        }
        this.isSend = true;
        let date = new Date();
        date.setSeconds(date.getSeconds()+1);
        let chatGPT = {
          headImg: require("@/assets/img/emoji/smiling-face.png"),
          name: "chatbot",
          time: date.toLocaleString(),
          msg: "",
          chatType: 0, //信息类型,0文字,1图片
          uid: "1002", //uid
        };
        this.sendMsg(chatGPT);
        resolve(data).then((res) => {
          let converter = new Showdown.Converter();
          let htmlStr=res.msg;
          let convertedHtml = converter.makeHtml(htmlStr);
          this.chatList[this.chatList.length-1].msg = convertedHtml;
          this.isSend = false;
          let history = JSON.parse(localStorage.getItem("resolve"));
          let flag=false;
          history=this.chatList;
          localStorage.setItem("resolve", JSON.stringify(history));
        });
        
      } else {
        this.$message({
          message: "消息不能为空哦~",
          type: "warning",
        });
      }
    },
    //发送表情
    sendEmoji(msg) {
      let chatMsg = {
        headImg: require("@/assets/img/head_portrait.jpg"),
        name: "大毛是小白",
        time: "09:12 AM",
        msg: msg,
        chatType: 1, //信息类型,0文字,1图片
        extend: {
          imgType: 1, //(1表情,2本地图片)
        },
        uid: "1001",
      };
      this.sendMsg(chatMsg);
      this.clickEmoji();
    },
    //发送本地图片
    sendImg(e) {
      let _this = this;
      console.log(e.target.files);
      let chatMsg = {
        headImg: require("@/assets/img/head_portrait.jpg"),
        name: "大毛是小白",
        time: "09:12 AM",
        msg: "",
        chatType: 1, //信息类型,0文字,1图片, 2文件
        extend: {
          imgType: 2, //(1表情,2本地图片)
        },
        uid: "1001",
      };
      let files = e.target.files[0]; //图片文件名
      if (!e || !window.FileReader) return; // 看是否支持FileReader
      let reader = new FileReader();
      reader.readAsDataURL(files); // 关键一步,在这里转换的
      reader.onloadend = function () {
        chatMsg.msg = this.result; //赋值
        _this.srcImgList.push(chatMsg.msg);
      };
      this.sendMsg(chatMsg);
      e.target.files = null;
    },
    //发送文件
    sendFile(e) {
      let chatMsg = {
        headImg: require("@/assets/img/head_portrait.jpg"),
        name: "大毛是小白",
        time: "09:12 AM",
        msg: "",
        chatType: 2, //信息类型,0文字,1图片, 2文件
        extend: {
          fileType: "", //(1word,2excel,3ppt,4pdf,5zpi, 6txt)
        },
        uid: "1001",
      };
      let files = e.target.files[0]; //图片文件名
      chatMsg.msg = files;
      console.log(files);
      if (files) {
        switch (files.type) {
          case "application/msword":
          case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
            chatMsg.extend.fileType = 1;
            break;
          case "application/vnd.ms-excel":
          case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
            chatMsg.extend.fileType = 2;
            break;
          case "application/vnd.ms-powerpoint":
          case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
            chatMsg.extend.fileType = 3;
            break;
          case "application/pdf":
            chatMsg.extend.fileType = 4;
            break;
          case "application/zip":
          case "application/x-zip-compressed":
            chatMsg.extend.fileType = 5;
            break;
          case "text/plain":
            chatMsg.extend.fileType = 6;
            break;
          default:
            chatMsg.extend.fileType = 0;
        }
        this.sendMsg(chatMsg);
        e.target.files = null;
      }
    },
    // 发送语音
    telephone() {
      this.$message("该功能还没有开发哦,敬请期待一下吧~🥳");
    },
    //发送视频
    video() {
      this.$message("该功能还没有开发哦,敬请期待一下吧~🥳");
    },
  },
};

用于实现一个功能丰富的聊天窗口,支持发送和接收文本、表情、图片和文件消息。以下是代码的详细说明:

导入模块和组件

  • Showdown: 一个Markdown转换器,用于将Markdown文本转换为HTML。
  • animation: 一个自定义动画函数,用于实现平滑滚动效果。
  • getChatMsg, resolve: 从API获取数据的函数。
  • HeadPortrait: 头像组件。
  • Emoji: 表情组件。
  • FileCard: 文件展示组件。

组件配置

  • components: 注册了HeadPortraitEmojiFileCard三个子组件。
  • props: 接收一个frinedInfo对象作为属性,默认值为空对象。
  • data: 返回组件的状态数据,包括聊天记录chatList、输入的消息inputMsg、表情显示状态showEmoji、好友信息friendInfo、图片列表srcImgList、发送状态isSend

生命周期钩子

  • mounted: 在组件挂载时执行:
    • 检查本地存储中是否有resolve历史记录,如果没有则初始化为空数组。
    • 如果存在历史记录,则从本地存储中加载并赋值给chatList
    • 使用$nextTick确保DOM更新完成后,将聊天内容区域滚动到最底部。

方法

  • handleKeydown: 处理键盘事件,当按下Enter键且未按Shift键时,调用sendText函数发送消息。
  • sendMsg: 添加消息到聊天记录chatList并滚动到底部。
  • scrollBottom: 滚动聊天内容区域到底部。
  • clickEmoji: 切换表情框的显示状态。
  • sendText: 发送文本消息:
    • 构建用户消息对象并添加到chatList
    • 重置输入框并构建请求数据。
    • 设置isSendtrue表示正在发送消息。
    • 添加一个占位的机器人回复消息。
    • 调用resolve函数获取机器人的回复,将Markdown格式转换为HTML,并更新到占位消息中。
    • 更新本地存储中的聊天记录。
  • sendEmoji: 发送表情消息。
  • sendImg: 发送本地图片:
    • 使用FileReader读取图片文件并将其转换为Base64格式。
    • 构建图片消息对象并添加到chatList
  • sendFile: 发送文件消息:
    • 根据文件类型设置扩展属性中的文件类型。
    • 构建文件消息对象并添加到chatList
  • telephone: 显示未开发的语音功能提示。
  • video: 显示未开发的视频功能提示。

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值