接口文档地址:https://www.showdoc.com.cn/128719739414963/2513235043485226
阿里巴巴字体iconfont:https://www.iconfont.cn/
即本项目的后台已经写好了,直接调用接口即可
填入自己的openID
录名
作
styles
存放公共样式
components
存放组件
lib
存放第三库
utils
的帮助库
request
的接帮助库
名称
名称
index
分类
category
商品列表
goods_list
商品详情
goods_detail
购物
cart
收藏
collect
订单
order
搜索
search
个中
user
意反馈
feedback
登录
login
授权
auth
结算
pay
1. 打开阿巴巴字体图标 站
https://www.iconfont.cn/
2. 选择的图标
选择自己想要的图标添加入库
3. 添加项
选择购物车图标
点击添加至项目(我选择了三个购物车的图标)
可以将其添加到一个已有的项目或者新建一个项目
本次项目所需要的图标
点击Font class生成代码
会生成一个class地址
4. 点击链接,复制样式,将其放入styles目录下的iconfont.wxss中
@font-face {
font-family: "iconfont"; /* Project id 3078102 */
src: url('//at.alicdn.com/t/font_3078102_um8ol0i9ny.woff2?t=1640609932945') format('woff2'),
url('//at.alicdn.com/t/font_3078102_um8ol0i9ny.woff?t=1640609932945') format('woff'),
url('//at.alicdn.com/t/font_3078102_um8ol0i9ny.ttf?t=1640609932945') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-weibiaoti2fuzhi08:before {
content: "e625";
}
.icon-shoucangxuanzhong:before {
content: "e62b";
}
.icon-fenxiang:before {
content: "e86e";
}
.icon-kefu:before {
content: "e88f";
}
.icon-dingdan:before {
content: "e645";
}
.icon-fukuantongzhi:before {
content: "e60c";
}
.icon-tuihuotuikuan_dianpu:before {
content: "e773";
}
.icon-shoucang:before {
content: "e8b9";
}
.icon-gouwucheman:before {
content: "e600";
}
.icon-gouwuchekong:before {
content: "e601";
}
.icon-gouwucheman1:before {
content: "e602";
}
5. 在app.wxss中导入要使用的样式
@import "./styles/iconfont.wxss"
1. 在项目中创建icon文件夹,并将素材中的相关图标拷贝进入
2. 常见tabbar相关页面和样式
app.json中
{
"pages":[
"pages/index/index",
"pages/category/index",
"pages/goods_list/index",
"pages/goods_detail/index",
"pages/cart/index",
"pages/collect/index",
"pages/order/index",
"pages/search/index",
"pages/user/index",
"pages/feedback/index",
"pages/login/index",
"pages/auth/index",
"pages/pay/index"
],
"tabBar": {
"color": "#999",
"selectedColor": "#ff2d4a",
"backgroundColor": "#fafafa",
"position": "bottom",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "icons/home.png",
"selectedIconPath": "icons/home-o.png"
},
{
"pagePath": "pages/category/index",
"text": "分类",
"iconPath": "icons/category.png",
"selectedIconPath": "icons/category-o.png"
},
{
"pagePath": "pages/cart/index",
"text": "购物车",
"iconPath": "icons/cart.png",
"selectedIconPath": "icons/cart-o.png"
},
{
"pagePath": "pages/user/index",
"text": "我的",
"iconPath": "icons/my.png",
"selectedIconPath": "icons/my-o.png"
}
]
},
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#eb4450",
"navigationBarTitleText": "黑马优购",
"navigationBarTextStyle":"white"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
2.初始化页面
在app.wxss中
@import "./styles/iconfont.wxss";
/**在微信小程序中 不支持通配符* **/
page,view,text,swiper-item,image,navigator{
padding: 0;
margin: 0;
box-sizing: border-box;
}
/**
主题颜色 通过变量来实现
less中存在变量这个知识点
原生的css和wxss也支持变量
**/
page{
/**定义主题颜色**/
--themeColor:#eb4450;
/**
统一字体大小
1px = 2rpx
**/
font-size: 20rpx;
}
==
1. 在components下面创建一个SearchInput组件,实现搜索的功能
2. 在SearchInput.wxml创建搜索导航
搜索
3. SearchInput.wxss中的样式
/* components/SearchInput/SearchInput.wxss */
.search_input {
height: 90rpx;
padding: 10rpx;
background-color: var(--themeColor);
}
.search_input navigator {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: white;
border-radius: 15rpx;
color: #666;
}
4.引入所使用的组件
在pages/index/index.json中引入所使用的组件
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput"
},
"navigationBarTitleText": "优购首页"
}
5.使用组件
在pages/index/index.wxml
1. 网络请求获取轮播图的数据
在pages/index/index.js下
Page({
/**
* 页面的初始数据
*/
data: {
//轮播图数组
swipperList:[]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//异步请求获取轮播图的数据
wx.request({
url: 'https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata',
success:(result)=>{
this.setData({
swipperList:result.data.message
})
}
});
}
})
接口调用结果显示
没有结果显示解决办法
没有添加appid,点击详情按钮,选择不校验合法域名
为了后面的开发管理和部署上线,选择开发管理中的服务设置,设置服务器的域名
2. 轮播图动态渲染
在pages/index/index/wxml中
相应的wxss
.index_swiper swiper {
width: 750rpx;
height: 340rpx;
}
.index_swiper swiper image {
width: 100%;
}
3. 将原生的请求改为promise方式
在request的目录下创建index.js
export const request=(params)=>{
return new Promise((resolve,reject)=>{
wx.request({
...params,
success:(result)=>{
resolve(result);
},
fail: (err)=>{
reject(err)
}
});
} )
}
在pages/index/index.js中加入request.js的路径
import {request} from “…/…/request/index.js”
请求路径的改写
onLoad: function (options) {
//异步请求获取轮播图的数据
// wx.request({
// url: ‘https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata’,
// success:(result)=>{
// this.setData({
// swipperList:result.data.message
// })
// }
// });
request({url:'https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata'})
.then(result=>{
this.setData({
swipperList:result.data.message
})
})
},
1. 请求接口数据
在pages/index/index.js中获取导航数据
//获取导航数据
getCatesList(){
request({url:'https://api-hmugo-web.itheima.net/api/public/v1/home/catitems'})
.then(result=>{
this.setData({
catesList:result.data.message
})
})
}
2. 页面进行导航数据的显示
在pages/index/indedx.wxml中进行导航数据的显示
3. css样式
.index_cate {
display: flex;
padding: 20rpx;
}
.index_cate navigator {
flex: 1;
}
.index_cate navigator image {
width: 100%;
}
1. 获取接口数据
pages/index/index.js
//获取楼层的接口数据
getFloorList(){
request({url:'https://api-hmugo-web.itheima.net/api/public/v1/home/floordata'})
.then(result=>{
this.setData({
floorList:result.data.message
})
})
}
2. 内容显示
pages/index/index.wxml
3. 导入样式
pages/index/index.wxss
.index_floor .floor_group .floor_title {
padding: 10rpx 0;
}
.index_floor .floor_group .floor_title image {
width: 100%;
}
.index_floor .floor_group .floor_list {
overflow: hidden;
}
.index_floor .floor_group .floor_list navigator {
float: left;
width: 33.3%;
/*后面四个的超链接*/
/*2.3超链接*/
}
.index_floor .floor_group .floor_list navigator:nth-last-child(-n+4) {
/**
原图 232*386
232/286 = 33.3vw/height
**/
height: 27.72711207vw;
border-left: 10rpx solid #fff;
}
.index_floor .floor_group .floor_list navigator:nth-child(2),
.index_floor .floor_group .floor_list navigator:nth-child(3) {
border-bottom: 10rpx solid #fff;
}
.index_floor .floor_group .floor_list navigator image {
width: 100%;
height: 100%;
}
首页效果
在pages/category/index.js
// pages/category/index.js
import {request} from "../../request/index.js";
Page({
/**
* 页面的初始数据
*/
data: {
//左侧的菜单数据
leftMenuList:[],
//右侧的商品数据
rightContent:[],
//被点击的左侧菜单
currentIndex:0
},
//接口的返回数据
Cates:[],
onLoad:function(options){
this.getCates()
},
//获取分类菜单
getCates(){
request({
url:"https://api-hmugo-web.itheima.net/api/public/v1/categories"
})
.then(result=>{
this.Cates=result.data.message
//构造左侧的大菜单数据
let leftMenuList=this.Cates.map(v=>v.cat_name)
//构造右侧的商品数据
let rightContent=this.Cates[0].children;
this.setData({
leftMenuList,
rightContent
})
})
},
//左侧菜单的点击事件
handleItemTap(e)
{
/**
* 1.获取别点击的索引
* 2.getdata中currentIndex赋值
* 3.根据不同的索引渲染右侧的菜单
*/
const {index}=e.currentTarget.dataset;
let rightContent=this.Cates[index].children;
this.setData({
currentIndex:index,
rightContent
})
}
})
在pages/category/index.wxml
{{item}}
{{item1.cat_name}}
{{item2.cat_name}}
在pages/category/index.wxss
page {
height: 100%;
}
.cates {
height: 100%;
}
.cates .cates_container {
display: flex;
height: cac(100vh - 90rpx);
}
.cates .cates_container .left_menu {
flex: 2;
}
.cates .cates_container .left_menu .menu_item {
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 30rpx;
}
.cates .cates_container .left_menu .active {
color: var(--themeColor);
border-left: 5rpx solid currentColor;
}
.cates .cates_container .right_content {
flex: 5;
}
.cates .cates_container .right_content .goods_group .goods_title {
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
}
.cates .cates_container .right_content .goods_group .goods_title .delimiter {
color: #ccc;
padding: 0 10rpx;
}
.cates .cates_container .right_content .goods_group .goods_list {
display: flex;
flex-wrap: wrap;
}
.cates .cates_container .right_content .goods_group .goods_list navigator {
width: 33.33%;
text-align: center;
}
.cates .cates_container .right_content .goods_group .goods_list navigator image {
width: 50%;
}
先判断本地是否有没有过期的旧数据,如果有就使用旧数据,没有就重新从接口中获取
在pages/category/index.js中修改的部分代码
onLoad:function(options){
/**
* 1. 先判断本地存储中有没有旧数据
* {tine:Date.now,data[...]}
* 2. 没有旧数据直接发送新请求
* 有旧数据同时旧数据也没有过期 就是要本地存储中的旧数据即可
*/
//1.获取本地存储中的数据(小程序中也是本地存储)
const Cates=wx.getStorage("cates");
this.getCates()
//2.判断
if(!Cates)
{
//不存在 发送请求获取数据
this.getCates();
}
else
{
// //有旧的数据 定义过期时间
if(Date.now()-Cates.time>1000*10)
{
//重新发送数据
this.getCates()
}
else{
//可以使用旧数据
this.Cates=Cates.data;
//构造左侧的大菜单数据
let leftMenuList=this.Cates.map(v=>v.cat_name)
//构造右侧的商品数据
let rightContent=this.Cates[0].children;
this.setData({
leftMenuList,
rightContent
})
}
}
},
//获取分类菜单
getCates(){
request({
url:"https://api-hmugo-web.itheima.net/api/public/v1/categories"
})
.then(result=>{
this.Cates=result.data.message
//把接口中的数据存入本地存储中
wx.setStorageSync("cates", {time:Date.now(),data:this.Cates});
//构造左侧的大菜单数据
let leftMenuList=this.Cates.map(v=>v.cat_name)
//构造右侧的商品数据
let rightContent=this.Cates[0].children;
this.setData({
leftMenuList,
rightContent
})
})
},
在scrocll-view中有设置滚动条的位置
在页面中添加属性scroll-top并绑定值
在data中添加scrollTop
修改点击事件,点击一次距离顶部的距离为0
//左侧菜单的点击事件
handleItemTap(e)
{
/**
* 1.获取别点击的索引
* 2.getdata中currentIndex赋值
* 3.根据不同的索引渲染右侧的菜单
*/
const {index}=e.currentTarget.dataset;
let rightContent=this.Cates[index].children;
this.setData({
currentIndex:index,
//距离顶部的位置
scrollTop:0,
rightContent
})
}
发现这些接口有一些共同的路径,我们将其提取处理
在request/index.js下提取公共路径
然后在其他的请求接口中删除https://api-hmugo-web.itheima.net/api/public/v1/即可
1. tab/tab.wxml
{{item.value}}
2. tab/tab.wxss
.tab{}
.tab_title{
display: flex;
}
.title_item{
display: flex;
justify-content: center;
align-items: center;
flex: 1;
padding: 15rpx 0;
}
.active{
color: var(--themeColor);
border-bottom: 5rpx solid currentColor;
}
.tab_content{}
3. tab/tab.js
// components/tab/tab.js
Component({
/**
* 组件的属性列表
*/
properties: {
tab:{
type:Array,
value:[]
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
handleItemTap(e)
{
//获取点击的索引
const {index}=e.currentTarget.dataset;
//触发父组件中的事件 自定义
this.triggerEvent("tabItemChange",{index})
}
}
})
1. pages/gods_list/index.wxml
1
2
3
2. pages/gods_list/index.json
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput",
"tab":"../../components/tab/tab"
},
"navigationBarTitleText": "商品列表"
}
3. pages/gods_list/index.js
// pages/goods_list/index.js
Page({
/**
* 页面的初始数据
*/
data: {
tab:[
{
id:0,
value:'综合',
isActive:true
},
{
id:1,
value:'销量',
isActive:false
},
{
id:0,
value:'价格',
isActive:false
}
]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
console.log(options)
},
//标题的点击事件 从子组件中传递过来的
handleTabItemChange(e)
{
//获取被点击标题发索引
const {index}=e.detail
//修改原数组
let {tab}=this.data
tab.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
//赋值到data中
this.setData({
tab
})
}
})
需求分析
用户上滑页面 滚动条触底 开始加载下一页数据
下拉刷新页面
1. pages/goods_list/index.js
import {request} from "../../request/index.js";
Page({
/**
* 页面的初始数据
*/
data: {
tab:[
{
id:0,
value:'综合',
isActive:true
},
{
id:1,
value:'销量',
isActive:false
},
{
id:0,
value:'价格',
isActive:false
}
],
goodsList:[]
},
//接口要的数据
QueryParams:{
qurty:"",
cid:"",
pagenum:1,
pagesize:10
},
//总页数
totalPages:1,
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.QueryParams.cid=options.cid;
this.getGoodsList();
},
//获取商品数据
getGoodsList(){
request({url:"goods/search",data:this.QueryParams})
.then(result=>{
//获取总条数
const total= result.data.message.total
//计算总页数
this.totalPages=Math.ceil(total/this.QueryParams.pagesize)
console.log(this.totalPages)
this.setData({
goodsList:[...this.data.goodsList,...result.data.message.goods]
})
})
//关闭下拉刷新的窗口 如果没有
wx.stopPullDownRefresh()
},
//标题的点击事件 从子组件中传递过来的
handleTabItemChange(e)
{
//获取被点击标题发索引
const {index}=e.detail
//修改原数组
let {tab}=this.data
tab.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
//赋值到data中
this.setData({
tab
})
},
//页面上滑 滑动条触底事件
onReachBottom(){
if(this.QueryParams.pagenum>=this.totalPages)
{
wx.showToast({title: '没有下一页数据了' })
}
else{
//还有下一页数据
this.QueryParams.pagenum++;
this.getGoodsList()
}
},
//页面上滑刷新
onPullDownRefresh()
{
//1.重置数组
this.setData({
goodsList:[]
})
//重置页码
this.QueryParams.pagenum=1;
//发送请求
this.getGoodsList();
}
})
2. pages/goods_list/index.wxss
.first_tab .goods_item {
display: flex;
border-bottom: 1rpx solid #ccc;
}
.first_tab .goods_item .goods_img_wrap {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.first_tab .goods_item .goods_img_wrap image {
width: 70%;
}
.first_tab .goods_item .goods_info_wrap {
flex: 3;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.first_tab .goods_item .goods_info_wrap .goods_name {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.first_tab .goods_item .goods_info_wrap .goods_price {
color: var(--themeColor);
font-size: 32rpx;
}
3. pages/goods_list/index.js
// pages/goods_list/index.js
import {request} from "../../request/index.js";
Page({
/**
* 页面的初始数据
*/
data: {
tab:[
{
id:0,
value:'综合',
isActive:true
},
{
id:1,
value:'销量',
isActive:false
},
{
id:0,
value:'价格',
isActive:false
}
],
goodsList:[]
},
//接口要的数据
QueryParams:{
qurty:"",
cid:"",
pagenum:1,
pagesize:10
},
//总页数
totalPages:1,
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.QueryParams.cid=options.cid;
this.getGoodsList();
},
//获取商品数据
getGoodsList(){
request({url:"goods/search",data:this.QueryParams})
.then(result=>{
//获取总条数
const total= result.data.message.total
//计算总页数
this.totalPages=Math.ceil(total/this.QueryParams.pagesize)
console.log(this.totalPages)
this.setData({
goodsList:[...this.data.goodsList,...result.data.message.goods]
})
})
//关闭下拉刷新的窗口 如果没有
wx.stopPullDownRefresh()
},
//标题的点击事件 从子组件中传递过来的
handleTabItemChange(e)
{
//获取被点击标题发索引
const {index}=e.detail
//修改原数组
let {tab}=this.data
tab.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
//赋值到data中
this.setData({
tab
})
},
//页面上滑 滑动条触底事件
onReachBottom(){
if(this.QueryParams.pagenum>=this.totalPages)
{
wx.showToast({title: '没有下一页数据了' })
}
else{
//还有下一页数据
this.QueryParams.pagenum++;
this.getGoodsList()
}
},
//页面上滑刷新
onPullDownRefresh()
{
//1.重置数组
this.setData({
goodsList:[]
})
//重置页码
this.QueryParams.pagenum=1;
//发送请求
this.getGoodsList();
}
})
需求分析
点击轮播图预览大图
1. 给轮播图绑定点击事件
2. 调用小程序的api priviewUmage
点击加入购物车
1.pages/goods_detail/index.wxml
¥{{goodsObj.goods_price}}
{{goodsObj.goods_name}}
收藏
图文详情
客服
分享
购物车
加入购物车
立即购买
2. pages/goods_detail/index.wxss
page {
padding-bottom: 90rpx;
}
.detail_swiper swiper {
height: 65vw;
text-align: center;
}
.detail_swiper swiper image {
width: 60%;
}
.goods_price {
padding: 15rpx;
font-size: 32rpx;
font-weight: 600;
color: var(--themeColor);
}
.goods_name_row {
display: flex;
}
.goods_name_row .goods_name {
border-top: 5rpx solid #dedede;
border-bottom: 5rpx solid #dedede;
padding: 10rpx 0;
flex: 5;
color: #000;
font-size: 30rpx;
padding: 0 10rpx;
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.goods_name_row .goods_collect {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-left: 1rpx solid #000;
}
.goods_name_row .goods_collect .icon-shoucangxuanzhong {
color: orangered;
}
.goods_info .goods_info_title {
font-size: 32rpx;
color: var(--themeColor);
font-weight: 600;
padding: 20rpx;
}
.btm_tool {
border-top: 1rpc solid #000;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 90rpx;
background-color: #fff;
display: flex;
}
.btm_tool .tool_item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 24rpx;
position: relative;
}
.btm_tool .tool_item button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.btm_tool .btn_cart {
flex: 2;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #ffa500;
color: #fff;
font-size: 30rpx;
font-weight: 600;
}
.btm_tool .btn_buy {
flex: 2;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #eb4450;
color: #fff;
font-size: 30rpx;
font-weight: 600;
}
pages/goods_detail/index.js
// pages/goods_detail/index.js
import {request} from “…/…/request/index.js”;
/**
Page({
/**
},
//商品对象
GoodsInfo:{},
/**
},
//获取商品详情数据
getGoodsDetail(goods_id)
{
request({url:‘goods/detail’,data:{goods_id}})
.then(result=>{
const goodsObj=result.data.message;
this.GoodsInfo=goodsObj
//获取缓存中的商品收藏数组
let collect=wx.getStorageSync(“collect”)||[];
//判断当前商品是否别收藏
let isCollect = collect.some(v=>v.goods_id=this.GoodsInfo.goods_id)
this.setData({
goodsObj:{
goods_name:goodsObj.goods_name,
goods_price:goodsObj.goods_price,
//iphone部分手机不识别webp图片格式 可以在后端进行修改 临是可以自己该 确保后台存在,1.webp=>1,jpg
goods_introduce:goodsObj.goods_introduce.replace(/.webp/g,’.jpg’),
pics:goodsObj.pics
},
isCollect
})
})
},
bindlePrevewImage(e){
//构造预览图片的数组
const urls=this.GoodsInfo.pics.map(v=>v.pics_mid);
//接收传递过来的url
const current=e.currentTarget.dataset.url;
wx.previewImage({
current,
urls
})
},
handleCartAdd()
{
//1.获取缓存中的购物车数据
let cart=wx.getStorageSync(“cart”)||[];
//2.判断商品是否存在与购物车中
let index=cart.findIndex(v=>v.goods_id=this.GoodsInfo.goods_id);
if(index===-1)
{
//3.不存在第一次添加
this.GoodsInfo.num=1;
this.GoodsInfo.checked=true
cart.push(this.GoodsInfo);
}
else
{
//4.已经存在购物车中 执行num++
cart[index].num++
}
//5.把购物车重新添加到缓存中
wx.setStorageSync(‘cart’, cart)
wx.showToast({
title:“加入成功”,
icon:‘success’,
//true 防止用户手抖疯狂点击
mask: true
})
},
//点击商品收藏图标
handleCollect(){
let isCollect=false
//1. 获取缓存中商品收藏数组
let collect=wx.getStorageSync(“collect”)||[]
//判断该商品是否被收藏过
let index=collect.findIndex(v=>v.goods_id=this.GoodsInfo.goods_id)
//3 当index=1-表示已经收藏过
if(index!-1)
{
//已经收藏过 应该从收藏册数组中删除
collect.splice(index,1)
isCollect=false;
wx.showToast({
title:“取消成功”,
icon:“success”,
mask:true
});
}
else{
//没有收藏过
collect.push(this.GoodsInfo)
isCollect=true
wx.showToast({
title:“收藏成功”,
icon:“success”,
mask:true
});
}
wx.setStorageSync(“collect”,collect)
this.setData({
isCollect
})
}
})
1. 在 pages/collect/index.json中引入组件
{
"usingComponents": {
"tab":"../../components/tab/tab"
},
"navigationBarTitleText":"商品收藏"
}
** 2.pages/collect/index.wxml**
全部
正在热卖
即将上线
{{item.goods_name}}
¥{{item.goods_price}}
3. pages/collect/index.js
// pages/collect/index.js
Page({
/**
* 页面的初始数据
*/
data: {
collect:[],
tabs:[
{
id:0,
value:"商品收藏",
isActive:true
},
{
id:1,
value:"品牌收藏",
isActive:false
},
{
id:2,
value:"店铺收藏",
isActive:false
},
{
id:3,
value:"浏览足迹",
isActive:false
}
]
},
onShow(){
const collect=wx.getStorageSync("collect")||[]
this.setData({
collect
})
},
handleTabItemChange(e)
{
console.log(e)
//获取被点击标题发索引
const {index}=e.detail
//修改原数组
let {tabs}=this.data
for(let i=0;i<4;i++)
{
if(i===index)
{
tabs[i].isActive=true
}
else
{
tabs[i].isActive=false
}
}
//赋值到data中
this.setData({
tabs
})
}
})
4. pages/collect/index.wxss
.collect_main {
background-color: #f3f4f6;
}
.collect_main .collect_title {
padding: 40rpx 0;
}
.collect_main .collect_title .collect_tips {
padding: 15rpx;
border: 1rpx solid #ccc;
margin-left: 25rpx;
background-color: #fff;
}
.collect_main .collect_title .active {
color: var(--themeColor);
border-color: currentColor;
}
.collect_main .collect_content .goods_item {
display: flex;
background-color: #fff;
border-bottom: 1rpx solid #ccc;
}
.collect_main .collect_content .goods_item .goods_img_wrap {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.collect_main .collect_content .goods_item .goods_img_wrap image {
width: 70%;
}
.collect_main .collect_content .goods_item .goods_info_wrap {
flex: 3;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.collect_main .collect_content .goods_item .goods_info_wrap .goods_name {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.collect_main .collect_content .goods_item .goods_info_wrap .goods_price {
color: var(--themeColor);
font-size: 32rpx;
}
需求分析
获取用户的收获地址
获取用户对小程序所授予获取地址的权限状态 scope
onshow
1. 获取缓存中的购物车数组
2. 把购物车中的数据填充到data中
全选的实现
1. onshow获取缓存中的购物车数据
2. 根据购物车中的商品数据 所有的商品都被选中 checked=true 全选就被选中
总价格 总数量
商品属性
全选和反选
商品数量的编辑
5.把cart数组 重新设置回缓存中和data中
点击结算
1. pages/cart/index.wxml
{{address.userName}}
{{address.provinceName+address.cityName+address.countyName+address.detailInfo}}
{{address.telNumber}}
购物车
{{item.goods_name}}
¥{{item.goods_price}}
-
{{item.num}}
+
全选
总计¥{{totalPrice}}
包含运费
结算{{totalNum}}
2. pages/cart/index.wxss
page {
padding-bottom: 90rpx;
}
.revice_address_row .address_btn {
padding: 20rpx;
}
.revice_address_row .address_btn button {
width: 60%;
}
.revice_address_row .user_info_row {
display: flex;
padding: 20rpx;
}
.revice_address_row .user_info_row .user_info {
flex: 5;
}
.revice_address_row .user_info_row .user_phone {
flex: 3;
text-align: right;
}
.cart_content .cart_title {
padding: 20rpx;
font-size: 36rpx;
color: var(--themeColor);
border-top: 1rpx solid currentColor;
border-bottom: 1rpx solid currentColor;
}
.cart_content .cart_main .cart_item {
display: flex;
padding: 10rpx;
border-bottom: 1rpx solid #000;
}
.cart_content .cart_main .cart_item .cart_chk_wrap {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.cart_content .cart_main .cart_item .cart_img_wrap {
flex: 2;
display: flex;
align-items: center;
justify-content: center;
}
.cart_content .cart_main .cart_item .cart_img_wrap image {
width: 80%;
}
.cart_content .cart_main .cart_item .cart_info_wrap {
flex: 4;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.cart_content .cart_main .cart_item .cart_info_wrap .goods_name {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
color: #666;
}
.cart_content .cart_main .cart_item .cart_info_wrap .goods_price_wrap {
display: flex;
justify-content: space-between;
}
.cart_content .cart_main .cart_item .cart_info_wrap .goods_price_wrap .goods_price {
color: var(--themeColor);
font-size: 34rpx;
}
.cart_content .cart_main .cart_item .cart_info_wrap .goods_price_wrap .cart_num_tool {
display: flex;
}
.cart_content .cart_main .cart_item .cart_info_wrap .goods_price_wrap .cart_num_tool .num_edit {
width: 55rpx;
height: 55rpx;
display: flex;
justify-content: center;
justify-items: center;
border: 1rpx solid #ccc;
}
.cart_content .cart_main .cart_item .cart_info_wrap .goods_price_wrap .cart_num_tool .goods_num {
width: 55rpx;
height: 55rpx;
display: flex;
justify-content: center;
justify-items: center;
}
.footer_tool {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 90rpx;
background-color: #fff;
display: flex;
border-top: 1rpx solid #ccc;
}
.footer_tool .all_chk_wrap {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.footer_tool .total_price_wrap {
flex: 5;
padding-right: 15rpx;
text-align: right;
}
.footer_tool .total_price_wrap .total_price text.total_price_text {
color: var(--themeColor);
font-size: 34rpx;
font-weight: 600;
}
.footer_tool .order_pay_wrap {
flex: 3;
background-color: var(--themeColor);
color: #fff;
font-size: 32rpx;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
}
在使用微信小程序的过程中,我发现由于异步流程延迟的原因,导致不能及时的获取真实的数据,我们可以使用promise()异步请求来解决这个问题
在utils下面创建一个名为asyncWx.js文件,后面问我们可以进行异步待遇
/**
*promise形式的 getSetting
*/
export const getSetting =()=>{
return new Promise((resolve,reject)=>{
wx.getSetting({
success: function(result) {
resolve(result)
},
fail:(err)=>{
reject(err)
}
});
})
}
/**
*promise形式的 chooseAddress
*/
export const chooseAddress =()=>{
return new Promise((resolve,reject)=>{
wx.chooseAddress({
success: function(result) {
resolve(result)
},
fail:(err)=>{
reject(err)
}
});
})
}
/**
*promise形式的 openSetting
*/
export const openSetting =()=>{
return new Promise((resolve,reject)=>{
wx.openSetting({
success: function(result) {
resolve(result)
},
fail:(err)=>{
reject(err)
}
});
})
}
export const showToast =({title})=>{
return new Promise((resolve,reject)=>{
wx.showToast({
title: title,
icon: 'success',
success:(res)=>{
resolve(res)
},
fail:(err)=>{
reject(err)
}
})
})
}
3.pages/cart/index.js
调用相关的异步函数
// pages/cart/index.js
//调用promise
import{getSetting,chooseAddress,openSetting,showToast} from "../../utils/asyncWx.js"
// import regeneratorRuntime from "../../lib/runtime/runtime"
Page({
/**
* 页面的初始数据
*/
data: {
address:{},
cart:[],
allChecked:false,
totalPrice:0,
totalNum:0
},
onShow(){
// 获取缓冲中的收货地址信息
const address=wx.getStorageSync("address")
//获取缓存中的购物车数据
const cart=wx.getStorageSync("cart")||[]
// 计算全选中
// every 数组方法 遍历会接收一个回调函数 如果每一个回调函数都返回true every方法的返回值就为true 只有有一个返回false every方法不在执行 防护false
//空数组返回值为true
// const allChecked=cart.length?cart.every(v=>v.checked):false
this.setCart(cart)
this.setData({
address
})
},
//点击获取收货地址
async handleChoseAddress()
{
//1.获取权限状态
const res1=await getSetting();
const scopeAddress=res1.authSetting['scope.address']
//2 。判断权限状态
if(scopeAddress===false)
{
await openSetting()
}
//调用获取收货地址的api
const address=await chooseAddress();
console.log(address)
//放入缓存中
wx.setStorageSync('address', address)
},
//商品选中
handeItemChange(e)
{
//获取选中商品的id
const goods_id=e.currentTarget.dataset.id
//获取购物车数组
let {cart}=this.data;
//找到被修改商品的对象
let index = cart.findIndex(v=>v.goods_id===goods_id)
//修改商品的选中事件
cart[index].checked=!cart[index].checked
this.setCart(cart)
},
//商品全选和反选
handleItemAllCheck(e)
{
//获取data中的数据和选中状态
let {cart,allChecked}=this.data
//选中状态取反
allChecked=!allChecked
//循环修改cart中商品的选中状态
cart.forEach(v=>v.checked=allChecked)
//把修改后的值填充回data或者缓存中
this.setCart(cart)
},
//商品数量的编辑
handleItemNumEdit(e)
{
//获取传递过来的参数
const {operation,id}=e.currentTarget.dataset
//获取购物车数组
let {cart}=this.data;
//找到需要获取商品的索引
const index=cart.findIndex(v=>v.goods_id===id)
if(cart[index].num===1&&operation===-1)
{
//弹框提示
wx.showModal({
title: '提示',
content: '你是否删除',
success: (res)=> {
if (res.confirm) {
cart.splice(index, 1);
this.setCart(cart)
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
//进行修改数量
else
{
cart[index].num+=operation
this.setCart(cart)
}
},
//点击结算功能
async handlePay(){
//判断收货地址
const {address,totalNum}=this.data
if(!address.userName)
{
await showToast({title:"您还没有选择地址"})
return
}
//判断用户是否选购了商品
if(totalNum===0)
{
await showToast({title:"您还没有选购商品"})
return
}
//跳转到支付页面
wx.navigateTo({
url: '/pages/pay/index'
});
},
//设置购物车状态同时 重新计算底部工具栏的数据 全选中 价格 购买数量
setCart(cart){
let allChecked=true
//总价格 总数量
let totalPrice=0
let totalNum=0
cart.forEach(v=>{
if(v.checked)
{
totalPrice+=v.num*v.goods_price
totalNum+=v.num
}
else{
allChecked=false
}
})
if(cart.length==0)
{
allChecked=false
}
//将数据设置回data和缓存中
this.setData({
cart,
totalNum,
totalPrice,
allChecked
})
wx.setStorageSync("cart",cart)
}
})
输入绑定 值改变事件 input事件
防抖 (防止抖动) 定时器 节流
1. pages/search/index.wxml
{{item.goods_name}}
2. pages/search/index.js
import {request} from "../../request/index.js"
Page({
/**
* 页面的初始数据
*/
data: {
goods:[],
//取消按钮是显示
isFouces:false,
//输入框的值
inputValue:''
},
Timeid:-1,
handleInpput(e)
{
//获取输入框的值
const {value}=e.detail
//监测合法值
if(!value.trim())
{
this.setData({
goods:[],
isFouces:false
})
//值不合法
return ;
}
this.setData({
isFouces:true
})
//发送获取数据
clearTimeout(this.Timeid)
this.Timeid=setTimeout(()=>{
this.qsearch(value)
},1000)
this.qsearch(value)
},
//发送请求获取搜索数据
async qsearch(query)
{
console.log(query)
const res=await request({url:"goods/search",data:{query}});
this.setData({
goods:res.data.message.goods
})
},
//点击取消按钮
handleCancle()
{
this.setData({
inputValue:'',
isFouces:false,
goods:[]
})
}
})
3. pages/search/index.wxss
page {
background-color: #dedede;
padding: 20rpx;
}
.search_row {
height: 60rpx;
display: flex;
}
.search_row input {
background-color: #fff;
flex: 4;
height: 100%;
padding-left: 30rpx;
}
.search_row button {
flex: 1;
height: 100%;
font-size: 26rpx;
padding: 0;
margin: 0 10rpx;
display: flex;
justify-content: center;
align-items: center;
}
.search_content {
margin-top: 30rpx;
}
.search_content .search_item {
background-color: #fff;
font-size: 26rpx;
padding: 15rpx 10rpx;
border-bottom: 1rpx solid #ccc;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
1. page/login/index.wxml
2. pages/login/index.js
// pages/login/index.js
Page({
handleGetUserInfo(e)
{
const {userInfo} = e.detail;
wx.setStorageSync('userInfo', userInfo)
wx.navigateBack({
delta: 1
})
}
})
3. pages/login/index.wxss
/* pages/login/index.wxss */
button{
margin-top: 40rpx;
width: 70%;
}
1. 在pages/collect/index.json中引入组件
{
"usingComponents": {
"tab":"../../components/tab/tab"
},
"navigationBarTitleText":"商品收藏"
}
2. pages/collect/index.wxss
全部
正在热卖
即将上线
{{item.goods_name}}
¥{{item.goods_price}}
3. pages/ccollect/index.wxss
.collect_main {
background-color: #f3f4f6;
}
.collect_main .collect_title {
padding: 40rpx 0;
}
.collect_main .collect_title .collect_tips {
padding: 15rpx;
border: 1rpx solid #ccc;
margin-left: 25rpx;
background-color: #fff;
}
.collect_main .collect_title .active {
color: var(--themeColor);
border-color: currentColor;
}
.collect_main .collect_content .goods_item {
display: flex;
background-color: #fff;
border-bottom: 1rpx solid #ccc;
}
.collect_main .collect_content .goods_item .goods_img_wrap {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.collect_main .collect_content .goods_item .goods_img_wrap image {
width: 70%;
}
.collect_main .collect_content .goods_item .goods_info_wrap {
flex: 3;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.collect_main .collect_content .goods_item .goods_info_wrap .goods_name {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.collect_main .collect_content .goods_item .goods_info_wrap .goods_price {
color: var(--themeColor);
font-size: 32rpx;
}
4. pages/collect/index.js
// pages/collect/index.js
Page({
/**
* 页面的初始数据
*/
data: {
collect:[],
tabs:[
{
id:0,
value:"商品收藏",
isActive:true
},
{
id:1,
value:"品牌收藏",
isActive:false
},
{
id:2,
value:"店铺收藏",
isActive:false
},
{
id:3,
value:"浏览足迹",
isActive:false
}
]
},
onShow(){
const collect=wx.getStorageSync("collect")||[]
this.setData({
collect
})
},
handleTabItemChange(e)
{
console.log(e)
//获取被点击标题发索引
const {index}=e.detail
//修改原数组
let {tabs}=this.data
for(let i=0;i<4;i++)
{
if(i===index)
{
tabs[i].isActive=true
}
else
{
tabs[i].isActive=false
}
}
//赋值到data中
this.setData({
tabs
})
}
})
点击+号 触发tap点击事件
点击自定义图片 组件
点击提交
由于需要使用图片上传的组件,先引入图片上传的组件
在components下面创建一个名为Upimg的文件夹,用于文件上传组件
在components/Upimg下面的Upimg文件下声明组件
{
“component”: true,
“usingComponents”: {}
}
components/Upimg/Upimg.wxml
components/Upimg/Upimg.wxss
.up_img_wrap{
width: 90rpx;
height: 90rpx;
position: relative;
}
.up_img_wrap image{
width: 100%;
height: 100%;
border-radius: 15rpx;
}
.up_img_wrap icon{
position: absolute;
top: -22rpx;
right: -22rpx;
}
components/Upimg/Uping.js
// components/Upimg/Upimg.js
Component({
/**
},
/**
},
/**
}
})
1. 在pages/feedback/index.json中声明组件
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput",
"tab":"../../components/tab/tab",
"UpImg":"../../components/Upimg/Upimg"
},
"navigationBarTitleText":"意见反馈",
"enablePullDownRefresh":true,
"backgroundTextStyle":"dark"
}
2. pages/feedback/index.wxml
问题的种类
功能建议
购买遇到的问题
性能问题
其他
3. pages/feedback/index.wxss
page {
background-color: #eeeeee;
}
.fb_main {
padding: 20rpx;
}
.fb_main .fb_tips {
display: flex;
flex-wrap: wrap;
}
.fb_main .fb_tips text {
width: 30%;
padding: 10rpx;
text-align: center;
background-color: #fff;
margin: 20rpx 10rpx;
}
.fb_main .fb_content {
background-color: #fff;
margin-top: 20rpx;
}
.fb_main .fb_content textarea {
padding: 10rpx;
}
.fb_main .fb_content .fb_tool {
display: flex;
flex-wrap: nowrap;
padding-bottom: 30rpx;
}
.fb_main .fb_content .fb_tool button {
margin: 0;
width: 90rpx;
height: 90rpx;
font-size: 60rpx;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
margin-left: 20rpx;
color: #ccc;
margin-top: 20rpx;
}
.fb_main .fb_content .fb_tool .up_img_item {
margin-top: 20rpx;
margin-left: 20rpx;
}
.fb_main .form_btn_wrap {
margin-top: 20rpx;
display: flex;
justify-content: flex-end;
}
.fb_main .form_btn_wrap button {
background-color: red;
color: white;
margin: 0;
padding: 0;
width: 30%;
}
4. pages/feedback/index.js
Page({
/**
* 页面的初始数据
*/
data: {
tab:[
{
id:0,
value:'体验问题',
isActive:true
},
{
id:1,
value:'商品商家投诉',
isActive:false
}
],
//被选中图片的路径 数组
chooseImgs:[],
// //外网的图片路径数组
// UploadImgs:[],
//文本域内容
textVal:''
},
//标题的点击事件 从子组件中传递过来的
handleTabItemChange(e)
{
//获取被点击标题发索引
const {index}=e.detail
//修改原数组
let {tab}=this.data
tab.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
//赋值到data中
this.setData({
tab
})
},
//点击+号自定义选择图片
handleChoseImg(e)
{
//调用小程序中内置的选择图片api
wx.chooseImage({
//同时选中图片的数量
count:9,
//图片的格式 原图 压缩
sizeType:['original','compressed'],
//图片的来源 相册 照相机
sourceType:['album','camera'],
success:(result)=>{
console.log(result)
this.setData({
//图片数组进行拼接
chooseImgs:[...this.data.chooseImgs,...result.tempFilePaths]
})
}
});
},
//点击自定义的图片进行删除
handleRemoveImage(e)
{
//获取被点击的组件的索引
const {index}=e.currentTarget.dataset
//获取data中的图片数组
let {chooseImgs}=this.data
//删除元素
chooseImgs.splice(index,1)
this.setData({
chooseImgs
})
},
//文本域的输入事件
handleTextInput(e)
{
this.setData({
textVal:e.detail.value
})
},
//提交按钮的点击事件
handleFormSubmit()
{
//获取文本域的内容
const {textVal,chooseImgs}=this.data
//合法性验证
if(!textVal.trim())
{
//不合法
wx.showToast({
title:'输入不合法',
icon:'none',
mask: true
});
return
}
//准备上传文件,到专门的服务器
//上传文件的api不支持多个文件同时上传
//显示正在等待的图片
wx.showLoading({
title:"正在上传",
mask:true
})
if(chooseImgs.length!=0)
{
chooseImgs.forEach((v,i)=>{
wx.uploadFile({
//图片要上传到哪里
// url: 'https://images.ac.cn/Home/Index/UploadAction/',
url:'https://img.coolcr.cn/api/upload',
//要上传文件的路径
filePath:v,
//上传文件的名称 后台获取某个文件 file
// name:'file',
name:"image",
// header: {}, // 设置请求的 header
// HTTP 请求中其他额外的 form data
formData: {},
success: function(res){
let url=JSON.parse(res.data).data.url
// this.UploadImgs.push(url)
}
})
//所有图片都上传完毕才会触发
if(i===chooseImgs.length-1){
wx.hideLoading()
console.log('把文本中的内容和外网的图片数组提交到后台中')
//提交都成功了
//重置页面
this.setData({
textVal:'',
chooseImgs:[]
})
//返回到上一个页面
wx.navigateBack({
delta: 1
})
}
})
}
else
{
console.log("只是提交了文本")
wx.hideLoading()
//返回到上一个页面
wx.navigateBack({
delta: 1
})
}
}
})
1. pages/user/index.wxml
{{userInfo.nickName}}
登录
8
收藏的店铺
{{collectNums}}
收藏的商品
8
关注的商品
8
我的足迹
我的订单
全部订单
待付款
待收货
退货/退款
收货地址管理
联系客服
400-618-4000
意见反馈
关于我们
把应用推荐给其他人
2. pages/user/index.wxss
page {
background-color: #edece8;
}
.user_info_wrap {
height: 45vh;
overflow: hidden;
background-color: var(--themeColor);
position: relative;
}
.user_info_wrap .user_img_wrap {
position: relative;
}
.user_info_wrap .user_img_wrap .user_bg {
height: 50vh;
filter: blur(10rpx);
}
.user_info_wrap .user_img_wrap .user_info {
position: absolute;
left: 50%;
top: 20%;
transform: translateX(-50%);
text-align: center;
}
.user_info_wrap .user_img_wrap .user_icon {
width: 150rpx;
height: 150rpx;
border-radius: 50%;
}
.user_info_wrap .user_img_wrap .user_name {
color: #fff;
margin-top: 40rpx;
}
.user_info_wrap .user_btn {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 40%;
border: 1rpx solid greenyellow;
color: greenyellow;
font-size: 38rpx;
padding: 30rpx;
border-radius: 10rpx;
}
.user_content {
position: relative;
}
.user_content .user_main {
padding-bottom: 100rpx;
color: #666;
position: absolute;
width: 90%;
left: 50%;
transform: translateX(-50%);
top: -40rpx;
}
.user_content .user_main .history_wrap {
background-color: #fff;
display: flex;
}
.user_content .user_main .history_wrap navigator {
flex: 1;
padding: 10rpx 0;
text-align: center;
}
.user_content .user_main .history_wrap navigator .his_num {
color: var(--themeColor);
}
.user_content .user_main .orders_wrap {
background-color: #fff;
margin-top: 30rpx;
}
.user_content .user_main .orders_wrap .order_title {
padding: 20rpx;
border-bottom: 1rpx solid #ccc;
}
.user_content .user_main .orders_wrap .order_content {
display: flex;
}
.user_content .user_main .orders_wrap .order_content navigator {
padding: 15rpx 0;
flex: 1;
text-align: center;
}
.user_content .user_main .orders_wrap .order_content navigator .iconfont {
color: var(--themeColor);
font-size: 40rpx;
}
.user_content .user_main .address_wrap {
margin-top: 30rpx;
background-color: #fff;
padding: 20rpx;
}
.user_content .user_main .app_info_wrap {
margin-top: 30rpx;
background-color: #fff;
}
.user_content .user_main .app_info_wrap .app_info_item {
padding: 20rpx;
border-bottom: 1rpx solid #ccc;
}
.user_content .user_main .app_info_wrap .app_info_contact {
display: flex;
justify-content: space-between;
}
.user_content .user_main .recommend_wrap {
margin-top: 30rpx;
background-color: #fff;
padding: 20rpx;
}
3. pages/user/index.js
// pages/user/index.js
Page({
/**
* 页面的初始数据
*/
data: {
userInfo:{},
//收藏商品的数量
collectNums:0
},
onShow(){
const userInfo=wx.getStorageSync('userInfo')
const collect=wx.getStorageSync("collect")||[]
this.setData({
userInfo,
collectNums:collect.length
})
}
})
说明:由于是个人用户,小程序的订单功能未实现,但小程序中的大部分功能已经实现