一、常用组件
在之前的封装请求数据的模块中请求轮播图的数据
1.首页轮播图数据的请求以及渲染
1.轮播图数据的请求pages/index/index.js
data: {
bannerlist:[] //存放轮播图数据的列表
},
onLoad: function () {
//请求首页轮播图的数据
request({
url : '/banner' //注意接口不要写错
}).then(res => {
console.log(res)
// 在Vue中,this.bannerist = res.data.data
// 在React中,this.setState(bannerlist: res.data.data)
// 在小程序中修改状态的方式就是this.setData
this.setData({ //将获取到的数据保存到本地变量中
bannerlist: res.data.data
})
})
}
同理之前通过/pro
接口获取到的商品列表的数据也可以通过this.setData
来保存本地:
data: {
bannerlist:[], //存放轮播图数据的列表
prolist:[] //存放商品数据的列表
},
...
this.setData({
prolist: res.data.data
})
为了代码更加直白美观,可以将获取商品列表数据和请求轮播图数据另外封装在自定义方法中,然后在onLoad
中调用就可以了:
onLoad: function () {
// 请求轮播图数据
this.getBannerlistData()
// 请求商品列表数据
this.getProlistData()
},
...
//请求轮播图数据
getBannerlistData () {
request({
url : '/banner'
}).then(res => {
console.log(res)
// 在Vue中,this.bannerist = res.data.data
// 在React中,this.setState(bannerlist: res.data.data)
// 在小程序中修改状态的方式就是this.setData
this.setData({ //将获取到的数据保存到本地变量中
bannerlist: res.data.data
})
}) //可以省略catch方法,。没有关系
},
//请求商品列表数据
getProlistData () {
request({
url : '/pro',
data : {}
}).then((res) => { //then是请求成功后的处理方法
console.log(res)
this.setData({
prolist: res.data.data
})
}).catch((err) => { //catch是请求失败后的处理方法
console.log(err)
})
}
3.使用组件 - 视图容器 - swiper
滑块视图容器。其中只可放置swiper-item
组件,否则会导致未定义的行为。 一些属性见官方文档:小程序官方文档–swiper
<swiper
indicator-dots="{{true}}" autoplay="{{true}}" circular="{{true}}"
duration="{{500}}">
<!-- wx:key=""不知道写啥的话可以写*this,指的就是自己 -->
<block wx:for="{{bannerlist}}" wx:key="index">
<swiper-item >
<image src="{{item.img}}"></image>
</swiper-item>
</block>
</swiper>
<prolist></prolist>
注意:上面的
item.img
是根据获取到的数据结构来判断的,不能直接写item
,因为item
指的是每一行的数据,我们要的仅仅是图片数据,所以只需要选取其路径item.img
就可以了。
如果碰到图片显示不全或者没有铺满屏幕的情况,在
wxss
中设置一下即可,例如铺满屏幕:image { width: 100%; }
更多设置图片格式的方法:关于图片的其它一些属性
轮播图的使用就到此为止。
二、自定义组件 - 产品列表
1.自定义组件的布局
components/prolist/prolist.wxml
列表组件prolist
的布局:
<view class="prolist">
<view class="proitem">
<view class="itemimg">
<image class="img" src=""></image>
</view>
<view class="iteminfo">
<view class="title">
产品名称
</view>
<view class="price">
¥199
</view>
</view>
</view>
</view>
2.自定义组件的样式
components/prolist/prolist.wxss
列表组件prolist
的样式:
.prolist .proitem{
width: 100%;
display: flex;
height: 100px;
box-sizing: border-box;
border-bottom: 1px solid #ccc;
}
.prolist .proitem .itemimg{
width: 100px;
height: 100px;
padding: 5px;
}
.prolist .proitem .itemimg .img{
width: 90px;
height: 90px;
box-sizing: border-box;
border: 1px solid #ccc;
}
.prolist .proitem .iteminfo {
padding: 3px;
}
.prolist .proitem .iteminfo .title{
font-size: 18px;
font-weight: bold;
}
.prolist .proitem .iteminfo .price{
font-size: 12px;
}
3.首页请求数据,并且传递给子组件
pages/index/index.js
:
首页请求数据就是之前自定义的两个方法getBannerlistData ()
和 getProlistData ()
pages/index/index.wxml
:
<prolist prolist="{{prolist}}"></prolist>
vue
父组件给子组件传值:
父组件调用子组件的地方,添加一个自定义的属性,属性的值就是父组件要传递给子组件的值
如果属性的值是
变量
,boolean
,numder
,就需要绑定属性子组件定义的地方,添加一个
props
选项,props
的值是一个数组或者对象
如果是数组,数组的元素就是添加的属性名,可以在组件中通过此属性名访问数据
如果是对象,有两种形式:
2.1.
key
值为自定义的属性名,value
值为数据类型2.2.
key
值为自定义的属性名,value
值为一个对象,该对象有两个选项,一个为type
(数据类型),另一个为default
(默认值),如果默认值是对象或者数组,需要把default
写成一个函数,返回对象或数组
在小程序中:
父组件调用子组件的地方,添加一个自定义的属性,属性的值就是父组件要传递给子组件的值
如果属性的值是
变量
,boolean
,numder
,就需要用{{}}
包裹<prolist prolist="{{ prolist }}"/>
子组件定义的地方,添加一个
properties
选项,properties
的值是一个数组或者对象key为自定义的属性名,value值为数据类型:
properties: { prolist:Array }
可以在组件中通过此属性名访问数据
4.子组件接收数据
components/prolist/prolist.js
:
Component({
/**
* 组件的属性列表
*/
properties: {
prolist: Array
},
})
5.子组件渲染数据
components/prolist/prolist.wxml
:
<view class="prolist">
<view class="proitem" wx:for="{{prolist}}" wx:key="item.proid">
<view class="itemimg">
<image class="img" src="{{item.proimg}}"></image>
</view>
<view class="iteminfo">
<view class="title">
{{item.proname}}
</view>
<view class="price">
¥{{item.price}}
</view>
</view>
</view>
</view>
三、实现下拉刷新上拉加载
1.开启首页的下拉刷新功能
pages/index/index.json
:
{
"usingComponents": {
"prolist": "/components/prolist/prolist"
},
"enablePullDownRefresh": true, //实现下拉刷新
"backgroundColor": "#efefef",
"backgroundTextStyle": "dark"
}
2.完善相关的下拉刷新函数
pages/index/index.js
:
//页面相关事件处理函数---监听用户下拉刷新事件(重新请求了第一页的页面数据)
onPullDownRefresh: function() {
console.log("刷新了当前页面")
this.getRefreshData() //下拉刷新之后重新请求第一页的数据
},
//上拉触底事件函数
/**
* 上拉加载---分页效果,例如开始是第一页10条数据,下拉到底之后再向数据库中请求后10条数据显示出来,这个过程需要页码
*/
onReachBottom: function() {
console.log("对不起已经到底了")
this.requestMoreData()
},
...
// 下拉刷新后重新请求第一页的数据
getRefreshData () {
request({
url : '/pro',
data : {
pageCode: 0, // 页码默认从0开始
limitNum: 10 //每一页默认10条数据
}
}).then((res) => { //then是请求成功后的处理方法
console.log(res)
this.setData({
prolist: res.data.data,
pageCode: 1 //下拉刷新之后切记 要将页码重新置为0
})
// 真机测试的时候,在下拉刷新结束后需要 停止 下拉刷新的操作
wx.stopPullDownRefresh();
}).catch((err) => { //catch是请求失败后的处理方法
console.log(err)
})
},
// 上拉触底后再次请求更多的数据显示(翻页)
requestMoreData () {
request({
url : '/pro',
data : {
pageCode: this.data.pageCode, // 页码默认从0开始
limitNum: 10 //每一页默认10条数据
}
}).then((res) => { //then是请求成功后的处理方法
console.log(res)
// 请求之后需要判断
// 1.判断还有没有数据
if (res.data.code === '10000') {
// 没有更多数据了,要给用户提示信息
toast({title: '没有更多数据了'}) // 这里toast的参数必须是对象类型
} else {
// 2.如果有数据---请求到的数据追加到之前的数据上
// vue 中, thisprolist = [...this.prolist,res.data.data]
// 小程序中 修改数据的方式类似于 React
// React 获取数据 处理数据 修改数据(状态)
// 3.每一次请求完成页码要+1
let arr = this.data.prolist //获取数据
let num = this.data.pageCode //获取页码
let list = [...arr,...res.data.data] //处理数据
num += 1
this.setData({ //修改数据
prolist: list,
pageCode: num
})
}
})
}
四、返回顶部功能实现
<!-- 返回顶部按钮 -->
<!-- 绑定事件 -->
<!-- 小程序中有两种绑定事件的方法---移动端尽量不使用click事件,建议使用tap事件,或者用touch代替click事件
bindtap:
catchtap:组织冒泡
-->
<button class="backtop" bindtap="backtop">返回顶部</button>
CSS
样式文件:
.backtop {
position: fixed;
bottom: 20px;
right: 10px;
border-radius: 5px;
background-color: #f66;
}
pages/index/index.js
:
backtop: function () {
// 小程序api 的界面 - 滚动
wx.pageScrollTo({
scrollTop: 0,
duration: 300
})
}
五、实现点击商品列表进入产品的详情页面
1.构建详情页面
"pages": [
"pages/detail/detail"
],
2.声明式导航跳转
<!-- 首页商品列表点击进入详情页面vue和React 1.声明式导航 vue <router-Link></router-Link> React <Link></Link> <NavLink></NavLink> 2.编程式导航 new Vue ({router ,store ,el:' ' }) vue this.$router.push() replace() go() back() React this.props.history.push() --> <!-- 小程序中的点击进入详情页面 1.声明式导航---标签跳转---<a></a> https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html 格式为:<navigator url=" " open-type=" " ></navigator> open-type: navigate:保留当前页面,新添加一个页面,不能添加tab页面--push redirect:替换当前页面,不能替换tab页面--replace switchTab:切换当前的tab页面--小程序特有 navigateBack:返回--back,goBack 2.编程式导航---JS跳转---window.location.href="" https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab.html -->
小程序 组件-导航-navigator
<!-- 声明式导航 -->
<view class="prolist">
<!-- 因为每一个商品列表都有跳转功能,循环遍历时要用在navigator上面 -->
<navigator url="/pages/detail/detail" wx:for="{{prolist}}" wx:key="item.proid">
<view class="proitem">
<view class="itemimg">
<image class="img" src="{{item.proimg}}"></image>
</view>
<view class="iteminfo">
<view class="title">{{item.proname}}</view>
<view class="number">目前已售出{{item.sales}}件 / 剩余{{item.stock}}件</view>
<view class="price">¥{{item.price}}</view>
</view>
</view>
</navigator>
</view>
3.详情页面接收数据并且渲染数据
在小程序中向目标页面传递参数使用的是:/../..?+参数
,例如:
url="{{'/pages/detail/detail?proid='+item.proid}}"
在目标页面的onLoad
函数中的参数options
就是传递过来的参数。pages/detail/detail.js
:
import { request } from './../../utils/index.js'
Page({
...
data: {
proid: '', // 在商品加入购物车时必须要用到的proid
proname: '',
proimg: '',
desc: '',
price: 0
},
onLoad: function (options) {
console.log(options)
// 获取传递过来的参数值proid
const { proid } = options
// 请求产品详情的数据
request({
url:'/pro/detail?proid=' + proid
// url:'/pro/detail?proid=${proid}'
}).then(res => {
console.log(res.data)
// 解构赋值
const { proid, proname, price, proimg, desc} = res.data.data
// const { data:{proid, proname, price, proimg, desc}} = res.data
// 修改状态
this.setData({
proid, proname, price, proimg, desc
})
})
},
...
})
pages/detail/detail.wxml
:
<image src="{{proimg}}" style="width: 100px;height: 100px;"></image>
<view>{{proname}}</view>
<view>¥{{price}}</view>
<view>{{desc}}</view>
4.编程式导航渲染
使用小程序提供的api实现编程式路由的跳转:
wx.switchTab(Object object)
跳转到tabBar
页面,并关闭其他所有非tabBar
页面。
wx.reLaunch(Object object)
关闭所有页面,打开到应用内的某个页面。
wx.redirectTo(Object object)
关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到tabbar
页面。
wx.navigateTo(Object object)
保留当前页面(会保存在页面栈中),跳转到应用内的某个页面。但是不能跳到tabbar
页面。使用wx.navigateBack
可以返回到原页面。小程序中页面栈最多十层。
wx.navigateBack(Object object)
关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages
获取当前的页面栈,决定需要返回几层。
小程序传递数据使用
data-params
形式,可以在事件中根据event
获取该参数,用bindtap
来绑定单击事件
<view class="prolist">
<view class="proitem" bindtap="toDetail" data-proid="{{item.proid}}" wx:for="{{prolist}}" wx:key="item.proid">
<view class="itemimg">
<image class="img" src="{{item.proimg}}"></image>
</view>
<view class="iteminfo">
<view class="title">{{item.proname}}</view>
<view class="number">目前已售出{{item.sales}}件 / 剩余{{item.stock}}件</view>
<view class="price">¥{{item.price}}</view>
</view>
</view>
</view>
components/prolist/prolist.js
:
Component({
...
methods: {
toDetail (event) {
console.log('跳转到详情页面',event)
// 获取到产品id
const { proid } = event.currentTarget.dataset
// 编程式导航
// 如果跳转的是tab页面,可以使用switchTab 或者 reLuanch
// 如果跳转的是非tab页面,可以使用 redirectTo 或者 navigateTo 或者 reLuanch
//1.navigateTo
wx.navigateTo({
url: '/pages/detail/detail?proid=' + proid
// url: '/pages/detail/detail?proid=${proid}' 这种写法无法解析
})
//2.redirectTo 页面的左上角没有了返回按钮
// wx.redirectTo({
// url: '/pages/detail/detail?proid=' + proid
// })
//3.reLuanch
// wx.reLaunch({
// url: '/pages/detail/detail?proid=' + proid
// })
}
}
})
关于
getCurrentPages
的用法:在
detail.js
中onShow: function () { console.log(getCurrentPages()) // console.log(getCurrentPages()[getCurrentPages().length-1]) 输出当前页面(即当前自己页面) // console.log(getCurrentPages()[getCurrentPages().length-2]) 输出首页(即上一个页面) // console.log(getCurrentPages()[getCurrentPages().length-3]) undefined,因为数组中只有两个元素 },
length-1
对应的就是当前页面,length-2
就是(页面栈)上一个页面,以此类推。
如果详情页面的数据量处理特别多,可以将获取数据抽离出来,封装成方法:
request({
url:'/pro/detail?proid=' + proid
// url:'/pro/detail?proid=${proid}' 这种写法无法解析
}).then(res => {this.getDetailData(res,proid)})
...
// 将then之后获取数据成功后的方法进行封装
getDetailData (res,proid) {
console.log(res.data)
// 解构赋值
// 此处proid不需要从接口中获取自己内部已经有了
const { proname, price, proimg, desc} = res.data.data
// const { data:{proid, proname, price, proimg, desc}} = res.data
// 修改状态
this.setData({
proid, proname, price, proimg, desc
})
},
六.使用第三方组件库
1.WeUI
WeUI 是微信官方出品的组件库,它沿用了微信的视觉设计与交互设计,提供了各类原生组件的基础样式,风格简约大方。选用这一套组件库,可以让你的小程序与微信本身保持一致的界面风格。
2.iViewUI
iViewUI 是由TalkingData发布的组件库。iViewUI开发文档
3.Vant Weapp
Vant Weapp官方地址
Vant 是由有赞发布的,轻量的小程序 UI 组件库。如果你想制作一款电商、餐饮、外卖平台、票务预订等购物类小程序,选用 Vant 是较为合适的。Vant Weapp里边的组件是基于小程序自定义组件开发的。
Vant Weapp快速上手步骤
1.安装
,如果后面出现无法构建的情况,安装之前可以使用一下:
npm init
npm i @vant/weapp -S --production
2.构建npm包
打开微信开发者工具,点击 工具 -> 构建 npm,并勾选 使用 npm 模块 选项,构建完成后,即可引入组件。
3.使用组件
在使用之前将app.json
中的 "style": "v2"
去除,小程序的新版基础组件强行加上了许多样式,难以去除,不关闭将造成部分组件样式混乱。
首先在全局配置文件app.json
或者页面配置文件index.json
中引入:
"usingComponents": {
"van-goods-action": "@vant/weapp/goods-action/index",
"van-goods-action-icon": "@vant/weapp/goods-action-icon/index",
"van-goods-action-button": "@vant/weapp/goods-action-button/index"
}
接着在detail.wxml
中添加:
<van-goods-action>
<van-goods-action-icon icon="chat-o" text="客服" />
<van-goods-action-icon icon="cart-o" text="购物车" />
<van-goods-action-button
text="加入购物车"
type="warning"
/>
<van-goods-action-button text="立即购买" />
</van-goods-action>
如果出现
json: ["usingComponents"]["van-goods-action"]
未找到,再次点击 工具 -> 构建 npm即可。如果最终的实现效果和文档中的不一致,那么或许是详情–本地设置–调式基础库的原因。
"usingComponents": {
"van-goods-action": "@vant/weapp/goods-action/index",
"van-goods-action-icon": "@vant/weapp/goods-action-icon/index",
"van-goods-action-button": "@vant/weapp/goods-action-button/index"
}
接着在detail.wxml
中添加:
<van-goods-action>
<van-goods-action-icon icon="chat-o" text="客服" />
<van-goods-action-icon icon="cart-o" text="购物车" />
<van-goods-action-button
text="加入购物车"
type="warning"
/>
<van-goods-action-button text="立即购买" />
</van-goods-action>
如果出现
json: ["usingComponents"]["van-goods-action"]
未找到,再次点击 工具 -> 构建 npm即可。如果最终的实现效果和文档中的不一致,那么或许是详情–本地设置–调式基础库的原因。