第一天
文档地址 https://www.showdoc.com.cn/128719739414963
01
在全局app.js中,输入app选择第三个,可以把常用方法补出来
在项目index.js中,输入的是page
02
把阿里图标库的代码放到styles的icon.wxss中,在全局app.wxss中引入
@import “./styles/icon.wxss”;
03
在app.json中输tabBar然后自动补全
其中pagePath是路径,text为文字,iconPath是未选中的图标,selectedIconPath是选中的图标
其中在tabBar下的属性中,color是未选中的字体颜色,selectedColor是选中时的颜色,backgroundColor是整体的背景颜色
"tabBar": {
"color":"#999",
"selectedColor":"#ff2d4a",
"backgroundColor":"#fafafa",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "./icons/首页.png",
"selectedIconPath": "./icons/首页-o.png"
},
{
"pagePath": "pages/category/index",
"text": "分类",
"iconPath": "./icons/分类.png",
"selectedIconPath": "./icons/分类-o.png"
},
{
"pagePath": "pages/cart/index",
"text": "购物车",
"iconPath": "./icons/购物车空.png",
"selectedIconPath": "./icons/购物车空-o.png"
},
{
"pagePath": "pages/user/index",
"text": "我的",
"iconPath": "./icons/我的.png",
"selectedIconPath": "./icons/我的-o.png"
}
]
}
04
在微信小程序中 不支持 通配符 * ,所以要使用这种写法
page,view,text,swiper,swiper-item,image,navigator{
padding:0;
margin:0;
box-sizing:border-box;
}
主题颜色,通过变量来实现
- less 中 存在 变量这个知识
- 原生的css和wxss也是支持 变量
在全局app.wxss中定义,字体默认直接使用
page{
/* 定义主题颜色 */
--themeColor:#eb4450;
/*
定义统一字体大小 假设设计稿大小时 375px
1px=2rpx
14px = 28rpx
*/
font-size:28rpx;
}
在index.wxss中使用
view{
color:var(--themeColor)
}
在app.json中的window下
navigationBarBackgroundColor 是背景颜色
navigationBarTextStyle 是字体颜色
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#eb4450",
"navigationBarTitleText": "收购阿里计划",
"navigationBarTextStyle":"white"
}
05 搜索框
先注册组件,在components文件夹中新建一个目录,名字为SearchInput,再右键文件夹创建component,名字与文件夹名字相同
之后在要使用该组件的index.json中使用usingComponents,进行注册
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput"
},
"navigationBarTitleText":"首页"
}
components中SearchInput.wxml
<view class="search_input">
/* url是跳转地址,open-type="navigate"是跳转到非tabBar页面 */
<navigator url="/pages/search/index" open-type="navigate">
搜索
</navigator>
</view>
SearchInput.wxss
.search_input{
height:90rpx;
padding:10rpx;
background-color:var(--themeColor)
}
.search_input navigator{
display:flex;
justify-content: center;
align-items: center;
background-color:#fff;
color:#666;
height:100%;
border-radius:15rpx;
}
06 轮播图请求数据
Page({
data: {
swiperList:[]
},
/* 页面一加载就会触发 */
onLoad: function (options) {
wx.request({
url: 'https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata',
success:(result)=>{
this.setData({
swiperList:result.data.message
})
}
})
}
})
将数据传输给data
this.setData({
swiperList:result.data.message
})
07 轮播图渲染
先进行for循环,除了key以外,其他调用都需要 {{}} 括号,并且循环时,默认item是数据,index是下标
<!--
1 swiper标签存在默认的宽度和高度
100% * 150px
2 image标签也存在默认的宽度和高度
320px * 240px
3 设计图片和轮播图
1 先看一下原图的宽高 750 * 340
2 让图片的高度自适应 宽度 等于100%
3 让swiper标签的高度 变成和图片的高一样即可
4 图片标签
mode属性 渲染模式
widthFix 让图片的标签宽高 和 图片标签的内容的宽高等比
-->
<view class="index_swiper">
<swiper indicator-dots autoplay circular>
<swiper-item wx:for="{{swiperList}}" wx:key="goods_id">
<navigator>
<image src="{{item.image_src}}" mode="widthFix"></image>
</navigator>
</swiper-item>
</swiper>
</view>
其中swiper中的其他属性分别是:
indicator-dots 是否显示面板指示点
indicator-color 指示点颜色
indicator-active-color 当前选中的指示点颜色
autoplay 是否自动切换
circular 是否循环轮播
/* 轮播图 */
.index_swiper swiper{
width:750rpx;
height:340rpx;
}
.index_swiper swiper image{
width:100%;
}
08 导航渲染
通过flex布局,每一个for循环出来的都占比份1,之后用padding把盒子挤过去
<view class="index_cate">
<navigator wx:for="{{cateList}}" wx:key="name">
<image mode="widthFix" src="{{item.image_src}}"></image>
</navigator>
</view>
/* 导航 */
.index_cate {
display:flex;
}
.index_cate navigator{
flex:1;
padding:15rpx;
}
.index_cate navigator image{
width:100%;
}
data: {
cateList:[]
},
getCateList(){
wx.request({
url: 'https://api-hmugo-web.itheima.net/api/public/v1/home/catitems',
success:(result)=>{
this.setData({
cateList:result.data.message
})
}
})
}
第二天
09 楼层
获取数据
getFloorList(){
wx.request({
url:"https://api-hmugo-web.itheima.net/api/public/v1/home/floordata",
success:(result)=>{
this.setData({
floorList:result.data.message
})
}
})
}
wxml
<!-- 楼层开始 -->
<view class="index_floor">
<view class="floor_group" wx:for="{{floorList}}" wx:for-item="item1" wx:for-index="index1" wx:key="floor_title">
<!-- 标题 -->
<view class="floor_title">
<image src="{{item1.floor_title.image_src}}" mode="widthFix"></image>
</view>
<!-- 内容 -->
<view class="floor_list">
<navigator wx:for="{{item1.product_list}}" wx:for-item="item2" wx:for-index="index2" wx:key="name">
<image src="{{item2.image_src}}" mode="{{index2===0?'widthFix':'scaleToFill'}}"></image>
</navigator>
</view>
</view>
</view>
<!-- 图片的scaleToFill是根据高度自适应 -->
<!-- 楼层结束 -->
wxss
.floor_gourp .floor_title image{
width:100%;
}
.floor_title{
padding:10rpx 0;
}
.floor_list{
overflow:hidden;
}
.floor_list navigator{
float: left;
width:33.33%;
}
.floor_list navigator:nth-last-child(-n+4){
height:27.72711207vw;
border-left:10rpx solid #fff;
}
.floor_list navigator:nth-child(2),
.floor_list navigator:nth-child(3){
border-bottom:10rpx solid #fff;
}
.floor_list navigator image{
width:100%;
height:100%;
}
10 分类页获取数据
js代码
// pages/category/index.js
Page({
data: {
//左侧的菜单数据
leftMenuList:[],
//右侧的商品数据
rightContent:[]
},
Content:[],
onLoad: function (options) {
this.getMenuList();
},
getMenuList(){
wx.request({
url: 'https://api-hmugo-web.itheima.net/api/public/v1/categories',
success:(result)=>{
this.Content=result.data.message
let leftMenuList = this.Content.map(v=>v.cat_name)
let rightContent = this.Content[0].children
console.log(rightContent);
this.setData({
leftMenuList,
rightContent
})
console.log(result);
}
})
}
})
11 分类页布局
这个是微信小程序提供给我们的能够上下拉动,左右拉动的标签
wxss vh和vw是手机屏幕的宽高,总占100份
page{
height:100%;
}
.cates{
height:100%;
}
.cates .cates_container{
height:calc(100vh - 90rpx);
display:flex;
}
.cates .cates_container .left_menu{
flex:2;
background-color: aqua;
}
.cates .cates_container .right_content{
flex:5;
background-color: lawngreen;
}
wxml scroll-y是可以让纵向滚动
<view class="cates">
<SearchInput></SearchInput>
<view class="cates_container">
<!-- 左侧菜单 -->
<scroll-view scroll-y class="left_menu">
</scroll-view>
<!-- 右侧商品内容 -->
<scroll-view class="right_content"></scroll-view>
</view>
</view>
第三天
12 分类页面布局2
学习布局方法
wxss完整代码
page{
height:100%;
}
.cates{
height:100%;
}
.cates .cates_container{
height:calc(100vh - 90rpx);
display:flex;
}
.cates .cates_container .left_menu{
flex:2;
}
.cates .cates_container .right_content{
flex:5;
}
/* 第三天 */
.active{
color:var(--themeColor);
border-left:5rpx solid currentColor;
width:95%;
background-color: rgba(224, 224, 224, 0.3);
}
.left_menu .menu_list{
height:80rpx;
display:flex;
align-items:center;
justify-content:center;
font-size:30rpx;
}
.right_content .goods_group .goods_list{
display:flex;
flex-wrap:wrap;
}
.right_content .goods_group .goods_list navigator{
width:33.33%;
text-align:center;
}
.right_content .goods_group .goods_list navigator image{
width:50%;
}
.goods_title{
display:flex;
justify-content:center;
align-items:center;
height:80rpx;
}
.goods_title .delimiter{
color:#ccc;
padding:0 10rpx;
}
wxml完整代码
<view class="cates">
<SearchInput></SearchInput>
<view class="cates_container">
<!-- 左侧菜单 -->
<scroll-view scroll-y class="left_menu">
<view class="menu_list {{index===currentIndex?'active':''}}" wx:for="{{leftMenuList}}" wx:for-item="item1" wx:key="*this">
<view>{{item1}}</view>
</view>
</scroll-view>
<!-- 右侧商品内容 -->
<scroll-view scroll-y class="right_content">
<view class="goods_group"
wx:for="{{rightContent}}"
wx:for-item="item1"
wx:for-index="index1"
wx:key="cat_id"
>
<view class="goods_title">
<text class="delimiter">/</text>
<view class="title">{{item1.cat_name}}</view>
<text class="delimiter">/</text>
</view>
<view class="goods_list">
<navigator
wx:for="{{item1.children}}"
wx:for-item="item2"
wx:for-index="index2"
wx:key="cat_id"
>
<image mode="widthFix" src="{{item2.cat_icon}}"></image>
<view>{{item2.cat_name}}</view>
</navigator>
</view>
</view>
</scroll-view>
</view>
</view>
js中多加了一个
data:{
//实时点击切换
currentIndex:0
}
13 点击实时切换
bindtap 点击事件,相当于绑定了@onclick
**data-index ** 传参 数据就会传到点击事件的e.currentTarget.dataset中
例:data-index="{{index}}"
实现原理 :
- 获取被点击的标题身上的索引
- 给data中的currentIndex赋值就可以了
js代码
// pages/category/index.js
Page({
data: {
//左侧的菜单数据
leftMenuList:[],
//右侧的商品数据
rightContent:[],
//实时点击切换
currentIndex:0
},
Content:[],
onLoad: function (options) {
this.getMenuList();
},
getMenuList(){
wx.request({
url: 'https://api-hmugo-web.itheima.net/api/public/v1/categories',
success:(result)=>{
this.Content=result.data.message
let leftMenuList = this.Content.map(v=>v.cat_name)
let rightContent = this.Content[0].children
this.setData({
leftMenuList,
rightContent
})
}
})
},
handleItemTap(e){
const {index} = e.currentTarget.dataset;
let rightContent = this.Content[index].children;
this.setData({
currentIndex:e.currentTarget.dataset.index,
rightContent
})
}
})
14 缓存技术
- 先判断一下本地存储中有没有旧的数据
- 没有旧数据 直接发送新请求
- 有旧的数据 同时 旧的数据也没有过期 就是用 本地存储中的数据
wx.setStorageSync(“key”,“value”); 设置数据
wx.getStorageSync(“key”); 获取数据
// 获取本地存储中的数据(小程序中也是存在本地存储 技术)
const Cates = wx.getStorageSync("cates");
// 判断 不存在,就发送请求
if(!Cates){
this.getMenuList();
}
getMenuList函数中的success下加入
// 把接口的数据存入到本地存储中
wx.setStorageSync("cates",{time:Date.now(),data:this.Content});
//cates是名称,time是时间戳,
onLoad完整代码
onLoad: function (options) {
// 获取本地存储中的数据(小程序中也是存在本地存储 技术)
const Cates = wx.getStorageSync("cates");
// console.log(Cates);
if(!Cates){
this.getMenuList();
}else{
// 有旧的数据 定义过期时间 5s
if(Date.now()-Cates.time>1000*10){
// 重新发送请求
this.getMenuList();
}else{
this.Content = Cates.data;
let leftMenuList = this.Content.map(v=>v.cat_name)
let rightContent = this.Content[0].children
this.setData({
leftMenuList,
rightContent
})
}
}
}
15 点击菜单,右侧列表置顶,优化
scroll-top 设置竖向滚动条位置
data中设置一个值num,然后在点击事件那里传值num:0,动态传参到前面
scroll-top="{{num}}"
16 商品列表 获取分类id
在navigator的url中传参
url="/pages/goods_list/index.wxml?cid={{item2.cat_id}}"
页面参数在左侧最下面点击看
参数获取:
在跳转页面中的onLoad中options就是cid参数
onLoad: function (options) {
console.log(options);
}
17 实现搜索框与tabs组件
要想把引用的wxml中js的值传入components组建中,就使用名字相同的方法如下:
<Tabs tabs="{{tabs}}" bindtabsItemChange="TabsChange"></Tabs>
<!-- tabsItemChange这个是Tabs.js中定义的方法,前面加上bind就是用来监听页面的,TabsChange是自己起的名字 -->
Tabs.js的接受方法:
/**
* 组件的属性列表
*/
properties: {
tabs:{
type:Array,
value:[]
}
}
引入页面(goods_list的index.js)的js数据
data: {
tabs:[
{
id:0,
value:"综合",
isActive:true
},
{
id:1,
value:"销量",
isActive:false
},
{
id:2,
value:"价格",
isActive:false
}
]
},
// 标题点击事件 从子组件传递过来
TabsChange(e){
//1 获取被点击的标题索引、
const {index} = e.detail;
//2 修改源数组
let {tabs} = this.data;
tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
//3 赋值到data中
this.setData({
tabs
})
}
Tabs.js
methods: {
handleItemTap(e){
const {index} = e.currentTarget.dataset;
//触发父组件中的事件
this.triggerEvent("tabsItemChange",{index})
}
在当前页面想要获取组件中的某一状态,需要使用到
this.triggerEvent(’ ',{},{}) components父组件需要传参,需要用到
第一个参数是自定义事件名称,这个名称是在页面调用组件时bind的名称,第二个对象就可以将想要的属性拿到,第三个参数文档中有介绍,有机会再做补充
第四天(21.03.28)
18 静态商品列表样式
可以让文字显示几行,剩下的变成…样式,css中的内容
.name{
display:-webkit-box;
overflow:hidden;
-webkit-box-orient:vertical;
-webkit-line-clamp:2; // 2就是显示两行
}
如:
卡奇莱德(katald)车载空气净化器除甲醛汽车内用负离子氧吧PM2.5除味器消除异味过滤灰尘吸收TVOC气体-灰色
就会显示为:卡奇莱德(katald)车载空气净化器除甲醛汽车内用负离子氧吧PM2.5除…
在静态商品这里有个小bug,页面在使用组件里的slot中,不能在wxss中使用class样式,只能使用行内样式或标签选择器navigator这种
<SearchInput></SearchInput>
<Tabs tabs="{{tabs}}" bindtabsItemChange="TabsChange">
<block wx:if="{{tabs[0].isActive}}">
<view class="goods_first">
<navigator name="goods_item" style="display:flex;" wx:for="{{5}}">
<!-- 左侧图片 -->
<view class="goods_image" style="flex:2;display:flex;justify-content:center;align-items:center;">
<image mode="widthFix" style="width:70%;" src="http://image1.suning.cn/uimg/b2c/newcatentries/0070134290-000000000149003877_1_800x800.jpg"></image>
</view>
<!-- 右侧内容 -->
<view class="goods_info_wrap" style="flex:3;display:flex;justify-content:space-around;flex-direction:column;">
<view class="name" style="display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:2;">卡奇莱德(katald)车载空气净化器除甲醛汽车内用负离子氧吧PM2.5除味器消除异味过滤灰尘吸收TVOC气体-灰色</view>
<view class="price" style="color:var(--themeColor);font-size:32rpx;">¥3999</view>
</view>
</navigator>
</view>
</block>
<block wx:elif="{{tabs[1].isActive}}">1</block>
<block wx:elif="{{tabs[2].isActive}}">2</block>
</Tabs>
19 动态渲染
goods_list 中 index.js
// pages/goods_list/index.js
Page({
data: {
goodsList:{}
},
QueryParams:{
query:"",
cid:"",
pagenum:1,
pagesize:10
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.QueryParams.cid = options.cid
this.getGoodsList();
},
getGoodsList(){
const that = this;
// console.log(this.QueryParams.cid);
wx.request({
url:`https://api-hmugo-web.itheima.net/api/public/v1/goods/search?cid=${that.QueryParams.cid}&pagenum=${that.QueryParams.pagenum}&pagesize=${that.QueryParams.pagesize}&query=${that.QueryParams.query}`,
success:(result)=>{
console.log(result);
this.setData({
goodsList:result.data.message.goods
})
}
})
}
})
注:get传值时,自己加完参数别忘了前面加它自己本身pagenum=${that.QueryParams.pagenum}
index.wxml
注意的点只有一个,就是图片没有的时候,用三元运算符,把没有图片的数据加上一个默认图片,其他的直接个数据就好
src="{{item.goods_small_logo?item.goods_small_logo:'https://ww1.sinaimg.cn/large/007rAy9hgy1g24by9t530j30i20i2glm.jpg'}}"
20 加载下一页
-
用户上滑页面 滚动条触底 开始加载下一页
-
找到滚动条触底事件
-
判断还有没有下一页数据
-
获取到总页数 只有总条数
总页数 = Math.ceil(总条数 / 页容量 pagesize)
总页数 = Math.ceil(23 / 10) = 3
-
获取当前的页码
-
判断一下 当前的页码是否大于等于 总页数
-
-
假如没有下一页数据,弹出一个提示
-
假如还有下一页数据 加载下一页
- 当前的页码 ++
- 重新发送请求
- 数据请求回来 要对data中的数组 进行 拼接 而不是全部替换!!!
-
onReachBottom 监听用户上拉触底事件
在page中定义一个全局参数
toTalPages:1,
在请求的success中,写入
const total = result.data.message.total;
that.toTalPages = Math.ceil(total/that.QueryParams.pagesize)
console.log(that.toTalPages); // 3
this.setData({
goodsList:[...this.data.goodsList,...result.data.message.goods]
// 使用解构赋值方法,否则数据会覆盖
})
onReachBottom()
// 下拉事件
onReachBottom(){
// console.log(132);
if(this.QueryParams.pagenum>=this.toTalPages){
// 没有下一页数据了
wx.showToast({
title: '没有数据了',
})
}else{
this.QueryParams.pagenum++;
this.getGoodsList();
}
},
21 下拉刷新
- 下拉刷新页面
- 触发下拉刷新事件 需要在页面的json文件中开启一个配置项 enablePullDownRefresh,backgroundTextStyle
- 找到 触发下拉刷新的事件 onPullDownRefresh
- 重置 数据 数组
- 重置页码 设置为1
- 重新发送请求
- 数据请求回来 需要手动的关闭 等待效果 wx.stopPullDownRefresh(),设置在监听用户下拉动作中
- 触发下拉刷新事件 需要在页面的json文件中开启一个配置项 enablePullDownRefresh,backgroundTextStyle
json中
enablePullDownRefresh Boolean false 是否全局开启下拉刷新
backgroundTextStyle String dark 下拉loading的样式,仅支持dark/light
js中
onPullDownRefresh function 监听用户下拉动作
js中的某个方法中
wx.stopPullDownRefresh()
onPullDownRefresh(){
// console.log(11);
// 重置数组
this.setData({
goodsList:[]
})
//设置页码为1
this.QueryParams.pagenum=1;
//重新请求数据
this.getGoodsList();
//关闭下拉
wx.stopPullDownRefresh();
}
})
22 全局加载图标
wx.showLoading() 显示加载中的效果
wx.showLoading({
title:"加载中",
mask:true //在加载中的时候,无法点击其他标签
})
wx.hideLoading() 关闭加载中的效果
23 商品详情
先修改名称
json中"navigationBarTitleText":“商品详情”
在跳转的页面中url="/pages/goods_list/index?goods_id={{item.goods_id}}"
detail获取数据
Page({
data: {
goodsObj:{}
},
goods_id:{},
onLoad: function (options) {
const {goods_id} = options;
this.goods_id = goods_id
this.getGoodsDetail();
},
getGoodsDetail(){
wx.showLoading({
title: '加载中',
mark:true
})
wx.request({
url:"https://api-hmugo-web.itheima.net/api/public/v1/goods/detail?goods_id="+this.goods_id,
success:(result)=>{
this.setData({
goodsObj:result.data.message
})
console.log(result);
}
})
wx.hideLoading();
}
})
24 轮播图渲染
wxml
<view class="detail_swiper">
<swiper indicator-dots autoplay circular>
<swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id">
<image mode="widthFix" src="{{item.pics_mid}}"></image>
</swiper-item>
</swiper>
</view>
wxss
.detail_swiper swiper{
height:65vw; //vw vh
text-align:center;
}
.detail_swiper swiper image{
width:60%;
}