赞
踩
最近在做一个自己的全栈项目,前端用的uni-app,主要也是想巩固一下uni-app这方面的知识,其中有一个页面,涉及到ai聊天的功能,我理想型是类似文心一言或者微信聊天页面的效果,但是研究半天,发现uni-app的scroll-view这个内置组件并不能像写pc的滚动条那么灵活,因为在小程序或者app没有dom这个概念,网上找了一堆资源,基本上全是vue2版本的,密密麻麻的文字,真是看不下去,自己动手,丰衣足食。
- <template>
- <view class="content">
- <view class="container">
- <!--简介: scroll-with-animation:动画,开启有一个过渡效果;scroll-into-view:向指定id滚动 -->
- <scroll-view @scrolltoupper="addInfo" scroll-with-animation :scroll-into-view="item" class="Scroll" scroll-y="true">
- <view class="box" v-for="(item,index) in dialogList" :key="index" :id="`item-${index}`">
- <view class="input">
- <p class="i">{{ item.input }}</p>
- </view>
- <view class="output">
- <p class="o">{{ item.output }}</p>
- </view>
- </view>
- </scroll-view>
- </view>
- <view class="footer">
- <view class="ipt">
- <input placeholder="请输入内容" class="IPT" v-model="sendInfo"/>
- </view>
- <view class="btn">
- <button class="BTN" type="primary" @click="send">发送</button>
- </view>
- </view>
- </view>
- </template>
-
- <script setup>
- import { ref,watch,nextTick } from 'vue';
-
- // scroll-into-view指向的id值
- let item = ref('')
-
- // 发送的内容
- let sendInfo = ref("")
-
- //模拟的虚拟数据
- const dialogList = ref([
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"首先,世界上菜品的总数是一个难以准确估量的数字。不同的地区、文化、民族、厨师等都会创造出新的菜品,同时传统的菜品也在不断地发展和变化。因此,即使尝试估算,这个数字也会是一个非常大的数。其次,一个人一生的天数也是有限的。假设一个人活到80岁,那么一生大约有29,200天(不考虑闰年)。这个数字与世界上菜品的总数相比,显然是微不足道的。"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- },
- {
- input:"你好",
- output:"你好,很高兴认识你!"
- }
- ])
-
- // 动态更新item的值
- watch(dialogList,(newval,oldval)=>{
- // 重新赋值item,延迟到dom更新之后进行,否则没效果
- nextTick(()=>{
- item.value = "item-" + (newval.length - 1)
- })
- },{
- deep:true, //深度监视
- immediate:true //初始化立即执行
- })
-
- // 发送
- const send = () => {
- let obj = {
- input:sendInfo.value,
- output:"......"
- }
- // 追加数据
- dialogList.value.push(obj)
- // 清空输入框
- sendInfo.value = ""
- // 模拟返回消息,延迟2秒,开发环境下可以把这里替换成网络请求的逻辑
- setTimeout(()=>{
- dialogList.value[dialogList.value.length - 1].output = "别说了,我知道你很帅!"
- },2000)
- }
-
- // 触顶加载更多
- const addInfo = () => {
- console.log('触顶加载更多!')
- }
-
- </script>
-
- <style lang="scss" scoped>
- .content {
- width: 100vw;
- height: 100vh;
- background: gainsboro;
- .container {
- width: 100%;
- height: 85vh;
- padding: 10rpx 10rpx 10rpx 20rpx;
- box-sizing: border-box;
- .Scroll {
- width: 100%;
- height: 85vh;
- .box {
- width: 100%;
- padding: 0 10rpx 0 0;
- box-sizing: border-box;
- .output {
- width: 100%;
- display: flex;
- justify-content: flex-start;
- margin: 30rpx 0;
- .o {
- max-width: 70vw;
- height: auto;
- padding: 10rpx;
- background-color: rgb(192,192,192);
- border-top-left-radius: 10rpx;
- border-top-right-radius: 10rpx;
- border-bottom-right-radius: 10rpx;
- }
- }
- .input {
- width: 100%;
- display: flex;
- justify-content: flex-end;
- margin: 20rpx 0;
- .i {
- max-width: 70vw;
- height: auto;
- padding: 10rpx;
- background-color: rgb(28,217,128);
- border-top-left-radius: 10rpx;
- border-top-right-radius: 10rpx;
- border-bottom-left-radius: 10rpx;
- }
- }
- }
- }
- }
- .footer {
- width: 100vw;
- height: 10vh;
- margin-top: 20rpx;
- background-color: #e3f9fd;
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 10rpx 20rpx 0 20rpx;
- box-sizing: border-box;
- .ipt {
- flex: 6;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- .IPT {
- height: 80rpx;
- width: 100%;
- line-height: 80rpx;
- background-color: white;
- border-radius: 10rpx;
- margin-right: 10rpx;
- padding-left: 10rpx;
- }
- }
- .btn {
- flex: 1.5;
- .BTN {
- height: 80rpx;
- line-height: 80rpx;
- border-radius: 10rpx;
- margin-right: 10rpx;
- }
- }
- }
- }
- </style>
二、效果展示
三、描述
整体上就是使用uni-app的scroll-into-view这个方法实现的,通过vue的watch,来监视聊天内容,变化了则更新scroll-into-view属性所关注的id,这里需要动态的给列表渲染的每一项设置一个动态的id,id是不能重复的,大致逻辑就是这样,具体的看代码部分就好,实在看不懂就自己贴一下代码到自己项目,我这也是个demo样式,能直接跑起来的,希望对你有帮助!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。