vue实现基本对话功能

基于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>

运行效果

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Vue可以通过实现图书阅读功能。首先,我们需要创建一个Vue的项目,然后引入Vue的相关组件和插件。接下来,我们可以使用Vue的数据绑定功能来动态展示图书的详细信息,例如书名、作者、封面图片等。同时,我们也可以使用Vue的条件渲染来实现图书的展示和隐藏。 为了实现图书的翻页功能,我们可以使用Vue的事件绑定功能来监听用户在浏览器中的触发事件,例如鼠标点击、键盘按下等。当用户触发了翻页事件时,我们可以通过修改Vue中的数据状态来改变当前显示的图书页数。同时,在渲染图书页面时,我们也可以根据当前页数来展示对应的图书内容。 为了方便用户进行图书的搜索和筛选,我们可以使用Vue的表单绑定功能来获取用户输入的关键词。然后,通过Vue的过滤器功能来筛选符合用户需求的图书数据。这样,用户就能够方便地找到他们想要的图书。 除了基本的图书阅读功能外,我们还可以添加一些其他的功能来增强用户体验。例如,为图书阅读界面添加目录功能,让用户能够快速跳转到感兴趣的章节;为图书阅读界面添加书签功能,让用户能够方便地标记自己感兴趣的部分;将图书的阅读进度保存到后端服务器,使得用户可以在不同设备上同步阅读进度等等。 通过Vue的灵活性和强大的功能,我们可以实现一个功能完备的图书阅读应用,提供给用户一个良好的阅读体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@李优秀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值