问题:历史消息记录添加后 会不在之前浏览的地方
- 上拉加载 加载添加的内容 滚动条 动(滚动条和顶部的距离变了) 显示的还是加载前的内容
- 下拉加载 加载添加的内容 滚动条 没动(滚动条和顶部的距离没变) 显示的是新加载的内容
解决思路一 滚动条距离顶部的高度
- 添加元素之前获取与底部的距离 底部的距离 = 元素.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>