uniapp 聊天记录插入的两种方式

问题:历史消息记录添加后 会不在之前浏览的地方

  • 上拉加载 加载添加的内容 滚动条 动(滚动条和顶部的距离变了) 显示的还是加载前的内容
  • 下拉加载 加载添加的内容 滚动条 没动(滚动条和顶部的距离没变) 显示的是新加载的内容

解决思路一 滚动条距离顶部的高度

  • 添加元素之前获取与底部的距离 底部的距离 = 元素.scrollHeight - 元素.scrollTop
  • 添加元素之后元素的滚动条高度 scrollTop = 元素.scrollHeight - 底部的距离
  • 元素滚动上去的距离就是现在的总高度减去刚刚的固定底部
<template>
  <view class="content">
    <!-- 主体部分 -->
    <view class="main">
      <scroll-view scroll-y="true" :upper-threshold="a"
       :scroll-top="sTop"
       @scrolltoupper="scrolltoupper" 
       @scrolltolower="scrolltolower" 
       @scroll="scroll"
       >
        <view class="loading">
          <text>没有更多数据了</text>
        </view>
        <view v-for="(item,index) in list" :id="'a_'+index" :key="index">{{item.id}}</view>
      </scroll-view>
    </view>
  </view>
</template>

<script>
  import AppHeader from "@/components/app-header.vue";
  export default {
    components: { AppHeader },
    data() {
      return {
        a: 100, // 触发顶部加载方法的距离 可不写 默认50
        sTop: '0', // 滚动条的位置
        list: [
          {id:1},{id:2},{id:3},{id:4}
        ]
      };
    },
    created() {
      this.newScrollHeight = 0; // 记录新的高度
      this.oldScrollHeight = 0; // 记录原先的高度
      this.scrollTop = 0; // 记录 底部的距离
    },
    methods: {
      scrolltoupper: function(e) {
        let arr = []
        for(let i = -1; i >= -4; --i){
          arr.unshift({id: this.list[0].id-1 + i})
        }
        // this.list.concat(arr)
        this.list.unshift(...arr);
        this.scrollIntoIndex = `a_${20}`
      },
      /**
       * 问题:
       *  上拉加载 加载添加的内容 滚动条 动(滚动条和顶部的距离变了) 显示的还是加载前的内容
       *  下拉加载 加载添加的内容 滚动条 没动(滚动条和顶部的距离没变) 显示的是新加载的内容
       * 解决思路:
       *  与上拉加载反过来, 那就是保证滚动条与底部的距离不变
       *  添加元素之前获取与底部的距离 底部的距离 = 元素.scrollHeight - 元素.scrollTop
       *  添加元素之后元素的滚动条高度 元素.scrollTop = 元素.scrollHeight - 底部的距离
       *  
       *  元素滚动上去的距离就是现在的总高度减去刚刚的固定底部
       *  scrollHeight: 滚动条总高度 scrollTop: 滚动条距离顶部的高度
       * */
      scroll: function(e) {
        const SCROLL_HEIGHT = e.target.scrollHeight; // 当前的滑动区域高度
        const SCROLL_TOP = e.target.scrollTop; // 滚动条位置
        this.newScrollHeight = SCROLL_HEIGHT;
        
        if(this.oldScrollHeight==0) {
          this.oldScrollHeight = this.newScrollHeight;
        }
        if(this.newScrollHeight != this.oldScrollHeight) {
          this.scrollTop = this.oldScrollHeight - SCROLL_TOP; // -> 计算之前滚动条离底部的距离
          this.sTop = this.newScrollHeight - this.scrollTop; // -> 计算滚动条因在什么位置
          this.oldScrollHeight = this.newScrollHeight;
        }
      }
    },
  }
</script>

<style lang="scss">
// 主体部分
.content {
  background-color: $uni-bg-color;
  .main {
    // padding: 0 $uni-spacing-row-base;
    // box-sizing: border-box;
    scroll-view {
      width: 100%;
      height: 100%;

      overflow-anchor: auto;
      
      vertical-align: middle;
      display: flex;
      flex-direction: column-reverse;
      
      view {
        padding: 0 $uni-spacing-row-base;
        box-sizing: border-box;
      }
      view:nth-child(n) {
        width: 100%;
        height: 200rpx;
        background-color: antiquewhite;
      }
      view:nth-child(2n) {
        width: 100%;
        height: 250rpx;
        background-color: aqua;
        margin-top: 10rpx;
      }
      .loading {
        width: 100%;
        height: 60rpx !important;
      }
    }
  }
}
</style>
解决思路二 scroll-into-view属性

scroll-into-view属性 具体情况请看官方文档 uniapp scroll-view标签

<template>
  <!-- 聊天页面 -->
  <view class="content">
    <!-- 主体部分 -->
    <view class="main">
      <scroll-view scroll-y="true"
       :scroll-top="scrollTop"
       :scroll-anchoring="true"
       @scrolltoupper="scrolltoupper" 
       :scroll-into-view="scrollIndex"
       >
        <view class="loading">
          <text>没有更多数据了</text>
        </view>
        <view v-for="(item,index) in list" :id="'id_'+ item.id" :key="index">{{item.id}}</view>
      </scroll-view>
    </view>
  </view>
</template>

<script>
  export default {
    data() {
      return {
        scrollTop: '0',
        scrollIndex: "",
        list: [
          {id:1},{id:2},{id:3},{id:4},
        ]
      };
    },
    created() {
      this.first = 'id_1';
      // 不在created中调用的给方法的话 第一次触顶 不会被定位 可以去掉这句 取updated中打印下scrollIndex 第一次触顶 只会渲染更新一次 之后都会更新两次
      this.scrolltoupper();
    },
    methods: {
      scrolltoupper: function(e) {
        let arr = [];
        this.first = `id_${this.list[0].id}`;
        for(let i = -1; i >= -4; --i){
          arr.unshift({id: this.list[0].id-1 + i})
        }
        this.list.unshift(...arr);
        // 此处用 nextTick 是因为需要保证 页面以及渲染完成 也可以在 updated 钩子中执行赋值
        // 没有中一句的话不会定位到之前的位置
        this.$nextTick(()=>{
          this.scrollIndex = this.first;
        })
      }
    },
  }
</script>

<style lang="scss">
// 主体部分
.content {
  background-color: $uni-bg-color;
  .main {
    // padding: 0 $uni-spacing-row-base;
    // box-sizing: border-box;
    scroll-view {
      width: 100%;
      height: calc(100% - 0rpx);

      overflow-anchor: auto;
      
      vertical-align: middle;
      display: flex;
      flex-direction: column-reverse;
      
      view {
        padding: 0 $uni-spacing-row-base;
        box-sizing: border-box;
      }
      view:nth-child(n) {
        width: 100%;
        height: 200rpx;
        background-color: antiquewhite;
      }
      view:nth-child(2n) {
        width: 100%;
        height: 250rpx;
        background-color: aqua;
        margin-top: 10rpx;
      }
      .loading {
        width: 100%;
        height: 60rpx !important;
      }
    }
  }
}
</style>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值