uniapp实战 —— 猜你喜欢(含滚动触底分页加载)

效果预览

在这里插入图片描述

组件封装

src\components\SUI_Guess.vue

<script setup lang="ts">
import {
      
       ref, onMounted } from 'vue'
import type {
      
       GuessItem } from '@/types/index'
import {
      
       getGuessListAPI } from '@/apis/index'
import type {
      
       PageParams } from '@/types/global'

// 分页参数 -- Required指定分页参数必传
const pageParams: Required<PageParams> = {
      
      
  page: 1,
  pageSize: 10,
}

// 已结束标记
const finish = ref(false)

// 猜你喜欢的数据列表
const GuessList = ref<GuessItem[]>([])

// 获取猜你喜欢的数据列表
const getGuessList = async () => {
      
      
  // 已标记为无更多数据时,不再查询
  if (finish.value === true) {
      
      
    return uni.showToast({
      
       icon: 'none', title: '没有更多数据~' })
  }
  // 查询分页数据
  let res = await getGuessListAPI(pageParams)
  // 新数据不断累加--数组追加
  GuessList.value.push(...res.result.items)
  // 未到最后一页时,页码不断累加
  if (pageParams.page < res.result.pages) {
      
      
    // 页码累加
    pageParams.page++
  } else {
      
      
    // 到达最后一页时,标记为无更多数据
    finish.value = true
  }
}

// 生命周期-组件挂载成功时执行
onMounted(() => {
      
      
  getGuessList()
})

// 对外暴露方法 -- 供父组件调用
defineExpose({
      
      
  getGuessList: getGuessList,
})
</script>

<template>
  <!-- 猜你喜欢 -->
  <view class="caption">
    <text class="text">猜你喜欢</text>
  </view>
  <view class="guess">
    <navigator
      class="guess-item"
      v-for="(item, index) in GuessList"
      :key="'guess' + index"
      :url="item.url"
    >
      <image class="image" mode="aspectFill" :src="item.picture"></image>
      <view class="name"> {
   
   { item.name }} </view>
      <view class="price">
        <text class="small">¥</text>
        <text>{
   
   { item.price }}</text>
      </view>
    </navigator>
  </view>
  <view class="loading-text">
    {
   
   { finish ? '没有更多数据~' : '正在加载...' }}
  </view>
</template>

<style lang="scss">
:host {
      
      
  display: block;
}
/* 分类标题 */
.caption {
      
      
  display: flex;
  justify-content: center;
  line-height: 1;
  padding: 36rpx 0 40rpx;
  font-size: 32rpx;
  color: #262626;
  .text {
      
      
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 0 28rpx 0 30rpx;

    &::before,
    &::after {
      
      
      content: '';
      width: 20rpx;
      height: 20rpx;
      background-image: url(@/static/images/bubble.png);
      background-size: contain;
      margin: 0 10rpx;
    }
  }
}

/* 猜你喜欢 */
.guess {
      
      
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  padding: 0 20rpx;
  .guess-item {
      
      
    width: 345rpx;
    padding: 24rpx 20rpx 20rpx;
    margin-bottom: 20rpx;
    border-radius: 10rpx;
    overflow: hidden;
    background-color: #fff;
  }
  .image {
      
      
    width: 304rpx;
    height: 304rpx;
  }
  .name {
      
      
    height: 75rpx;
    margin: 10rpx 0;
    font-size: 26rpx;
    color: #262626;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  .price {
      
      
    line-height: 1;
    padding-top: 4rpx;
    color: #cf4444;
    font-size: 26rpx;
  }
  .small {
      
      
    font-size: 80%;
  }
}
// 加载提示文字
.loading-text {
      
      
  text-align: center;
  font-size: 28rpx;
  color: #666;
  padding: 20rpx 0;
}
</style>

注册为全局组件

src\pages.json
在这里插入图片描述

必要的 TS 类型声明

组件和组件实例类型声明

src\types\component.d.ts

import 'vue'

import SUI_Swiper from '@/components/SUI_Swiper.vue'
import SUI_Guess from '@/components/SUI_Guess.vue'
// 组件类型
declare module 'vue' {
    
    
  export interface GlobalComponents {
    
    
    SUI_Guess: typeof SUI_Guess
  }
}

// 组件实例类型
export type SUI_GuessInstance = InstanceType<typeof SUI_Guess>

接口参数和返回值类型声明

src\types\global.d.ts

/** 通用分页参数类型 */
export type PageParams = {
    
    
  /** 页码:默认值为 1 */
  page?: number
  /** 页大小:默认值为 10 */
  pageSize?: number
}

/** 通用分页结果类型 */
export type PageResult<T> = {
    
    
  /** 列表数据 */
  items: T[]
  /** 总条数 */
  counts: number
  /** 当前页数 */
  page: number
  /** 总页数 */
  pages: number
  /** 每页条数 */
  pageSize: number
}

业务数据类型声明

src\types\index.d.ts

/** 猜你喜欢 */
export type GuessItem = {
    
    
  /** 商品描述 */
  desc: string
  /** 商品折扣 */
  discount: number
  /** id */
  id: string
  /** 商品名称 */
  name: string
  /** 商品已下单数量 */
  orderNum: number
  /** 商品图片 */
  picture: string
  /** 商品价格 */
  price: number
  // 导航地址
  url: string
}

接口封装

src\apis\index.ts

import {
    
     http } from '@/utils/http'
import type {
    
     GuessItem } from '@/types/index'
import type {
    
     PageParams, PageResult } from '@/types/global'

/**
 * 公共组件-猜你喜欢
 */
export const getGuessListAPI = (data?: PageParams) => {
    
    
  return http<PageResult<GuessItem>>({
    
    
    method: 'GET',
    url: '/home/goods/guessLike',
    data,
  })
}

页面使用

src\pages\index\index.vue

  <!-- 中间--自适配高度的滚动区 -->
  <scroll-view class="contentBox" scroll-y @scrolltolower="onScrolltolower">
    <SUI_Guess ref="guessRef" />
  </scroll-view>
<style lang="scss">
page {
      
      
  background-color: #f7f7f7;
  // 总容器高度撑满屏幕
  height: 100%;
  // 使容器内元素使用flex布局
  display: flex;
  flex-direction: column;
}
.contentBox {
      
      
  // 滚动区自适配高度
  flex: 1;
}
</style>
import type {
    
     SUI_GuessInstance } from '@/types/component'

// 获取猜你喜欢组件实例
const guessRef = ref<SUI_GuessInstance>()

// 滚动触底事件
const onScrolltolower = () => {
    
    
  guessRef.value?.getGuessList()
}

猜你喜欢

转载自blog.csdn.net/weixin_41192489/article/details/134861005