灵感记录-滚动记录滚动高度

70 阅读3分钟

忽略 van-sticky van-notice-bar left-icon="volume-o" text

van-sticky

van-sticky van-notice-bar left-icon="volume-o" text=""

van-sticky

gpt给的demo
<template>
<div class="product-page">
  <!-- 顶部分类标签 -->
  <van-tabs
    v-model:active="activeTab"   <!-- 绑定当前激活的标签索引 -->
    sticky                      <!-- 吸顶效果 -->
    offset-top="0"
    swipeable                   <!-- 支持左右滑动切换 -->
    animated                    <!-- 开启切换动画 -->
  >
    <van-tab
      v-for="(category, index) in categories"
      :key="category.id"
      :title="category.name"
    >
      <!-- 商品列表 -->
      <div class="product-list">
        <van-card
          v-for="item in productsByCategory(category.id)"
          :key="item.id"
          :thumb="item.image"
          :title="item.name"
          :desc="item.desc"
        />
      </div>
    </van-tab>
  </van-tabs>
</div>
</template>

<script setup>
// 引入 Vue 组合式 API 和 Vant 组件
import { ref, reactive, watch, nextTick } from 'vue';
import { Tabs, Tab, Sticky, Card } from 'vant';

// Mock 数据:商品分类和商品列表
const categories = ref([
{ id: 1, name: '电子产品' },
{ id: 2, name: '服装' },
{ id: 3, name: '家居' },
]);
const products = ref([
{ id: 101, name: '手机', desc: '旗舰智能手机', image: 'https://via.placeholder.com/150', categoryId: 1 },
{ id: 102, name: '笔记本电脑', desc: '轻薄便携', image: 'https://via.placeholder.com/150', categoryId: 1 },
{ id: 201, name: '连衣裙', desc: '夏季新款', image: 'https://via.placeholder.com/150', categoryId: 2 },
{ id: 202, name: '牛仔裤', desc: '休闲百搭', image: 'https://via.placeholder.com/150', categoryId: 2 },
{ id: 301, name: '沙发', desc: '现代简约', image: 'https://via.placeholder.com/150', categoryId: 3 },
{ id: 302, name: '茶几', desc: '时尚耐用', image: 'https://via.placeholder.com/150', categoryId: 3 },
]);

// 当前激活的标签索引
const activeTab = ref(0);
// 保存每个分类的滚动位置
const scrollPositions = reactive({});

// 根据分类 ID 过滤商品列表
function productsByCategory(catId) {
return products.value.filter(item => item.categoryId === catId);
}

// 监听 activeTab 的变化,保存旧标签的滚动位置并恢复新标签的滚动位置
watch(activeTab, async (newIndex, oldIndex) => {
// 保存切换前标签的滚动值
scrollPositions[oldIndex] = window.scrollY || 0;
await nextTick();
// 恢复新标签的滚动值
window.scrollTo(0, scrollPositions[newIndex] || 0);
});
</script>

<style scoped>
.product-page {
width: 100%;
}
.product-list {
padding: 10px 0;
}
</style>

<template>
    <van-sticky>
        <van-notice-bar
            left-icon="volume-o"
            text="无论我们能活多久,我们能够享受的只有无法分割的此刻,此外别无其他。"
        />
    </van-sticky>
    <div class="my-swipe">
        <div>1</div>
        <div>2</div>
    </div>
    <div class="box" :class="scrollClass">
        <van-tabs
            v-model:active="active"
            :lazy-render="false"
            swipeable
            sticky
            offset-top="40"
            @scroll="scroll"
            @change="handleTabChange"
            :before-change="beforeChange"
            @click-tab="clickTab"
        >
            <van-tab
                v-for="index in 4"
                :title="'标签 ' + index"
                :key="index"
                :name="index"
                class="van-tab-111"
            >
                <pageF
                    :ref="(el) => setItemRef(el, index)"
                    :key="index"
                    :index="index"
                ></pageF>
            </van-tab>
        </van-tabs>
    </div>
</template>

<script setup lang="ts">
import { reactive, ref, onMounted, nextTick, onUnmounted } from "vue";

import pageF from "./PageF.vue";
import { getList1 } from "../api";
let active = ref(0);
let scrollClass = ref("scrollClass");
let refs = ref([]);
let scrollList = ref([]);
let isSticky = ref(false);
const setItemRef = (el, index) => {
    // console.log(index, "index");
    refs.value[index] = el;
};

let arr = [1, 2, 3, 4];
let p1 = new Promise((res, rej) => {
    rej("cuowu");
});
let arr2 = [];
arr.forEach((e, index) => {
    const url = `http://localhost:3001/api/items?page=${e}&limit=${10 + 10}`;
    arr2.push(fetch(url).then((res) => res.json()));
});

let isClick = false;
function scroll(temp) {
    console.log(temp)
    let el = document.querySelector(" .van-sticky--fixed");
    if(el){
        console.log('xitng')
    } else {
        scrollList.value = []
    }
    if(isClick) return
    // console.log(temp, "scroll", active.value);
    // console.log(document.documentElement.scrollTop, "scroll",'document.documentElement.scrollTop');
    // console.log(
    //     scrollList.value[active.value],
    //     "scrollList.value[active.value]"
    // );
    console.log('scroll')
    scrollList.value[active.value] = temp.scrollTop;
}

function clickTab(e) {
    console.log("clickTab");
    // console.log(e);
    active.value = e.name;
    // console.log(isSticky.value, scrollList.value[active.value]);

    // console.log("clickTab", scrollList.value);
}
// cont prevIndex = -1
async function handleTabChange(index) {
    console.log("handletabchange", active.value);
    await nextTick();
    isClick = true
    if (scrollList.value[active.value]) {
        setTimeout(async () => {
            
            // let offsetHeight = document.querySelectorAll('.van-swipe-item')[active.value].offsetHeight
            // console.log(offsetHeight, 'offsetHeight-out')
            document.documentElement.scrollTop = scrollList.value[active.value];
            // if(offsetHeight > 0){
            //     console.log(offsetHeight, 'offsetHeight')
            // }
            isClick = false
        }, 200);
        // console.log(document.querySelectorAll('.van-swipe-item')[active.value].offsetHeight, 'van-swipe-item.offsetHeight')
    } else {
        isClick = false
    }
}

function handleSwiper(direction) {
    // console.log(direction, "====");
}
function beforeChange(a) {
    // console.log("11beforeChange");
    // scrollList.value[active.value] = document.documentElement.scrollTop;
    // let el = document.querySelector(" .van-sticky--fixed");
    // console.log(el, "e", scrollList.value);
    // if (el) {
    //     isSticky.value = true;
    // } else {
    //     isSticky.value = false;
    // }

    return true;
}
onMounted(() => {
    nextTick(() => {
        Promise.allSettled(arr2)
            .then((res) => {
                console.log(res, "==========");
                res.forEach((e, index) => {
                    // console.log(refs.value)
                    refs.value[index + 1].addList(e.value.products, index);
                });
            })
            .catch((err) => {
                console.log(err);
            });
    });
    let e = document.querySelector(".box");
    let t = getTop(e);
    console.log(getTop(e), "getTop");
    function getTop(e) {
        var offset = e.offsetTop;
        if (e.offsetParent != null) {
            offset += getTop(e.offsetParent);
        }
        return offset;
    }
    // 添加滚动事件,简写,实际需要写卸载事件
    // window.onscroll = function(e){
    //    let top =  document.documentElement.scrollTop
    //    if(top >= 300){
    //         scrollClass.value = 'scrollClass'
    //     }else {
    //        scrollClass.value = ''

    //    }
    // }
});
</script>
<style lang="scss"></style>

<style lang="scss" scoped>
.tab-wrapper {
    width: 400px;
    height: 100vh;
    box-sizing: border-box;
    padding-top: 60px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;

    &__top {
        flex: none;
        background-color: #e7e7e7;
        display: flex;

        p {
            flex: 1;
            text-align: center;
            line-height: 2;
            cursor: pointer;

            &.active {
                background-color: #ccc;
                color: #fff;
            }
        }
    }

    &__bottom {
        background-color: #f2f2f2;
        flex: 1;
        position: relative;
        overflow: hidden;
    }
}

.tab-page {
}

.tab-page-box {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    overflow-y: auto;
}
img {
    width: 168px;
    height: 168px;
}
.tab-wrapper__bottom {
    background-color: pink;
}
.product-grid {
    display: flex;
    /* flex-wrap: wrap; */
}
.prod-item {
    flex: 1;
}

.good-item {
    border: 1px solid #777;
    border-radius: 4px;
    margin-bottom: 10px;
}

.product-item {
    margin: 10px;
    border: 1px solid #ccc;
    padding: 10px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.product-description {
    margin-top: 10px;
}
.my-swipe {
    color: #fff;
    font-size: 20px;
    line-height: 150px;
    text-align: center;
    background-color: #39a9ed;
}
.box {
    // padding: 10px;
    // margin: 20px;
}
</style>

``