vue实现聊天框自动滚动 您所在的位置:网站首页 手机网页怎么自动滚动 vue实现聊天框自动滚动

vue实现聊天框自动滚动

2024-07-14 16:35| 来源: 网络整理| 查看: 265

需求   

        1、聊天数据实时更新渲染到页面         2、页面高度随聊天数据增加而增加         3、竖向滚动         4、当用户输入聊天内容或者接口返回聊天内容渲染在页面后,自动滚动到底部         5、提供点击事件操控滚动条上下翻动

环境依赖

        vue:@vue/cli 5.0.8

        taro:v3.4.1

实现方案 方案一:元素设置锚点,使用scrollIntoView() 方法滑动

         Element 接口的 scrollIntoView()  方法会滚动元素的父容器,使被调用 scrollIntoView()  的元素对用户可见

        1、语法         element.scrollIntoView(); // 等同于 element.scrollIntoView(true)         element.scrollIntoView(alignToTop); // alignToTop为Boolean 型参数,true/false         element.scrollIntoView(scrollIntoViewOptions); // Object 型参数         2、参数      (1)alignToTop(可选)         类型:Boolean

        如果为true,元素的顶端将和其所在滚动区的可视区域的顶端对齐。对应的 scrollIntoViewOptions: {block: “start”, inline: “nearest”}。该参数的默认值为true。         如果为false,元素的底端将和其所在滚动区的可视区域的底端对齐。对应的scrollIntoViewOptions: {block: “end”, inline: “nearest”}。       (2)scrollIntoViewOptions (可选)         类型:对象          

        behavior 【可选】                 定义动画的过渡效果,取值为 auto/smooth。默认为 “auto”。         block 【可选】                 定义垂直方向的对齐, 取值为 start/center/end/nearest 。默认为 “start”。         inline 【可选】                 定义水平方向的对齐, 取值为 start/center/end/nearest。默认为 “nearest”。        代码实现如下:

{{ item.content }} import { ref, reactive, toRaw } from 'vue' export default { setup () { const contentTypeit = reactive({ arr: [] }) const scrollId = ref('id0') //scroll ID值 const scrollCursor = ref('id0') const number = ref(0) //https://blog.csdn.net/weixin_43398820/article/details/119963930 // 会话内容 // 获取对话结果 const sendMsg = function () { setContent( 'dfasdfsfsafdsafsafsdfsafsdfsdfdsfsafdsfsadfsafggfdhfhfjgfjhsdgdsfgasfsafdsafsagdhgfhfdhsgdsgdsgdgafsadfdsfdsfsadfhghsdfgsafdsaf') } // 设置对话内容 const setContent = function (msg) { let idValue = 'id' + number.value const currentObjTypeit = { 'content': msg, 'id': idValue } let _arr = toRaw(contentTypeit.arr) let _arrTmp = _arr.concat(currentObjTypeit) contentTypeit.arr = _arrTmp number.value = number.value + 1; scrollCursor.value = idValue //https://blog.csdn.net/weixin_46511008/article/details/126629361 setTimeout(() => { if (number.value !== 0) { let idValueSlide = 'id' + (number.value - 1) document.getElementById(idValueSlide).scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'end' }) } }, 100); } const scroll = function (e) { // console.log('scroll', e) } const upper = function (e) { // console.log('upper', e) } const lower = function (e) { // console.log('lower', e) } const pageUp = function (e) { console.log(scrollCursor.value) if (scrollCursor.value === undefined || scrollCursor.value === '' || scrollCursor.value.length < 3) { return; } let scrollCursorValue = scrollCursor.value.substring(2); console.log(scrollCursorValue); if (scrollCursorValue >= 1) { scrollCursorValue = scrollCursorValue - 1; scrollCursor.value = 'id' + scrollCursorValue; } setTimeout(function(){ if (document.querySelector('#'+ scrollCursor.value) === null) { return; } document.querySelector('#'+ scrollCursor.value).scrollIntoView() }, 200); } const pageDown = function (e) { console.log(scrollCursor.value) if (scrollCursor.value === undefined || scrollCursor.value === '' || scrollCursor.value.length < 3) { return; } let scrollCursorValue = scrollCursor.value.substring(2); console.log(scrollCursorValue); if (scrollCursorValue < contentTypeit.arr.length - 1) { scrollCursorValue = scrollCursorValue - (-1) scrollCursor.value = 'id' + scrollCursorValue; } if (scrollCursorValue === contentTypeit.arr.length - 1) { setTimeout(function(){ if (document.querySelector('#'+ scrollCursor.value) === null) { return; } document.querySelector('#'+ scrollCursor.value).scrollIntoView(false) }, 500); } else { setTimeout(function() { if (document.querySelector('#'+ scrollCursor.value) === null) { return; } document.querySelector('#'+ scrollCursor.value).scrollIntoView({ behavior: "smooth", // 平滑过渡 block: "end", // 上边框与视窗顶部平齐。默认值 }) }, 100); } } return { contentTypeit, scrollId, lower, upper, scroll, sendMsg, pageUp, pageDown, } } } .main { height: 100%; width: 100%; background-color: rgba(204, 204, 204, 0.32); overflow-x: hidden; overflow-y: auto; } .mainbody { max-width: 100%; background-size: contain; padding-bottom: 100px; } .info { display: flex; margin: 10px 3%; } .content-question { color: #0b4eb4; background-color: #ffffff; padding-left: 20px; } .content-questionBlock { align-items: center; } .content { background-color: #fff; border-radius: 16px; padding: 20px; margin-left: 20px; max-width: 82%; height: 100%; font-size: 36px; font-family: PingFangSC-Medium, PingFang SC; font-weight: 500; color: #0a0a27; line-height: 60px; word-break: break-all; }

        效果调试:

      (1)打开浏览器,按下F12进入调试模式;

      (2)在console窗口,多次调用document.getElementById('sendMsg').click(),使得对话内容超出界面高度,可观察到自动滚动效果;

       (3)在console窗口,调用document.getElementById('pageUp').click(),若没有滚动,可调整代码或者调用多次(取决于scrollIntoView()的参数),可观察到向上滚动;接着调用document.getElementById('pageDown').click(),可观察到向下滚动。

        效果图如下:

 方案二: 更改scrollTop取值,进行滚动        

        首先我们需要了解 clientHeight、offsetHeight、scrollHeight、scrollTop 的概念

        简单介绍:

                clientHeight:网页可见区域高

                offsetHeight:网页可见区域高(包括边线的高)

                scrollHeight:网页正文全文高                 scrollTop:网页被卷去的高

        具体说明:

       (1)clientHeight:包括padding 但不包括 border、水平滚动条、margin的元素的高度。对于inline的元素来说这个属性一直是0,单位px,为只读元素。

        简单来说就是——盒子的原始高度,具体可参考下图:

      (2)offsetHeight:包括padding、border、水平滚动条,但不包括margin的元素的高度。对于inline的元素来说这个属性一直是0,单位px,为只读元素。

        简单来说就是——盒子的原始高度+padding+border+滚动条,具体可参考下图:

       (3)scrollHeight: 这个只读属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。

        简单来说就是——盒子里面包含的内容的真实高度,具体可参考下图:

 

       (4)scrollTop: 代表在有滚动条时,滚动条向下滚动的距离也就是元素顶部被遮住部分的高度。在没有滚动条时 scrollTop==0 恒成立。单位px,可读可设置。

        MDN解释:一个元素的 scrollTop 值是这个元素的内容顶部(被卷起来的)到它的视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那它的 scrollTop 值为0,具体可参考下图:

         实现算法:卷起的高度(scrollTop) = 总的内容高度(scrollHeight) - 聊天区域盒子大小 (offsetHeight);

         代码实现如下:

{{ item.content }} import { ref, reactive, toRaw } from 'vue' import Taro from "@tarojs/taro"; export default { setup () { const contentTypeit = reactive({ arr: [] }) const scrollId = ref('id0') //scroll ID值 const scrollCursor = ref('id0') const scrollCursorStore = ref(0) // 自动 scrollTop //https://www.cnblogs.com/hmy-666/p/14717484.html 滚动原理与实现 //由于插入新的消息属于创建新的元素的过程,这个过程是属于异步的,所以为了防止异步创建元素导致获取高度不准确,我们可以等待一段时间,等元素创建完毕之后再获取元素高度 const scrollDownInterval = function () { let idDom = document.getElementById('mainbody') console.log("===================scrollTop,clientHeight,scrollHeight,offsetHeight", idDom.scrollTop, idDom.clientHeight, idDom.scrollHeight, idDom.offsetHeight) let currentScrollPosition = scrollCursorStore.value; Taro.nextTick(() => { console.log('scroll start...', idDom.scrollTop) let scrollInterval = setInterval(() => { if ( (idDom.scrollTop === idDom.scrollHeight - idDom.offsetHeight) || (idDom.scrollTop > idDom.scrollHeight - idDom.offsetHeight) ) { scrollCursorStore.value = idDom.scrollTop clearInterval(scrollInterval); console.log('scroll end...', idDom.scrollTop) } else { currentScrollPosition = currentScrollPosition + 100; idDom.scrollTop = currentScrollPosition; scrollCursorStore.value = idDom.scrollTop console.log('scrolling...', idDom.scrollTop) } }, 200) }) } const number = ref(0) //https://blog.csdn.net/weixin_43398820/article/details/119963930 // 会话内容 // 获取对话结果 const sendMsg = function () { setContent( 'dfasdfsfsafdsafsafsdfsafsdfsdfdsfsafdsfsadfsafggfdhfhfjgfjhsdgdsfgasfsafdsafsagdhgfhfdhsgdsgdsgdgafsadfdsfdsfsadfhghsdfgsafdsaf') } // 设置对话内容 const setContent = function (msg) { let idValue = 'id' + number.value const currentObjTypeit = { 'content': msg, 'id': idValue } let _arr = toRaw(contentTypeit.arr) let _arrTmp = _arr.concat(currentObjTypeit) contentTypeit.arr = _arrTmp number.value = number.value + 1; scrollCursor.value = idValue //https://blog.csdn.net/weixin_46511008/article/details/126629361 scrollDownInterval(); } const scroll = function (e) { // console.log('scroll', e) } const upper = function (e) { // console.log('upper', e) } const lower = function (e) { // console.log('lower', e) } const pageUp = function (e) { let idDom = document.getElementById('mainbody') console.log("===================", idDom.scrollTop, idDom.clientHeight, idDom.scrollHeight, idDom.offsetHeight) let currentScrollPosition = scrollCursorStore.value; scrollCursorStore.value = scrollCursorStore.value - 400 if (scrollCursorStore.value < 0) { scrollCursorStore.value = 0; } Taro.nextTick(() => { console.log('scroll start...', idDom.scrollTop) let scrollInterval = setInterval(() => { if ( (idDom.scrollTop === scrollCursorStore.value) || (idDom.scrollTop < scrollCursorStore.value) ) { clearInterval(scrollInterval); console.log('scroll end...', idDom.scrollTop) } else { currentScrollPosition = currentScrollPosition - 50; idDom.scrollTop = currentScrollPosition; console.log('scrolling...', idDom.scrollTop) } }, 100) }) } const pageDown = function (e) { let idDom = document.getElementById('mainbody') console.log("===================", idDom.scrollTop, idDom.clientHeight, idDom.scrollHeight, idDom.offsetHeight) let currentScrollPosition = scrollCursorStore.value; scrollCursorStore.value = scrollCursorStore.value + 400 if (scrollCursorStore.value > (idDom.scrollHeight - idDom.offsetHeight )) { scrollCursorStore.value = idDom.scrollHeight - idDom.offsetHeight; } Taro.nextTick(() => { console.log('scroll start...', idDom.scrollTop) let scrollInterval = setInterval(() => { if ( (idDom.scrollTop === scrollCursorStore.value) || (idDom.scrollTop > scrollCursorStore.value) ) { clearInterval(scrollInterval); console.log('scroll end...', idDom.scrollTop) } else { currentScrollPosition = currentScrollPosition - (-50); idDom.scrollTop = currentScrollPosition; console.log('scrolling...', idDom.scrollTop) } }, 100) }) } return { contentTypeit, scrollId, lower, upper, scroll, sendMsg, pageUp, pageDown, } } } .main { height: 100%; width: 100%; background-color: rgba(204, 204, 204, 0.32); overflow-x: hidden; overflow-y: auto; } .mainbody { max-width: 100%; background-size: contain; padding-bottom: 100px; } .info { display: flex; margin: 10px 3%; } .content-question { color: #0b4eb4; background-color: #ffffff; padding-left: 20px; } .content-questionBlock { align-items: center; } .content { background-color: #fff; border-radius: 16px; padding: 20px; margin-left: 20px; max-width: 82%; height: 100%; font-size: 36px; font-family: PingFangSC-Medium, PingFang SC; font-weight: 500; color: #0a0a27; line-height: 60px; word-break: break-all; }

        效果调试:

      (1)打开浏览器,按下F12进入调试模式;

      (2)在console窗口,多次调用document.getElementById('sendMsg').click(),使得对话内容超出界面高度,可观察到自动滚动效果;

       (3)在console窗口,调用document.getElementById('pageUp').click(),可观察到向上滚动;接着调用document.getElementById('pageDown').click(),可观察到向下滚动。

        效果图如下:

建议

        方案一由于接口支持,滑动效果更平滑,但是翻页只能调到指定锚点,滑动步长不可控,大部分场景不能满足需求。

        方案二可以自行调整翻页的步长,按需滑动至指定高度,不过滑动动画需要自行实现,看起来卡顿感较强。

        总体来说,建议使用方案二。

参考链接:

        https://blog.csdn.net/weixin_46511008/article/details/126629361

        https://www.cnblogs.com/wq805/p/16399600.html

        https://www.cnblogs.com/hmy-666/p/14717484.html

        Taro 文档



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有