当前位置:   article > 正文

uni-app(vue3)实现对话界面,滚动条处于最下方!

uni-app(vue3)实现对话界面,滚动条处于最下方!

最近在做一个自己的全栈项目,前端用的uni-app,主要也是想巩固一下uni-app这方面的知识,其中有一个页面,涉及到ai聊天的功能,我理想型是类似文心一言或者微信聊天页面的效果,但是研究半天,发现uni-app的scroll-view这个内置组件并不能像写pc的滚动条那么灵活,因为在小程序或者app没有dom这个概念,网上找了一堆资源,基本上全是vue2版本的,密密麻麻的文字,真是看不下去,自己动手,丰衣足食。

一、代码部分:
  1. <template>
  2. <view class="content">
  3. <view class="container">
  4. <!--简介: scroll-with-animation:动画,开启有一个过渡效果;scroll-into-view:向指定id滚动 -->
  5. <scroll-view @scrolltoupper="addInfo" scroll-with-animation :scroll-into-view="item" class="Scroll" scroll-y="true">
  6. <view class="box" v-for="(item,index) in dialogList" :key="index" :id="`item-${index}`">
  7. <view class="input">
  8. <p class="i">{{ item.input }}</p>
  9. </view>
  10. <view class="output">
  11. <p class="o">{{ item.output }}</p>
  12. </view>
  13. </view>
  14. </scroll-view>
  15. </view>
  16. <view class="footer">
  17. <view class="ipt">
  18. <input placeholder="请输入内容" class="IPT" v-model="sendInfo"/>
  19. </view>
  20. <view class="btn">
  21. <button class="BTN" type="primary" @click="send">发送</button>
  22. </view>
  23. </view>
  24. </view>
  25. </template>
  26. <script setup>
  27. import { ref,watch,nextTick } from 'vue';
  28. // scroll-into-view指向的id值
  29. let item = ref('')
  30. // 发送的内容
  31. let sendInfo = ref("")
  32. //模拟的虚拟数据
  33. const dialogList = ref([
  34. {
  35. input:"你好",
  36. output:"你好,很高兴认识你!"
  37. },
  38. {
  39. input:"你好",
  40. output:"你好,很高兴认识你!"
  41. },
  42. {
  43. input:"你好",
  44. output:"首先,世界上菜品的总数是一个难以准确估量的数字。不同的地区、文化、民族、厨师等都会创造出新的菜品,同时传统的菜品也在不断地发展和变化。因此,即使尝试估算,这个数字也会是一个非常大的数。其次,一个人一生的天数也是有限的。假设一个人活到80岁,那么一生大约有29,200天(不考虑闰年)。这个数字与世界上菜品的总数相比,显然是微不足道的。"
  45. },
  46. {
  47. input:"你好",
  48. output:"你好,很高兴认识你!"
  49. },
  50. {
  51. input:"你好",
  52. output:"你好,很高兴认识你!"
  53. },
  54. {
  55. input:"你好",
  56. output:"你好,很高兴认识你!"
  57. },
  58. {
  59. input:"你好",
  60. output:"你好,很高兴认识你!"
  61. },
  62. {
  63. input:"你好",
  64. output:"你好,很高兴认识你!"
  65. },
  66. {
  67. input:"你好",
  68. output:"你好,很高兴认识你!"
  69. },
  70. {
  71. input:"你好",
  72. output:"你好,很高兴认识你!"
  73. },
  74. {
  75. input:"你好",
  76. output:"你好,很高兴认识你!"
  77. },
  78. {
  79. input:"你好",
  80. output:"你好,很高兴认识你!"
  81. },
  82. {
  83. input:"你好",
  84. output:"你好,很高兴认识你!"
  85. },
  86. {
  87. input:"你好",
  88. output:"你好,很高兴认识你!"
  89. }
  90. ])
  91. // 动态更新item的值
  92. watch(dialogList,(newval,oldval)=>{
  93. // 重新赋值item,延迟到dom更新之后进行,否则没效果
  94. nextTick(()=>{
  95. item.value = "item-" + (newval.length - 1)
  96. })
  97. },{
  98. deep:true, //深度监视
  99. immediate:true //初始化立即执行
  100. })
  101. // 发送
  102. const send = () => {
  103. let obj = {
  104. input:sendInfo.value,
  105. output:"......"
  106. }
  107. // 追加数据
  108. dialogList.value.push(obj)
  109. // 清空输入框
  110. sendInfo.value = ""
  111. // 模拟返回消息,延迟2秒,开发环境下可以把这里替换成网络请求的逻辑
  112. setTimeout(()=>{
  113. dialogList.value[dialogList.value.length - 1].output = "别说了,我知道你很帅!"
  114. },2000)
  115. }
  116. // 触顶加载更多
  117. const addInfo = () => {
  118. console.log('触顶加载更多!')
  119. }
  120. </script>
  121. <style lang="scss" scoped>
  122. .content {
  123. width: 100vw;
  124. height: 100vh;
  125. background: gainsboro;
  126. .container {
  127. width: 100%;
  128. height: 85vh;
  129. padding: 10rpx 10rpx 10rpx 20rpx;
  130. box-sizing: border-box;
  131. .Scroll {
  132. width: 100%;
  133. height: 85vh;
  134. .box {
  135. width: 100%;
  136. padding: 0 10rpx 0 0;
  137. box-sizing: border-box;
  138. .output {
  139. width: 100%;
  140. display: flex;
  141. justify-content: flex-start;
  142. margin: 30rpx 0;
  143. .o {
  144. max-width: 70vw;
  145. height: auto;
  146. padding: 10rpx;
  147. background-color: rgb(192,192,192);
  148. border-top-left-radius: 10rpx;
  149. border-top-right-radius: 10rpx;
  150. border-bottom-right-radius: 10rpx;
  151. }
  152. }
  153. .input {
  154. width: 100%;
  155. display: flex;
  156. justify-content: flex-end;
  157. margin: 20rpx 0;
  158. .i {
  159. max-width: 70vw;
  160. height: auto;
  161. padding: 10rpx;
  162. background-color: rgb(28,217,128);
  163. border-top-left-radius: 10rpx;
  164. border-top-right-radius: 10rpx;
  165. border-bottom-left-radius: 10rpx;
  166. }
  167. }
  168. }
  169. }
  170. }
  171. .footer {
  172. width: 100vw;
  173. height: 10vh;
  174. margin-top: 20rpx;
  175. background-color: #e3f9fd;
  176. display: flex;
  177. justify-content: center;
  178. align-items: center;
  179. padding: 10rpx 20rpx 0 20rpx;
  180. box-sizing: border-box;
  181. .ipt {
  182. flex: 6;
  183. height: 100%;
  184. display: flex;
  185. justify-content: center;
  186. align-items: center;
  187. .IPT {
  188. height: 80rpx;
  189. width: 100%;
  190. line-height: 80rpx;
  191. background-color: white;
  192. border-radius: 10rpx;
  193. margin-right: 10rpx;
  194. padding-left: 10rpx;
  195. }
  196. }
  197. .btn {
  198. flex: 1.5;
  199. .BTN {
  200. height: 80rpx;
  201. line-height: 80rpx;
  202. border-radius: 10rpx;
  203. margin-right: 10rpx;
  204. }
  205. }
  206. }
  207. }
  208. </style>

二、效果展示

三、描述

整体上就是使用uni-app的scroll-into-view这个方法实现的,通过vue的watch,来监视聊天内容,变化了则更新scroll-into-view属性所关注的id,这里需要动态的给列表渲染的每一项设置一个动态的id,id是不能重复的,大致逻辑就是这样,具体的看代码部分就好,实在看不懂就自己贴一下代码到自己项目,我这也是个demo样式,能直接跑起来的,希望对你有帮助!

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/698558
推荐阅读
相关标签
  

闽ICP备14008679号