主要通過scroll-view組件來實現,比手動js獲取高度、判斷啥的更方便,而且官方支持
滾動到底
實現思路,通過錨點滾動實現,官方支持
<view id="chat-main">
<scroll-view class="chat-main-inner" :lower-threshold="15" :scroll-into-view="targetId" scroll-y="true" @scrolltolower="scrolltolower" @scroll="scroll">
<view class="chat-page">
<view class="chat-content">
你的內容....
</view>
<!-- 錨點1 -->
<view id="buttom-anchor"></view>
<!-- 錨點2 -->
<view id="buttom-anchor2"></view>
</view>
</scroll-view>
</view>
我們在scroll-view標籤內部新增兩個錨點,用於切換使用,點擊回到底部按鈕時,滾動條定位到錨點位置
const targetId = ref('');
const toContentBottom = () => {
let idName = targetId.value == 'buttom-anchor' ? 'buttom-anchor2' : 'buttom-anchor';
targetId.value = idName;
}
如果用户快速點擊,一個錨點是無法實現的,vue對快速執行相同事件貌似有節流,所以我們要兩個錨點來回切換
上滑取消置底
我們只需要保持這個思路即可:
1、如果滾動條置底了,那麼就一直自動置底
2、如果用户上滑了,取消自定置底
所以我們只需要判斷用户是否有上滑,如果是,則取消置底即可
scroll-view組件滾動條執行時會觸發@scroll="scroll"事件
import { ref, getCurrentInstance, onMounted } from 'vue';
const { proxy } = getCurrentInstance();
const query = uni.createSelectorQuery().in(proxy);
// 滾動時觸發
let contentDomHeight = 0
let defaultTop = 60; // 設置差異值
const isSureToBottom = ref(false);
const scroll = (e) => {
// h = scroll-view的全部高度 - 容器高度 - 已經滾動的高度
let h = e.detail.scrollHeight - contentDomHeight - e.detail.scrollTop;
// 按照上面的計算方法還不能拿到完全匹配的值,這其中有個差異值,我這裏設置60
// 如果滾動條距離底部大於兩倍差異值,説明當前滾動條不在底部
if (h > defaultTop * 2) {
// 不在底部
isSureToBottom.value = false;
} else {
// 滾動條距離底部 小於差異值,説明在底部範圍內
// 在底部
isSureToBottom.value = true;
}
};
// 獲取scroll-view組件外層的容器高度,一般是flex:1自動鋪滿視口的,所以高度可以正常拿到
const getContentDom = () => {
query
.select('#chat-main')
.boundingClientRect((data) => {
// data就是dom信息,拿到dom的高度
contentDomHeight = data.height;
})
.exec();
};
onMounted(() => {
getContentDom();
});
這樣就用户上滑取消自動置底功能就改造好了,我們在修改一下回到底部的邏輯,場景如下:
1、如果每次流式輸出,根據是否在底部標識判斷是否自動置底
2、用户可以設置強制置底功能,只需在toContentBottom(true)即可,否則根據滾動條位置自動判斷
3、toContentBottom事件是一個全局響應的事件,這裏我通過$mitt插件來實現全局事件監聽
const targetId = ref('');
// 回到底部
proxy.$mitt.on('toContentBottom', (e) => {
if (isSureToBottom.value || e) {
if (e) isSureToBottom.value = e;
let idName = targetId.value == 'buttom-anchor' ? 'buttom-anchor2' : 'buttom-anchor';
targetId.value = idName;
}
});
頁面使用
import { getCurrentInstance } from 'vue';
const toContentBottom = (state) => {
nextTick(() => {
proxy.$mitt.emit('toContentBottom', state);
});
};
// 在對應需要置底的位置調用即可
toContentBottom();
參考文檔:
scroll-view
獲取節點信息