uniapp实现聊天中的接发消息自动滚动、消息定位和回到底部

前言

前言无需多言,想必大家对聊天软件的功能已经很熟悉, 这里不做过多赘述,笔者通过uniapp实现聊天中的接发消息自动滚动、消息定位和回到底部。

代码实现

xml 复制代码
<template>
  <view class="chat-container">
    <!-- 消息列表 -->
    <scroll-view
        class="message-list"
        scroll-y
        style="height: 300px;"
        upper-threshold="200"
        :scroll-into-view="'message-item-' + scrollMsgIdx"
        :scroll-with-animation="true"
        @scroll="handleScroll"
    >
      <view class="message-item-box" v-for="(item, idx) in chatMessageList" :key="item.id" :id="'message-item-' + idx">
        <view :class="['message-item', item.self === true ? 'right' : 'left']">
          <view class="message-content">
            {{ item.content }}
          </view>
        </view>
      </view>
    </scroll-view>

    <view class="back-to-bottom-btn" @click="scrollToBottom" v-if="showBackBottomBtn">
      回到底部
    </view>

    <!-- 输入区域 -->
    <view class="content-area">
      <view class="input-box">
        <textarea v-model="inputText" placeholder="输入内容" maxlength="500" auto-height/>
      </view>
      <button class="send-btn" @click="sendMsg" size="mini">发送</button>
      <button class="jump-btn" @click="jumpMsg" size="mini">定位</button>
    </view>
  </view>
</template>

<script setup>
import {onLoad} from '@dcloudio/uni-app';
import {nextTick, ref} from "vue";

const scrollMsgIdx = ref(0); // 滚动控制
const showBackBottomBtn = ref(false); // 回到底部按钮显示
const inputText = ref(''); // 输入文本
const chatMessageList = ref([
  {id: 0, content: '请求添加你为好友?', self: false},
  {id: 1, content: '你好', self: false},
  {id: 2, content: '你是谁啊?', self: true},
  {id: 3, content: '我是你爸爸啊', self: false},
  {id: 4, content: '???', self: true},
  {id: 5, content: '我是你爷爷', self: true},
  {id: 6, content: '你真的是个老六', self: false},
  {id: 7, content: '谁让你张口就来', self: true},
  {id: 8, content: '再问一遍你是谁?', self: true},
  {id: 9, content: '我是张三,你叔叔介绍的相亲对象', self: false},
  {id: 10, content: '哦哦', self: true},
  {id: 11, content: '那你今年多大了?', self: true},
  {id: 12, content: '27', self: false},
  {id: 13, content: '那你哪个学校毕业的啊?', self: true},
  {id: 14, content: '在哪里工作?', self: true},
  {id: 15, content: '毕业于家里蹲大学', self: false},
  {id: 16, content: '现在没工作', self: false},
  {id: 17, content: '啊?那你用钱了怎么办啊', self: true},
  {id: 18, content: '你管我啊', self: false},
  {id: 19, content: '那你自己看着办吧!', self: true},
  {id: 20, content: '好的', self: false},
  {id: 21, content: '不用你操心哦', self: false},
  {id: 22, content: '替你家长操心!', self: true},
  {id: 23, content: '那也不需要', self: false},
  {id: 24, content: '你大学学的啥啊?工作都找不到', self: true},
  {id: 25, content: '大学光挂科去了', self: false},
  {id: 26, content: '那怪不得', self: true},
  {id: 27, content: '好自为之吧', self: true},
]); // 消息列表

onLoad(() => {
  // 回到底部
  scrollToBottom();
});

// 发送消息
function sendMsg() {
  if (!inputText.value.trim()) {
    console.log('不能发送空白信息');
    return;
  }
  chatMessageList.value.push({id: Date.now(), content: inputText.value, self: true});
  inputText.value = '';
  chatMessageList.value.push({id: Date.now(), content: '自动回复', self: false});

  // 回到底部
  scrollToBottom();
}

// 跳转指定消息
function jumpMsg() {
  if (!inputText.value.trim()) {
    console.log('不能发送空白信息');
    return;
  }
  scrollToMsgIdx(Number(inputText.value));
  inputText.value = '';
}

// 滚动事件处理
function handleScroll(e) {
  const { scrollTop, scrollHeight } = e.detail;
  const screenHeight = uni.getSystemInfoSync().screenHeight;
  showBackBottomBtn.value = scrollHeight - screenHeight - scrollTop > 50;
}

// 滚动到底部
function scrollToBottom() {
  let length = chatMessageList.value.length;
  if (length > 0) {
    scrollToMsgIdx(length - 1);
  }
}

// 滚动到指定消息
function scrollToMsgIdx(idx) {
  nextTick(() => {
    scrollMsgIdx.value = (idx < 0 || idx > chatMessageList.value.length - 1) ? 0 : idx;
    showBackBottomBtn.value = chatMessageList.value.length - 1 - scrollMsgIdx.value > 0;
  });
}
</script>

<style lang="scss" scoped>
.chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #f5f5f5;

  .message-list {
    flex: 1;
    margin-top: 10px;
    overflow: auto;
    background-color: #f5f5f5;

    .message-item-box {
      margin: 10px;
    }

    .message-item {
      display: flex;

      &.left {
        justify-content: flex-start;

        .message-content {
          margin-left: 10px;
          background-color: #fff;
        }
      }

      &.right {
        justify-content: flex-end;

        .message-content {
          margin-right: 10px;
          background-color: #95ec69;
        }
      }

      .message-content {
        max-width: 70%;
        border-radius: 2px;
        box-sizing: border-box;
        word-break: break-word;
        height: auto;
        padding: 10px;
      }
    }
  }

  .content-area {
    display: flex;
    align-items: center;
    padding: 8px 10px;
    background-color: #fff;
    border-top: 1px solid #eee;

    .input-box {
      flex: 4;

      textarea {
        box-sizing: border-box;
        width: 100%;
        background-color: #f5f5f5;
        border-radius: 4px;
        padding: 8px;
        font-size: 14px;
      }
    }

    .send-btn {
      flex: 1;
      text-align: center;
      align-items: center;
      background-color: #07c160;
      color: #ffffff;
      font-size: 12px;
      padding: 2px !important;
    }

    .jump-btn {
      flex: 1;
      text-align: center;
      align-items: center;
      background-color: #97aca1;
      color: #ffffff;
      font-size: 12px;
      padding: 2px !important;
    }
  }

  .back-to-bottom-btn {
    position: fixed;
    bottom: 55px;
    right: 10px;
    background-color: #575859;
    color: #ffffff;
    padding: 5px;
    border-radius: 4px;
    font-size: 12px;
    z-index: 999;
  }
}
</style>

演示

接发消息自动滚动

发送和接收消息都可以自己滚动到最新消息!

消息定位

为简化代码,消息框直接输入消息的索引号,即可定位对应消息,你可以自己添加样式!

回到底部

点击回到底部按钮即可!

相关推荐
拾光拾趣录1 分钟前
Vue Router 执行顺序
前端·vue.js·vue-router
前端权2 分钟前
Vue3 多行文本溢出隐藏与展开收起功能实现总结
前端·vue.js
用户3802258598242 分钟前
vue3源码解析:调度器
前端·vue.js
一一一87112 分钟前
javaScript数据存储, 对象和原型与原型链
javascript
梦想CAD控件28 分钟前
WEB CAD与Mapbox结合实现在线地图和CAD编辑(CGCS2000)
前端·javascript·vue.js
WTSolutions1 小时前
Excel 转 JSON by WTSolutions API 文档
javascript
努力只为躺平1 小时前
🔥 油猴脚本开发指南:从基础API到发布全流程
前端·javascript
普宁彭于晏1 小时前
Uni-app 生命周期与钩子:程序的“生命”旅程
uni-app·vue
bitbitDown1 小时前
我用Playwright爬了掘金热榜,发现了这些有趣的秘密... 🕵️‍♂️
前端·javascript·vue.js
markyankee1011 小时前
Vue 表单输入绑定终极指南:从基础到企业级实践
vue.js