首页 前端知识 vue实现基本对话功能

vue实现基本对话功能

2024-09-01 23:09:40 前端知识 前端哥 188 451 我要收藏

基于vue3.0实现的简易对话功能,仿照微信、QQ聊天界面。

HTML代码块

<template>
  <el-container style="height: 100%" ref="bodyform">
    <div class="el_main_content">
      <div class="main_content_header">这是一个对话框</div>
      <div class="main_content_center">
        <el-scrollbar
          class="faultExpertConsultation_scrollbar"
          ref="scrollbarRef"
        >
          <!--对话内容-->
          <div
            v-for="(item, index) in messagesWithTimestamps"
            :key="index"
            v-show="messagesWithTimestamps.length > 0"
          >
            <!--对话时间-->
            <div v-if="item.showTime" class="chat_time">
              {{ formatSendTime(item.timestamp) }}
            </div>
            <!--提问-->
            <div class="question chat">
              <div class="chat_question chat_common">
                <span>{{ item.question }}</span>
              </div>
              <el-avatar class="avatar">
                <span class="me">我</span>
              </el-avatar>
            </div>
            <!--回答-->
            <div class="answer chat" v-if="item.answer">
              <el-avatar :src="robot" />
              <div class="chat_answer chat_common">
                <span>{{ item.answer }}</span>
              </div>
            </div>
          </div>
        </el-scrollbar>
      </div>
      <div class="main_content_footer">
        <div class="input_box">
          <textarea class="chat-input no-border" v-model="question" />
        </div>
        <div class="btn_box">
          <el-button type="primary" class="btn" @click="askClick(question)"
            >发送</el-button
          >
        </div>
      </div>
    </div>
  </el-container>
</template>

JavaScript代码块

<script setup>
import { ref, onMounted, nextTick, computed, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
const question = ref(""); //输入框值
const chatList = ref([]); //循环的聊天数组
const scrollbarRef = ref(null);
//创建新的对话数组,加上属性showTime
const messagesWithTimestamps = computed(() => {
  return chatList.value.map((item, index) => ({
    ...item,
    showTime: index === 0 || shouldShowTime(index),
  }));
});
//计算两次会话时间是否超过3分钟方法
const shouldShowTime = (index) => {
  const current = new Date(chatList.value[index - 1].timestamp);
  const next = new Date(chatList.value[index].timestamp);
  const diff = next ? next - current : 0;
  return diff > 3 * 60 * 1000; // 如果间隔超过3分钟返回true
};
//提问方法
const askClick = (val) => {
  if (val != "") {
    chatList.value.push({
      question: val, //问题
      answer: "", //回答
      timestamp: new Date(), //时间戳
      to: "", //接收者
      form: "", //发送者
    });
  } else {
    ElMessage("不能发送空白消息");
  }
};
//滚动事件到底部事件
const scrollToBottom = () => {
  nextTick(() => {
    let chat = document.querySelector(".main_content_center");
    scrollbarRef.value.wrapRef.scrollTop = chat.scrollHeight;
  });
};
watch(
  chatList.value,
  (newVal, oldVal) => {
    scrollToBottom();
  },
  { immediate: true }
);

const formatSendTime = (sendTime) => {
  const now = new Date();
  const sendDate = new Date(sendTime);
  // 计算时间差(以毫秒为单位)
  const timeDiff = now - sendDate;
  const startOfToday = new Date(
    now.getFullYear(),
    now.getMonth(),
    now.getDate()
  );
  const startOfTargetDate = new Date(
    sendDate.getFullYear(),
    sendDate.getMonth(),
    sendDate.getDate()
  );
  // 一天内的毫秒数
  const oneDay = 24 * 60 * 60 * 1000;
  // 如果发送时间在当前时间之前
  if (timeDiff < 0) {
    return "Invalid time"; // 或者其他错误处理
  }
  // 发生在同一天
  if (startOfToday.getTime() === startOfTargetDate.getTime()) {
    return formatTime(sendDate);
  }
  // 如果发送时间在一天内
  if (timeDiff < oneDay) {
    return "昨天 " + formatTime(sendDate);
  }
  // 如果发送时间在二天至七天内
  if (timeDiff < 7 * oneDay) {
    const weekday = getWeekday(sendDate);
    return weekday + " " + formatTime(sendDate);
  }
  // 如果发送时间超过七天
  return (
    sendDate.toLocaleDateString("zh-CN", {
      year: "numeric",
      month: "2-digit",
      day: "2-digit",
    }) +
    " " +
    formatTime(sendDate)
  );
};
const formatTime = (date) => {
  // 格式化时间为“时:分”
  const hours = date.getHours().toString().padStart(2, "0");
  const minutes = date.getMinutes().toString().padStart(2, "0");
  return hours + ":" + minutes;
};
const getWeekday = (date) => {
  // 获取星期几的中文表示
  const weekdays = [
    "星期天",
    "星期一",
    "星期二",
    "星期三",
    "星期四",
    "星期五",
    "星期六",
  ];
  return weekdays[date.getDay()];
};
</script>

CSS代码块

<style>
.no-border {
  border: none;
  /* 可选的样式,以去除焦点时的边框(如果需要的话) */
  outline: none;
  width: none;
  height: none;
  resize: none;
}
</style>

<style lang="less" scoped>
.el_main_content {
  width: 50%;
  height: 70%;
  border-radius: 5px;
  border: 1px solid #e4e7ed;
  box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
  margin: auto;

  .main_content_header {
    width: 100%;
    height: 50px;
    border-radius: 5px;
    background-color: #7de0bd;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
  }

  .main_content_center {
    width: 100%;
    position: relative;
    height: calc(100% - 170px);
    margin: 10px 0px;

    .chat_time {
      display: flex;
      justify-content: center;
      font-size: 10px;
    }
    .question {
      justify-content: flex-end;
    }
    .chat_question {
      background-color: #8ce45f;
      margin-right: 5px;
      color: #ffffff;
    }
    .chat_answer {
      background-color: #f2f3f5;
      margin-left: 5px;
    }
    .chat {
      width: 98%;
      margin: 10px auto;
      display: flex;
    }
    .chat_common {
      max-width: 40%;
      padding: 10px;
      border-radius: 2px;
      word-break: break-all;
      display: flex;
      align-items: center;
    }
    .avatar {
      background-color: #409eff;
      border: 2px solid #409eff;
    }
    .me {
      font-size: 16px;
      color: #ffffff;
      font-weight: bold;
    }
  }

  .main_content_footer {
    width: 100%;
    height: 100px;
    border-top: 1px solid #e4e7ed;
    .input_box {
      width: 100%;
      height: 60px;
      .chat-input {
        width: calc(100% - 20px);
        padding: 10px;
        margin: auto;
      }
    }
    .btn_box {
      width: 100%;
      height: 40px;
      display: flex;
      justify-content: flex-end;
      align-items: center;
      .btn {
        margin-right: 10px;
      }
    }
  }
}
</style>

运行效果

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17464.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!