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

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试