这篇博客介绍的内容是有关于网页前端的
<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: 注册了
HeadPortrait
、Emoji
、FileCard
三个子组件。 - props: 接收一个
frinedInfo
对象作为属性,默认值为空对象。 - data: 返回组件的状态数据,包括聊天记录
chatList
、输入的消息inputMsg
、表情显示状态showEmoji
、好友信息friendInfo
、图片列表srcImgList
、发送状态isSend
。
生命周期钩子
- mounted: 在组件挂载时执行:
- 检查本地存储中是否有
resolve
历史记录,如果没有则初始化为空数组。 - 如果存在历史记录,则从本地存储中加载并赋值给
chatList
。 - 使用
$nextTick
确保DOM更新完成后,将聊天内容区域滚动到最底部。
- 检查本地存储中是否有
方法
- handleKeydown: 处理键盘事件,当按下Enter键且未按Shift键时,调用
sendText
函数发送消息。 - sendMsg: 添加消息到聊天记录
chatList
并滚动到底部。 - scrollBottom: 滚动聊天内容区域到底部。
- clickEmoji: 切换表情框的显示状态。
- sendText: 发送文本消息:
- 构建用户消息对象并添加到
chatList
。 - 重置输入框并构建请求数据。
- 设置
isSend
为true
表示正在发送消息。 - 添加一个占位的机器人回复消息。
- 调用
resolve
函数获取机器人的回复,将Markdown格式转换为HTML,并更新到占位消息中。 - 更新本地存储中的聊天记录。
- 构建用户消息对象并添加到
- sendEmoji: 发送表情消息。
- sendImg: 发送本地图片:
- 使用
FileReader
读取图片文件并将其转换为Base64格式。 - 构建图片消息对象并添加到
chatList
。
- 使用
- sendFile: 发送文件消息:
- 根据文件类型设置扩展属性中的文件类型。
- 构建文件消息对象并添加到
chatList
。
- telephone: 显示未开发的语音功能提示。
- video: 显示未开发的视频功能提示。