5 分钟带你实现一个多页签返回定位的列表组件

简介: 实现一个多页签返回定位的列表组件

a429aaef1bd8b9ccc59a1619ce30f16.png

项目地址(持续迭代中):github.com/jyliyue/vit…

系列文章:

前言

移动端有个常见的业务场景,在列表页滑动进入某一个详情页,回退的时候希望列表能够停留在原先访问的位置,本篇便针对这一需求,带大家一起完善我们的列表组件,顺便结合这个列表组件 实现一个多标签列表返回定位 的案例

思路

这一功能的实现网上已有很多相关案例,但大多都使用了监听滚动事件,动态的记录滚动位置,但分析下来这一功能实现实际上并不需要实时监听,只需要在 离开页面时记录滚动位置 ,重新进入页面时赋值就好了

按照这个思路,我们需要完成三步:

  • 缓存组件,即切换页面时页面组件不会被销毁
  • 记录位置,页面离开时记录滚动条位置
  • 重新定位,重新进入页面时定位到之前记录的位置

缓存组件

这里我们可以用之前已经实现的 <app-router-view> 组件来实现,借助 keepAlive 帮助我们实现页面离开时缓存页面的状态

a9c6a300cbc591882e8dfba58a6ff0c.png

关于 keepAlive 的相关讲解大家可以阅读我的另一篇文章,这里就不赘述了

传送门:5 分钟带你实现一个可控制缓存销毁的 keepAlive 组件

记录位置

这里使用我们之前封装好的列表组件 <app-list> 来进行改造

我们写一个通用方法 useScrollCache 来完成整一块滚动定位缓存这一需求的逻辑,首先我们定义一个 listRef 来获取我们列表盒子的 dom 元素,然后通过路由钩子 onBeforeRouteLeave 当页面离开前,把当前的滚动位置 listRef.value.scrollTop 记录下来,这样就完成了位置记录

<script setup>
import { onBeforeRouteLeave } from 'vue-router'
const { listRef } = useScrollCache()
/**
 * @description: 滚动定位缓存
 */
function useScrollCache() {
    const listRef = ref(null)
    let scrollTop = 0
    onBeforeRouteLeave(() => {
        scrollTop = listRef.value.scrollTop
    })
    return {
        listRef
    }
}
</script>
<template>
    <div class="app-list" ref="listRef">
        <van-pull-refresh
            v-model="refreshing"
            :success-text="successText"
            @refresh="onRefresh"
        >
            <van-list
                v-model:loading="loading"
                @load="onLoad"
                :finished="finished"
                :finished-text="finishedText"
                :offset="100"
            >
                <slot name="content" :list="list"> </slot>
            </van-list>
        </van-pull-refresh>
    </div>
</template>
<style lang="scss" scoped>
.app-list {
    height: 100%;
    overflow-y: auto;
}
</style>
复制代码

重新定位

因为我们使用了keepAlive,当我们离开重新进入页面时,会触发 onActivated 生命周期,我们只要在这里把之前记录的位置重新赋值给列表就可以了

完整代码

<script setup>
import { onBeforeRouteLeave } from 'vue-router'
const { listRef } = useScrollCache()
/**
 * @description: 滚动定位缓存
 */
function useScrollCache() {
    const listRef = ref(null)
    let scrollTop = 0
    onActivated(() => {
        // 激活时重新定位
        listRef.value.scrollTop = scrollTop
    })
    onBeforeRouteLeave(() => {
        // 离开记录位置
        scrollTop = listRef.value.scrollTop
    })
    return {
        listRef
    }
}
</script>
复制代码

这样,我们一个简单的列表返回记录位置的功能就实现啦,来看看效果

e00668fe9aeeb8bb40c82ed463412a0.png

做一个多 Tab 列表切换案例

现在来一起使用我们封装的组件实现一个多页签列表的案例

我们使用 <van-tab> 来做多标签,使用 setTimeout 来模拟数据请求,这里需要注意一点需要把 :animated="true" 设置一下,由于不开启动画效果的话,<app-list> 实例在切换时会被销毁掉,这样处理起来逻辑就变复杂了,这里我们使用动画过度,操作体验也会更友好一点

<script setup>
// This starter template is using Vue 3 <script setup> SFCs
const options1 = {
    getData: () => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({
                    data: new Array(20),
                    total: 30
                })
            }, 1000)
        })
    }
}
const options2 = {
    getData: () => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({
                    data: new Array(20),
                    total: 30
                })
            }, 1000)
        })
    }
}
const activeName = ref('a')
</script>
<template>
    <app-page>
        <van-tabs
            class="app-tab-list"
            v-model:active="activeName"
            :animated="true"
        >
            <van-tab title="标签 1" name="a">
                <app-list :options="options1">
                    <template #content="{ list }">
                        <van-cell
                            v-for="(item, index) in list"
                            :key="index"
                            :title="index"
                        />
                    </template>
                </app-list>
            </van-tab>
            <van-tab title="标签 2" name="b">
                <app-list :options="options2">
                    <template #content="{ list }">
                        <van-cell
                            v-for="(item, index) in list"
                            :key="index"
                            :title="index"
                        />
                    </template>
                </app-list>
            </van-tab>
            <van-tab title="标签 3" name="c"> c </van-tab>
        </van-tabs>
    </app-page>
</template>
复制代码

大家来一起看看效果

b48a1b0c9f64753adb33d4ad023d300.png

好了,本篇的内容比较简单也比较实用,希望能对大家完成需求有所帮助,下一篇,我们将对 Vue 自定义指令相关的知识点做讲解,并带大家一起实现一些移动端常用的指令,例如防抖截流,长按事件监听,点击复制文本等等,敬请期待!

相关文章
|
5月前
|
存储 前端开发 数据可视化
ThinkPHP在线客服系统源码_可视化开源在线网页客服聊天系统源码uniapp
本文详解在线客服系统源码构建,涵盖系统架构、技术选型、代码实现与功能特性,为开发者和企业提供参考。
|
开发工具 git
从 github 执行 git clone 一个大的项目时提示 error: RPC failed
目前克隆一个比较大的项目,出现RPC failed的错误 Cloning into 'bigfiles'... remote: Counting objects: 190, done. remote: Compressing objects: 100% (157/157), done.
4271 0
|
人工智能 架构师 项目管理
软件工程师,超过35岁怎么办
软件工程师,超过35岁怎么办
460 71
|
消息中间件 存储 安全
【深入浅出RocketMQ原理及实战】「底层原理挖掘系列」透彻剖析贯穿RocketMQ的消息顺序消费和并发消费机制体系的原理分析
【深入浅出RocketMQ原理及实战】「底层原理挖掘系列」透彻剖析贯穿RocketMQ的消息顺序消费和并发消费机制体系的原理分析
515 0
|
JSON 测试技术 API
黑马商城 Elasticsearch从入门到部署 RestClient操作文档
这篇文章详细介绍了如何使用Java的RestHighLevelClient客户端与Elasticsearch进行文档操作,包括新增、查询、删除、修改文档以及批量导入文档的方法,并提供了相应的代码示例和操作步骤。
|
人工智能 Cloud Native 数据管理
重磅升级,阿里云发布首个“Data+AI”驱动的一站式多模数据平台
阿里云发布首个AI多模数据管理平台DMS,助力业务决策提效10倍
1676 17
|
存储 关系型数据库 MySQL
MySQL——如何快速删除大表
MySQL——如何快速删除大表
270 0
|
Java Maven
构建Springboot项目、实现简单的输出功能、将项目打包成可以执行的JAR包(详细图解过程)
这篇文章详细介绍了构建SpringBoot项目的过程,包括新建工程、选择环境配置、添加依赖、项目结构说明,并演示了如何编写一个简单的Controller控制器实现输出功能,最后讲解了如何使用Maven将项目打包成可执行的JAR包,并提供了运行JAR包的命令和测试效果。
构建Springboot项目、实现简单的输出功能、将项目打包成可以执行的JAR包(详细图解过程)
|
缓存 JavaScript
vue 页面缓存 keep-alive(含配置清除页面缓存 exclude,局部缓存,动态缓存,路由控制缓存 $route.meta.keepAlive)
vue 页面缓存 keep-alive(含配置清除页面缓存 exclude,局部缓存,动态缓存,路由控制缓存 $route.meta.keepAlive)
1597 0
|
JavaScript
vue中一个标签中含有多个class(其中包含三元表达式)的写法
vue中一个标签中含有多个class(其中包含三元表达式)的写法
747 2