微信小程序实现优惠券页面布局
在电商类小程序中,优惠券模块是提升用户复购率和客单价的重要功能。本文将详细介绍一个优惠券列表页面的实现过程,包括数据处理、页面布局、样式设计和交互逻辑,帮助开发者快速掌握类似功能的开发技巧。
示例图片

功能概述
本次实现的优惠券列表页面具有以下特点:

  • 支持按 “未使用”、“已过期”、“已使用” 三种状态筛选优惠券
  • 顶部导航栏固定,支持状态切换交互
  • 优惠券卡片采用左右分栏设计,直观展示优惠金额和使用条件
  • 列表支持纵向滚动,适配不同屏幕尺寸
  • 空状态处理,当筛选结果为空时显示提示信息

核心方法实现
1、导航切换事件:处理导航项点击,切换当前选中状态并重新筛选数据

navClick(e) {
  this.setData({
    current: e.currentTarget.dataset.tag
  },()=>{
    this.getDataInfo();  // 数据更新后重新筛选
  })
}

2、数据筛选方法:根据当前选中的状态筛选优惠券

getDataInfo() {
  let t = this.data.current;
  // 筛选出状态匹配的优惠券
  let list = attrList.filter(item => item.current === t);
  this.setData({
    dataList: list
  })
}

具体可根据接口返回数据进行筛选。
3、高度计算方法:动态计算滚动区域高度,适配不同设备

getAreaHeight() {
  let self = this;
  const query = wx.createSelectorQuery();
  query.select('#navArea')
    .boundingClientRect((rect) => {
      // 计算顶部高度和滚动区域高度
      let top = rect.height + 12;
      let range = wx.getWindowInfo().screenHeight;
      self.setData({
        topHeight: top,
        viewHeight: range - top - 76
      });
    }).exec();
}

功能优化与扩展建议

1、性能优化:

  • 对于大量优惠券数据,可实现分页加载

  • 使用wx:key优化列表渲染性能

  • 图片资源使用合适尺寸,避免过大图片影响加载速度
    2、功能扩展:

  • 添加优惠券搜索功能,支持按类型、金额筛选

  • 实现优惠券分享功能

  • 添加优惠券过期提醒功能

  • 支持优惠券使用说明弹窗
    3、用户体验优化:

  • 添加加载状态提示

  • 优惠券过期状态使用灰色样式区分

  • 实现优惠券滑动删除功能(已过期 / 已使用)

  • 添加空状态图片提示,增强视觉效果

以下贴出完整代码,仅供参考:

1、js代码

const attrList = [
  {
    "money": 150,
    "fullMoney": 500,
    "text": "生鲜满减券",
    "kind": "食品类",
    "date": "2025.06.28-2025.07.12",
    "current": 1
  },
  {
    "money": 250,
    "fullMoney": 600,
    "text": "节日特惠券",
    "kind": "其他类",
    "date": "2025.06.29-2025.07.15",
    "current": 0
  },
  {
    "money": 300,
    "fullMoney": 750,
    "text": "教育专区券",
    "kind": "教育类",
    "date": "2025.06.27-2025.07.10",
    "current": 2
  },
  {
    "money": 280,
    "fullMoney": 400,
    "text": "食品折扣券",
    "kind": "食品类",
    "date": "2025.06.30-2025.07.14",
    "current": 1
  },
  {
    "money": 200,
    "fullMoney": 200,
    "text": "教育满减券",
    "kind": "教育类",
    "date": "2025.06.25-2025.07.08",
    "current": 0
  },
  {
    "money": 50,
    "fullMoney": 200,
    "text": "生活优惠券",
    "kind": "生活类",
    "date": "2025.06.28-2025.07.13",
    "current": 2
  },
  {
    "money": 100,
    "fullMoney": 500,
    "text": "食品通用券",
    "kind": "食品类",
    "date": "2025.06.26-2025.07.09",
    "current": 1
  },
  {
    "money": 50,
    "fullMoney": 100,
    "text": "生活满减券",
    "kind": "生活类",
    "date": "2025.06.29-2025.07.15",
    "current": 0
  },
  {
    "money": 75,
    "fullMoney": 300,
    "text": "数码优惠券",
    "kind": "数码类",
    "date": "2025.07.01-2025.07.20",
    "current": 1
  },
  {
    "money": 120,
    "fullMoney": 800,
    "text": "家电满减券",
    "kind": "家电类",
    "date": "2025.07.02-2025.07.22",
    "current": 0
  },
  {
    "money": 35,
    "fullMoney": 150,
    "text": "美妆优惠券",
    "kind": "美妆类",
    "date": "2025.07.03-2025.07.25",
    "current": 2
  }
]
    
Page({

  /**
   * 页面的初始数据
   */
  data: {
    current: 0,
    topHeight: 44,
    viewHeight: 640,
    navList: [{
        'id': 0,
        'title': '未使用',
        'total': 3
      },
      {
        'id': 1,
        'title': '已过期',
        'total': 3
      },
      {
        'id': 2,
        'title': '已使用',
        'total': 3
      },
    ],
    dataList: []
  },

  navClick(e) {
    this.setData({
      current: e.currentTarget.dataset.tag
    },()=>{
      this.getDataInfo();
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onLoad: function () {
    this.getDataInfo();
  },

  getDataInfo() {
    let t = this.data.current;
    let list = attrList.filter(item => item.current === t);
    this.setData({
      dataList: list
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    this.getAreaHeight();
  },

  getAreaHeight() {
    let self = this;
    const query = wx.createSelectorQuery();
    query.select('#navArea')
      .boundingClientRect((rect) => {
        let top = rect.height + 12;
        let range = wx.getWindowInfo().screenHeight;
        self.setData({
          topHeight: top,
          viewHeight: range - top-76
        });
      }).exec();
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})

2、wxml代码

<view class="level nav-box" id="navArea">
  <block wx:for="{{navList}}" wx:for-item="item" wx:for-index="index" wx:key="item">
    <view class="nav {{current==index?'active':''}}" bind:tap="navClick" data-tag="{{index}}">
      <view>{{item.title}}</view>
      <view class="line {{current==index?'red':'trans'}}" wx:if="{{current==index}}"></view>
    </view>
  </block>
</view>
<view class="box" style="padding-top: {{topHeight}}px;">
  <scroll-view scroll-y="{{true}}" style="height: {{viewHeight}}px;" wx:if="{{dataList.length>0}}">
    <block wx:for="{{dataList}}" wx:for-index="index" wx:for-item="item" wx:key="item">
      <view class="level row">
        <view class="row-left">
          <view class="middle left-t">
            <text>¥</text>
            <text>{{item.money}}</text>
          </view>
          <view class="middle left-b">满{{item.fullMoney}}可用</view>
        </view>
        <view class="dot top-dot"></view>
        <view class="dot bot-dot"></view>
        <view class="row-right">
          <view class="right-t">
            <text>{{item.text}}</text>
            <text>{{item.kind}}</text>
            <text>立即使用</text>
          </view>
          <view class="right-b">{{item.date}}</view>
        </view>
      </view>
    </block>
  </scroll-view>
  <view class="not-box" wx:else>暂无数据显示!</view>
</view>

3、wxss代码

page {
  font-size: 32rpx;
  background-color: #f1f1f1;
}

.level {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.nav-box {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9;
  justify-content: space-around;
  background-color: white;
}

.nav {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20rpx 0;
  color: #7c7a7a;
}

.active {
  color: #FF3333;
}

.line {
  width: 70rpx;
  height: 5rpx;
  margin-top: 10rpx;
  border-radius: 5rpx;
}

.trans {
  background-color: transparent;
}

.red {
  background-color: #FF3333;
}

.box {
  margin-bottom: 10rpx;
  margin-left: 10rpx;
  margin-right: 10rpx;
}

.row {
  background-color: white;
  border-radius: 20rpx;
  position: relative;
  margin-bottom: 30rpx;
}

.row-left {
  width: 30%;
  text-align: center;
}

.middle {
  display: flex;
  align-items: center;
  justify-content: center;
}

.left-t {
  font-size: 44rpx;
  color: white;
  padding: 16% 0;
  background-color: #F36827;
  border-top-left-radius: 20rpx;
}

.left-t text:first-child {
  font-size: 28rpx;
  margin-top: 15rpx;
  padding-right: 5rpx;
}

.left-b {
  background-color: #FFCDAA;
  font-size: 28rpx;
  padding: 5% 0;
  color: #e44222;
  border-bottom-left-radius: 20rpx;
}

.row-right {
  width: 70%;
  padding-left: 5%;
}

.right-t {
  display: flex;
  flex-direction: column;
  position: relative;
}

.right-t text:nth-child(1) {
  font-size: 34rpx;
  font-weight: bold;
}

.right-t text:nth-child(2) {
  font-size: 28rpx;
  color: #7c7a7a;
  padding-top: 5rpx;
}

.right-t text:nth-child(3) {
  position: absolute;
  right: 20rpx;
  font-size: 28rpx;
  bottom: 0;
  background-color: #01BA79;
  color: white;
  border-radius: 5rpx;
  padding: 5rpx 10rpx;
}

.right-b {
  font-size: 28rpx;
  color: #7c7a7a;
  padding-top: 20rpx;
  padding-bottom: 10rpx;
}

.dot {
  width: 28rpx;
  height: 28rpx;
  background-color: #F1F1F1;
  position: absolute;
  border-radius: 28rpx;
  left: 27%;
}

.top-dot {
  top: -12rpx;
}

.bot-dot {
  bottom: -12rpx;
}

.not-box {
  text-align: center;
  padding-top: 45%;
  font-size: 30rpx;
  color: #7c7a7a;
}

4、json代码

{
  "usingComponents": {},
  "navigationBarBackgroundColor": "#FF3333",
  "navigationBarTitleText": "优惠券模板"
}

总结

本文详细介绍了微信小程序优惠券列表页面的实现过程,通过动态计算高度实现了不同设备的适配,使用条件渲染实现了不同状态的展示切换,这些技巧在其他列表类页面开发中也同样适用。

更多示例,请关注 蒜鸟编程(微信小程序 / 抖音 / 小红书/微信公众号/微博****等同名称),在这里,编程与生活的边界从未如此清晰,期待与大家共同成长!后续将围绕编程技术持续更新更多实践示例,如果在实现过程中遇到问题,或者有更好的优化建议,欢迎在评论区交流讨论!

更多推荐