在设计一个小程序的首页时,包含轮播图、通知栏和商品列表这三个元素是非常常见且有效的布局方式。这样的设计既能够吸引用户的注意力,又能够高效地展示信息和商品。
轮播组件
小程序首页幻灯片通常位于小程序的顶部或显著位置,通过滑动屏幕可以切换不同的幻灯片内容。这些幻灯片可以包含图片、文字、链接等元素,为用户提供丰富的视觉体验和信息传递。
组件模板里找到轮播组件,把组件拖动进设计器。
绑定轮播API
轮播组件显示数据来源于API,配置域名、API接口
轮播绑定数据源
点击数据绑定,找到对应API返回轮播数据列表。
轮播图片、标题绑定
由于轮播图片、标题不同用户API返回结构会不同。所以要进行数据源绑定。
通知栏
拖动通知栏组件进设计区,同样跟轮播增加通知API接口,绑定数据源、标题。
商品内容
首先我们要造好一个商品模板,包括了图片、标题、价格及划线价格,大家参照FLEX组件教程或者直接用组件模板里的模板快速复用。
商品API
商品API参照轮播的API进行新增,但有一个小细节,我们希望拖动页面时进行无限加载商品数据。API上面有个小细节,大家要进行开启。
绑定数据源
定位循环绑定产品FLEX组件进行数据源绑定。
首页核心展示我们这里就基本上完成了。
保存源码至本地
点击保存源码至本地,我们即可看见效果了。
生成源码
<template> <view class="container container329916"> <view class="flex flex-wrap diygw-col-24 justify-center items-center flex15-clz" @tap="navigateTo" data-type="page" data-url="/pages/goods"> <text class="flex icon diygw-col-0 diy-icon-search"></text> <text class="diygw-col-0"> 搜索 </text> </view> <view class="flex diygw-col-24 swiper-clz"> <swiper :current="swiperIndex" class="swiper" @change="changeSwiper" indicator-color="rgba(51, 51, 51, 0.39)" indicator-active-color="#fff" indicator-dots="true" autoplay interval="3000" circular="true" style="height: 276rpx"> <swiper-item v-for="(item, index) in swipers.rows" :key="index" class="diygw-swiper-item"> <view class="diygw-swiper-item-wrap"> <image :src="item.img" class="diygw-swiper-image"></image> <view class="diygw-swiper-item-title swiper-title"> {{ item.title }} </view> </view> </swiper-item> </swiper> </view> <view class="flex diygw-col-24 noticebar-clz"> <diy-noticebar class="flex1 diy-notice-bar" :remote="true" :list="notices.rows" color="#fb4833" bgColor="#ffe8e8" leftIcon="diy-icon-notification"> <block v-slot:content> <text class="diy-notice-item" v-for="(item, index) in notices.rows" :key="index"> {{ item.title }} </text> </block> </diy-noticebar> </view> <view v-if="goods.total > 0" class="flex diygw-col-24 items-stretch flex-wrap flex-clz"> <view v-for="(item, index) in goods.rows" :key="index" class="flex flex-wrap diygw-col-12 flex-direction-column items-stretch flex6-clz" @tap="navigateTo" data-type="page" data-url="/pages/goods/detail" :data-id="item.id"> <view class="flex flex-wrap diygw-col-0 flex-direction-column items-center"> <image :src="item.img" class="image-size diygw-image diygw-col-24" mode="aspectFit"></image> </view> <view class="flex flex-wrap diygw-col-0 flex-direction-column justify-between flex20-clz"> <text class="diygw-col-0 text11-clz"> {{ item.title }} </text> <text class="diygw-text-line2 diygw-col-0"> {{ item.remark }} </text> <view class="flex flex-wrap diygw-col-0 items-center"> <text class="diygw-col-0 text7-clz"> ¥{{ item.price }} </text> <text class="diygw-text-line2 diygw-col-0 text8-clz"> ¥{{ item.linePrice }} </text> </view> </view> </view> </view> <view v-if="globalData.isshow && goods.code == 200 && goods.total == 0" class="flex flex-wrap diygw-col-24 flex-direction-column items-center flex1-clz"> <image src="/static/zwjl.png" class="image1-size diygw-image diygw-col-0" mode="widthFix"></image> <text class="diygw-col-0 text-clz"> 未找到任何数据 </text> </view> <view class="flex flex-wrap diygw-col-24 items-end diygw-bottom flex2-clz"> <view class="flex flex-wrap diygw-col-6 flex-direction-column items-center flex8-clz"> <view class="flex flex-wrap diygw-col-0 flex-direction-column items-center"> <image src="/static/sy3on.png" class="image2-size diygw-image diygw-col-0" mode="widthFix"></image> </view> <text class="diygw-text-line1 diygw-col-0"> 首页 </text> </view> <view class="flex flex-wrap diygw-col-6 flex-direction-column items-center flex11-clz" @tap="navigateTo" data-type="page" data-url="/pages/goods" data-redirect="1"> <view class="flex flex-wrap diygw-col-0 flex-direction-column items-center"> <image src="/static/fl.png" class="image8-size diygw-image diygw-col-0" mode="widthFix"></image> </view> <text class="diygw-text-line1 diygw-col-0"> 分类 </text> </view> <view class="flex flex-wrap diygw-col-6 flex-direction-column items-center flex9-clz" @tap="navigateTo" data-type="page" data-url="/pages/cart" data-redirect="1"> <view class="flex flex-wrap diygw-col-0 flex-direction-column items-center"> <text v-if="userInfo.carts && userInfo.carts.length > 0" class="diygw-text-line1 diygw-col-0 animate__animated animate__heartBeat animate__infinite text2-clz"> </text> <image src="/static/gwc.png" class="image5-size diygw-image diygw-col-0" mode="widthFix"></image> </view> <text class="diygw-text-line1 diygw-col-0"> 购物车 </text> </view> <view class="flex flex-wrap diygw-col-6 flex-direction-column items-center flex4-clz" @tap="navigateTo" data-type="page" data-url="/pages/articles" data-redirect="1"> <view class="flex flex-wrap diygw-col-0 flex-direction-column items-center"> <image src="/static/cp1.png" class="image3-size diygw-image diygw-col-0" mode="widthFix"></image> </view> <text class="diygw-text-line1 diygw-col-0"> 文章 </text> </view> <view class="flex flex-wrap diygw-col-6 flex-direction-column items-center flex12-clz" @tap="navigateTo" data-type="page" data-url="/pages/user" data-redirect="1"> <view class="flex flex-wrap diygw-col-0 flex-direction-column items-center"> <image src="/static/wd.png" class="image4-size diygw-image diygw-col-0" mode="widthFix"></image> </view> <text class="diygw-text-line1 diygw-col-0"> 我的 </text> </view> </view> <view class="clearfix"></view> </view> </template> <script> export default { data() { return { //用户全局信息 userInfo: {}, //页面传参 globalOption: {}, //自定义全局变量 globalData: { isshow: false }, swipersNum: 1, swipers: { rows: [ { id: 0, title: '', remark: '', img: '', path: null, userId: 0, createTime: '', updateTime: '', deleteTime: null } ], total: 0, code: 0, msg: '' }, noticesNum: 1, notices: { rows: [ { id: 0, title: '', remark: '', userId: 0, createTime: '', updateTime: '', deleteTime: null } ], total: 0, code: 0, msg: '' }, goodsNum: 1, goods: { rows: [ { id: 0, title: '', remark: '', img: '', imgs: '', status: '', content: '', price: '', amount: 0, sellamonut: null, skus: '', sortnum: null, cateId: 0, userId: 0, createTime: '', updateTime: '', deleteTime: null, linePrice: '', skuType: '' } ], total: 0, code: 0, msg: '' }, swiperIndex: 0 }; }, onShow() { this.setCurrentPage(this); }, onLoad(option) { this.setCurrentPage(this); if (option) { this.setData({ globalOption: this.getOption(option) }); } this.init(); }, methods: { async init() { await this.swipersApi(); await this.noticesApi(); await this.goodsApi(); }, // 轮播数据 API请求方法 async swipersApi(param) { let thiz = this; param = param || {}; //请求地址及请求数据,可以在加载前执行上面增加自己的代码逻辑 let http_url = '/cms/api.swiper/list'; let http_data = { pageNum: this.swipersNum, pageSize: 10, pageSize: param.pageSize || '5' }; let http_header = {}; let swipers = await this.$http.post(http_url, http_data, http_header, 'json'); this.swipers = swipers; this.globalData.isshow = true; }, // 公告数据 API请求方法 async noticesApi(param) { let thiz = this; param = param || {}; //请求地址及请求数据,可以在加载前执行上面增加自己的代码逻辑 let http_url = '/cms/api.notice/list'; let http_data = { pageNum: this.noticesNum, pageSize: 10, pageSize: param.pageSize || '5' }; let http_header = {}; let notices = await this.$http.post(http_url, http_data, http_header, 'json'); this.notices = notices; }, // 商品数据 API请求方法 async goodsApi(param) { let thiz = this; param = param || {}; //如果请求要重置页面,请配置点击附加参数refresh=1 增加判断如输入框回调param不是对象 if (param.refresh || typeof param != 'object') { this.goodsNum = 1; } //请求地址及请求数据,可以在加载前执行上面增加自己的代码逻辑 let http_url = '/shop/api.goods/list'; let http_data = { pageNum: this.goodsNum, pageSize: 10 }; let http_header = {}; let goods = await this.$http.post(http_url, http_data, http_header, 'json'); let datarows = goods.rows; if (http_data.pageNum == 1) { this.goods = goods; } else if (datarows) { let rows = this.goods.rows.concat(datarows); goods.rows = rows; this.goods = goods; } if (datarows && datarows.length > 0) { this.goodsNum = this.goodsNum + 1; } this.globalData.isshow = true; }, changeSwiper(evt) { let swiperIndex = evt.detail.current; this.setData({ swiperIndex }); } }, onPullDownRefresh() { // 商品数据 API请求方法 this.goodsNum = 1; this.goodsApi(); uni.stopPullDownRefresh(); }, onReachBottom() { // 商品数据 API请求方法 this.goodsApi(); } }; </script> <style lang="scss" scoped> .flex15-clz { padding-top: 16rpx; border-bottom-left-radius: 120rpx; padding-left: 10rpx; padding-bottom: 16rpx; border-top-right-radius: 120rpx; margin-right: 20rpx; background-color: #ffffff; margin-left: 20rpx; box-shadow: 0rpx 0rpx 12rpx 2px rgba(219, 219, 219, 0.31); overflow: hidden; width: calc(100% - 20rpx - 20rpx) !important; border-top-left-radius: 120rpx; margin-top: 10rpx; border-bottom-right-radius: 120rpx; margin-bottom: 10rpx; padding-right: 10rpx; } .icon { font-size: 36rpx; } .swiper-clz { margin-left: 20rpx; border-bottom-left-radius: 12rpx; overflow: hidden; width: calc(100% - 20rpx - 20rpx) !important; border-top-left-radius: 12rpx; margin-top: 10rpx; border-top-right-radius: 12rpx; border-bottom-right-radius: 12rpx; margin-bottom: 10rpx; margin-right: 20rpx; } .swiper-title { background-color: rgba(0, 0, 0, 0.281); color: #e6e6e6; } .noticebar-clz { margin-left: 20rpx; border-bottom-left-radius: 12rpx; overflow: hidden; width: calc(100% - 20rpx - 20rpx) !important; border-top-left-radius: 12rpx; margin-top: 10rpx; border-top-right-radius: 12rpx; border-bottom-right-radius: 12rpx; margin-bottom: 10rpx; margin-right: 20rpx; } .flex-clz { padding-top: 10rpx; padding-left: 10rpx; padding-bottom: 10rpx; padding-right: 10rpx; } .flex6-clz { padding-top: 20rpx; border-bottom-left-radius: 12rpx; padding-left: 20rpx; padding-bottom: 20rpx; border-top-right-radius: 12rpx; margin-right: 10rpx; background-color: #ffffff; margin-left: 10rpx; box-shadow: 0rpx 0rpx 12rpx 2px rgba(219, 219, 219, 0.31); overflow: hidden; width: calc(50% - 10rpx - 10rpx) !important; border-top-left-radius: 12rpx; margin-top: 10rpx; border-bottom-right-radius: 12rpx; margin-bottom: 10rpx; padding-right: 20rpx; } .image-size { height: 200rpx !important; width: 100%; } .flex20-clz { padding-top: 10rpx; flex: 1; padding-left: 10rpx; padding-bottom: 10rpx; padding-right: 10rpx; } .text11-clz { font-weight: bold; font-size: 28rpx !important; } .text7-clz { color: #f20000; font-weight: bold; font-size: 28rpx !important; } .text8-clz { text-decoration: line-through; } .flex1-clz { padding-top: 20rpx; padding-left: 20rpx; padding-bottom: 20rpx; padding-right: 20rpx; } .image1-size { height: 400rpx !important; width: 400rpx !important; } .text-clz { color: #969696; font-size: 28rpx !important; } .flex2-clz { border-top: 2rpx solid #e4e4e4; padding-top: 16rpx; border-bottom-left-radius: 0rpx; bottom: 0rpx; padding-left: 16rpx; padding-bottom: 16rpx; border-top-right-radius: 24rpx; background-color: #ffffff; box-shadow: 0rpx 4rpx 12rpx rgba(31, 31, 31, 0.16); overflow: visible; left: 0rpx; border-top-left-radius: 24rpx; border-bottom-right-radius: 0rpx; padding-right: 16rpx; } .flex8-clz { color: #fa240b; flex: 1; } .image2-size { height: 48rpx !important; width: 48rpx !important; } .flex11-clz { flex: 1; } .image8-size { height: 48rpx !important; width: 48rpx !important; } .flex9-clz { flex: 1; } .text2-clz { border: 2rpx solid #eee; border-bottom-left-radius: 40rpx; -webkit-animation-duration: 5000ms; color: #ffffff; animation-delay: 1000ms; -webkit-animation-delay: 1000ms; border-top-right-radius: 40rpx; right: -8rpx; background-color: rgba(255, 17, 17, 0.91); animation-duration: 5000ms; flex-shrink: 0; overflow: hidden; top: -8rpx; width: 16rpx !important; border-top-left-radius: 40rpx; border-bottom-right-radius: 40rpx; position: absolute; height: 16rpx !important; } .image5-size { height: 48rpx !important; width: 48rpx !important; } .flex4-clz { flex: 1; } .image3-size { height: 48rpx !important; width: 48rpx !important; } .flex12-clz { flex: 1; } .image4-size { height: 48rpx !important; width: 48rpx !important; } .container329916 { padding-bottom: 160rpx; background-color: #f5f5f5; } </style>
扩展阅读
1. 轮播图
位置:首页顶部,作为用户进入小程序后第一眼看到的内容。
功能:用于展示最新的促销信息、热门活动或推荐商品。
设计建议:
数量:建议3~5张图片,过多可能导致用户等待时间过长。
尺寸:确保每张图片的尺寸一致,以适应统一的展示框架。
交互:支持左右滑动切换图片,并在图片下方或一侧显示小圆点或数字指示当前图片的位置。
链接:每张图片应链接到相关的活动页面或商品详情页。
2. 通知栏
位置:轮播图下方,紧挨着轮播图。
功能:用于展示最新的通知、公告或促销信息。
设计建议:
样式:可以是文本、图标+文本或卡片式布局。
更新频率:根据内容的重要程度和时效性进行调整,避免过于频繁地打扰用户。
交互:用户点击通知栏时,应跳转到相关的活动页面或详情页。
清除:对于已读或已过时的通知,提供清除或隐藏的功能。
3. 商品列表
位置:通知栏下方,占据首页的大部分区域。
功能:展示推荐的商品、热门商品或分类商品。
设计建议:
布局:可以采用网格布局(如2列、3列)或列表布局,根据商品的种类和数量进行选择。
图片:每个商品应包含高质量的图片,以吸引用户的注意力。
信息:展示商品名称、价格、销量、评价等关键信息。
排序:提供排序功能,如按价格、销量、评价等排序。
交互:用户点击商品时,应跳转到该商品的详情页。
加载:支持分页加载或下拉刷新,以提高用户体验。