Vant实践之上拉加载及下拉刷新

本文作者系360奇舞团前端开发工程师

亲爱的小伙伴们,《奇舞精选》正在参加掘金年度人气创作者评选活动。请您动动发财的小手,帮《奇舞精选》投上宝贵的两票。我们也会再接再厉创作出更加优质的技术文章!

Vant组件

简介

Vant 是有赞前端团队开源的一套轻量、可靠的移动端组件库。

安装

通过 npm 安装

在现有项目中使用 Vant 时,可以通过 npm 进行安装:

bash 复制代码
# Vue3 项目,安装最新版 Vant
npm i vant

引入Vant组件

基础用法:

例:

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import Vant from 'vant'
import 'vant/lib/index.css'
const app =createApp(App)
app.use(Vant)
app.mount('#app')

自动按需引入请参考vant官方指导意见:vant-contrib.gitee.io/vant/#/zh-C...

Vue Router组件

安装

在现有项目中使用Vue Router 时,可以通过 npm 进行安装:

bash 复制代码
npm install vue-router@4

引入Vue Router组件

1、在src目录下创建一个文件夹views,然后在内创建两个vue页面,分别为AppHome和AppUser,用作路由跳转;

2、在src目录下创建一个文件夹router,然后在文件夹内创建一个router.js 文件。然后在router.js文件内添加如下代码:

js 复制代码
import { createRouter, createWebHistory  } from 'vue-router'
import AppHome from '@/views/AppHome'
import AppUser from '@/views/AppUser'
import AppClassify  from '@/views/AppClassify'

const routes =[
     { 
        path: '/', 
        component: AppHome
     },
    {
        path: '/appClassify',
        name: 'appClassify',
        component: AppClassify
    },
     {
         path:'/appUser',
         name:'appUser',
         component: AppUser 
     }
]

const router =createRouter({
    history:createWebHistory(),
    routes
})

export default router

3、在main.js文件中引入路由,这样就可以在项目中使用Vue Router组件

js 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router  from './router/router'
const app =createApp(App)
app.use(router)
app.mount('#app')

axios http库

安装

在现有项目中使用 axios 时,可以通过 npm 进行安装:

bash 复制代码
npm install axios

axios 网络请求封装

1、在src目录下创建一个文件夹utils,然后在文件夹内创建一个request.js 文件。

2、在request.js 文件内创建基础API接口,如下:

js 复制代码
import axios from 'axios'
const request=axios.create({
    baseURL: 'https://www.example.com'
})
export default request;

3、在src目录下再次创建一个文件夹API,然后在文件内创建一个articleListApi.js文件,实现列表数据请求接口,用于后续填充列表数据。

js 复制代码
import request from '@/utils/request.js'

export const getArticleListApi = function(page,limit){
    return request.get('/articles',{
        params: {
            _page: page,
            _limit: limit
        }
    })
}

使用Vant自定义组件

van-tabbar添加

在App.vue 文件内添加van-tabbar组件,并搭配路由自动切换标签。App.vue 实现如下:

vue 复制代码
<template>
<router-view/>
  <div id="home-container">
    <!--实现tabbar功能,并搭配路由自动切换标签-->
    <van-tabbar route v-model="active" active-color="#1989fa" inactive-color="#000">
      <van-tabbar-item  to="/" icon="home-o">首页</van-tabbar-item>
      <van-tabbar-item  to="/appUser" icon="user-o">我的</van-tabbar-item>
    </van-tabbar>
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  name: 'App',
  setup() {
    const active = ref(0);
    return { active };
  },
}
</script>

<style lang="less" scoped>

</style>

创建图文混排单元格组件

在src目录下的components文件夹内创建图文混排单元格组件AppArticleInfo.vue。实现如下:

vue 复制代码
<template>
  <div>
    <van-cell>
      <!--标题区域插槽-->
      <template #title>
        <div class="title-box">
          <!--标题-->
          <span>{{ title }}</span>
          <!--单张图片-->
          <img :src="cover.images[0]" v-if="cover.type === 1" alt="" class="thumb" />
        </div>
        <!--三张图片-->
        <div class="thumb-box" v-if="cover.type === 3">
          <img
            :src="item"
            v-for="(item, i) in cover.images"
            :key="i"
            alt=""
            class="thumb"
          />
        </div>
      </template>
      <!--label 区域的插槽-->
      <template #label>
        <div class="label-box">
          <span>
            作者 {{ author }} &nbsp;&nbsp; {{ commCount }} 评论 &nbsp;&nbsp; 发布时间
            {{ time }}</span
          >
          <!--关闭按钮-->
          <van-icon name="cross" />
        </div>
      </template>
    </van-cell>
  </div>
</template>

<script setup>
//自定义属性
defineProps({
  title: {
    //文章标题
    type: String,
    default: "",
  },
  author: {
    //作者
    type: String,
    default: "",
  },
  commCount: {
    //评论数
    type: parseInt,
    default: 0,
  },
  time: {
    //发布时间
    type: String,
    default: "",
  },
  cover: {
    //封面的信息对象
    type: Object,
    default: function () {
      return { type: 0 };
    },
  },
});
</script>

<style lang="less" scoped>
.label-box {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.thumb {
  width: 113px;
  height: 70px;
  background-color: #f8f8f8;
  object-fit: cover;
}

.title-box {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.thumb-box {
  display: flex;
  justify-content: space-between;
}
</style>

下拉刷新及上拉加载更多

在AppHome.vue 页面内引入图文混排组件AppArticleInfo.vue,并实现下拉刷新和上拉加载更多

vue 复制代码
<template>
  <div class="home-container">
    <van-nav-bar title="首页" :fixed="true"></van-nav-bar>
    <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
      <van-list
        v-model="loading"
        :finished="finished"
        finished-text="没有更多了"
        @load="loadMore"
      >
        <app-article-info
          v-for="item in state.list"
          :key="item.id"
          :title="item.title"
          :author="item.aut_name"
          :time="item.pubdate"
          :comm-count="item.comm_count"
          :cover="item.cover"
        ></app-article-info>
      </van-list>
    </van-pull-refresh>
  </div>
</template>
<script>
import { getArticleListApi } from "@/api/articleListApi.js";
import AppArticleInfo from "@/components/AppArticleInfo.vue";
import { ref, onMounted, reactive } from "vue";
export default {
  name: "AppHome",
  components: {
    AppArticleInfo,
  },
  setup() {
    const page = ref(1);
    const limit = ref(10);
    const refreshing = ref(false);
    const loading = ref(true);
    const finished = ref(false);
    const state = reactive({
      list: [],
    });

    onMounted(() => {
      initArticleList(page.value, limit.value);
    });

    async function initArticleList() {
      const { data: res } = await getArticleListApi(page.value, limit.value);
      if (refreshing.value === true) {
        refreshing.value = false;
        state.list = [];
        state.list = res;
        loading.value = false;
        console.log("refreshing", refreshing.value, finished.value);
      } else {
        state.list = [...state.list, ...res];
        console.log("loadMore",loading.value);
        if (res.length === 0) {
          finished.value = true;
        }
        loading.value = false;
      }

      console.log("返回数据:", state.list, page.value);
    }

    function loadMore() {
      page.value++;
      initArticleList();
      console.log("上拉", page.value);
    }

    function onRefresh() {
      refreshing.value = true;
      finished.value = false;
      page.value = 1;
      initArticleList();
      console.log("下拉", page.value);
      // console.log("返回数据:", state.list, page.value, loading.value, finished.value);
    }

    return {
      refreshing,
      loading,
      finished,
      page,
      limit,
      state,
      initArticleList,
      loadMore,
      onRefresh,
    };
  },
};
</script>

<style lang="less" scoped>
.home-container {
  padding: 46px 0 50px 0;
}

.van-nav-bar {
  background-color: #1989fa;
}

/deep/.van-nav-bar__title {
  color: #ffffff;
}
</style>

总结

本文是基于Vue3和Vant移动端组件库的一些常规组件的实际使用举例,只是对一个基础的功能的实践,更多实际应用组件功能请结合业务参考Vant

相关推荐
迷雾漫步者36 分钟前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-1 小时前
验证码机制
前端·后端
燃先生._.2 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖3 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235243 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240254 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar4 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人5 小时前
前端知识补充—CSS
前端·css
GISer_Jing5 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试