目录
1.7注册goods-card和goods-list全局组件
Ⅰ.项目介绍
1.1项目概述
慕尚花坊是⼀款同城鲜花订购 的小程序,项目常用功能模块分为项目首页、商品分类、商品列表、商品详情、用户管理、收货地址、购物车、结算支付和订单管理等等。
1.2项目技术栈
小程序内置组件:采用小程序内置组件,结合 Vant 组件库实现⻚⾯结构的搭建。
项⽬中使⽤了 css 拓展语言 Scss 绘制页面的结构。
小程序内置API:交互、支付、文件上传、地图定位、网络请求、预览图片、本地存储等。
小程序分包加载:降低⼩程序的启动时间、包的体积,提升⽤户体验度。
小程序组件开发:将页面内的功能模块抽象成⾃定义组件,实现代码的复⽤。
网络请求封装:request 方法封装、快捷⽅式封装、响应拦截器、请求拦截器。
骨架屏组件:利⽤开发者⼯具提供了⾃动⽣成⻣架屏代码的能力,提⾼了整体使用体验和用户满意 度。
UI 组件库:使用 Vant 组件库实现小程序 结构的绘制。
LBS :使⽤腾讯地图服务进行 LBS逆地址解析,实现选择收货地址功能。
miniprogram-licia :使用 licia 进行函数的防抖节流。
async-validator :使用async-validator 实现表单验证。
miniprogram-computed : 使用 miniprogram-computed 进行计算属性功能。
mobx-miniprogram :使用 mobx-miniprogram 进行项目状态的管理。
Ⅱ.项目初始化
1.1项目创建
1.2项目目录
1.3自定义构建
⾸先在project.config.json 配置 miniprogramRoot 选项,指定⼩程序源码的⽬录。
然后配置 project.config.json 的 setting.packNpmManually 为 true。
初始化项目,在内建终端打开
packageJsonPath 表示 node_modules 源对应的 package.json
miniprogramNpmDistDir 表示 node_modules 的构建结果⽬标位置
安装 vant ,然后进⾏ npm 构建,测试是否能够正常 vant 构建成功。
1.4 scss集成
在 project.config.json ⽂件中,修改 setting 下的 useCompilerPlugins 字段为 scss,即可开 启⼯具内置的 scss 编译插件。
Ⅲ.构建项目界面
1.1项目整体框架
assets⽂件导⼊ 配置app.json⽂件
{
"pages": [
"pages/category/category",
"pages/index/index",
"pages/cart/cart",
"pages/my/my"
],
"window": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "幕尚花坊",
"navigationBarBackgroundColor": "#FF734C"
},
"tabBar": {
"color": "#252933",
"selectedColor": "#FF734C",
"backgroundColor": "#ffffff",
"borderStyle":"black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "assets/tabbar/index.png",
"selectedIconPath": "assets/tabbar/index-active.png"
},
{
"pagePath": "pages/category/category",
"text": "分类",
"iconPath": "assets/tabbar/cate.png",
"selectedIconPath": "assets/tabbar/cart-active.png"
},
{
"pagePath": "pages/cart/cart",
"text": "购物车",
"iconPath": "assets/tabbar/cart.png",
"selectedIconPath": "assets/tabbar/cate-active.png"
},
{
"pagePath": "pages/my/my",
"text": "我的",
"iconPath": "assets/tabbar/index.png",
"selectedIconPath": "assets/tabbar/my-active.png"
}
]
},
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents",
"usingComponents": {
"van-button": "@vant/weapp/button/index",
"van-card": "@vant/weapp/card/index",
"van-submit-bar": "@vant/weapp/submit-bar/index"
}
}
1.2样式图
Ⅳ.首页
1.1首页结构
在index.wxml构建首页结构
<view class="index-container">
<!-- 首页背景图 -->
<view class="window-bgc"></view>
<!-- 页面主体部分 -->
<view class="container">
<!-- 轮播图区域 -->
<banner />
<!-- 导航区域 -->
<entrance />
<!-- 广告区域 -->
<view class="adver">
<view class="adver-left">
<navigator url="">
<image src="../../assets/images/love.jpg" mode="widthFix" />
</navigator>
</view>
<view class="adver-right">
<view>
<navigator url="">
<image src="../../assets/images/elder.jpg" mode="widthFix" />
</navigator>
</view>
<view>
<navigator url="">
<image src="../../assets/images/friend.jpg" mode="widthFix" />
</navigator>
</view>
</view>
</view>
<!-- 商品列表 -->
<goods-list title="人气推荐"/>
<goods-list title="猜我喜欢"/>
<goods-card/>
</view>
</view>
1.1.1navigator
navigator是一个全局对象,它提供了与浏览器相关的信息和操作接口。在前端开发中,我们通常会使用 navigator 对象来获取用户浏览器的相关信息。
navigator 对象的常见属性和方法包括:
navigator.userAgent: 返回当前浏览器的用户代理字符串。
navigator.appName: 返回当前浏览器的名称。
navigator.appVersion: 返回当前浏览器的版本号。
navigator.language: 返回当前浏览器的语言设置。
navigator.platform: 返回当前浏览器所在设备的操作系统平台。
navigator.geolocation: 提供了一组 API,用于获取当前设备的地理位置信息。
navigator.mediaDevices: 提供了一组 API,用于访问当前设备的音频、视频、屏幕等媒体设备。
navigator.serviceWorker: 提供了一组 API,用于在浏览器中注册和管理 Service Worker,实现离线缓存和推送通知等功能
1.2首页背景图
在index.sass中构建首页样式
.index-container{
//首页背景图
.window-bgc{
height: 200rpx;
position:absolute;
width:100%;
background-color: #f3514f;
border-radius:0rpx 0rpx 40% 40%;
}
.adver {
display: flex;
margin:0 auto;
width: 96%;
padding: 18rpx;
box-sizing: border-box;
background-color:rgb(177, 54, 54);
border-radius: 18rpx;
.adver-left{
width: 50%;
padding: 8rpx 8rpx 0rpx 8rpx;
}
.adver-right{
width: 50%;
padding: 8rpx 8rpx 0rpx 6rpx;
view:laat-child{
padding-top: 10rpx;
}
}
image{
width: 100%;
}
}
}
1.2.1 flex布局
flex-direction属性
flex-direction属性用于设置主轴方向,通过设置主轴方向可以规定项目的排列方向。
row:默认值,主轴为从左到右的水平方向。
row-reverse:主轴为从右到左的水平方向。
column:主轴为从上到下的垂直方向。
column-reverse:主轴为从下到上的垂直方向。
justify-content属性
justify-content属性用于设置项目在主轴方向上的对齐方式。能够分配项目之间及其周围 多余的空间。
flex-start:默认值,表示项目对齐到主轴起点,项目间不留空隙。
flex-end:项目对齐到主轴终点,项目间不留空隙。
center:项目在主轴上居中排列,项目间不留空隙。
space-between:两端对齐,两端的项目分别靠向容器的两端,其他项目之间的间隔相等 space-around:每个项目之间的距离相等
align-items属性align-items属性用于设置项目在交叉轴上的对齐方式。
center:项目在交叉轴的中间位置对齐。
flex-start:项目顶部与交叉轴起点对齐,flex-end:项目底部与交叉轴终点对齐。
baseline:项目的第一行文字的基线对齐。
1.3 banner组件
1.3.1构建banner组件结构
banner.js
Properties
(1)Properties类是专门用于读写配置文件的集合类
(2)配置文件的后缀名为.properties
(3)Properties类的方法可查找api文件
banner.json
1.4轮播图组件
在banner.wxml中通过swiper组件建立一个自动轮播列表
使用wx:for循环遍历bannerList数组
bannerList.length为数组长度
<view class="swiperbox">
<swiper autoplay class="swiper" indicator-active-color="#FF734C" interval="2000" duration="1000" indicator-color="rgba(0,0,0,3)">
<block wx:for="{{ bannerList }}" wx:key="index">
<swiper-item class="swiper-item">
<image class="img" src="{{item}}"></image>
</swiper-item>
</block>
</swiper>
<view class="indicator">
<text wx:for="{{bannerList.length}}" wx:key="id"
class="rectangle"></text>
</view>
</view>
设置swiperbox样式
.swiperbox{
position: relative;
.swiper{
height: 320rpx;
//设置圆角弧度
border-radius: 18rpx;
//设置溢出隐藏
overflow: hidden;
width: 95%;
//margin设置外边距
margin: 0 auto;
}
.swiper-item{
.img{
width: 100%;
height: 100%;
border-radius: 18rpx;
}
}
.indicator{
display: flex;
justify-content: center;
position: absolute;
bottom: 16rpx;
left: 0rpx;
right: 0rpx;
.rectangle{
width: 30rpx;
height: 6rpx;
background-color: #f3514f;
margin: 0 8rpx;
border-radius: 6rpx;
}
}
}
样式图
1.5entrance导航组件
在entrance.wxml中渲染一个导航列表
<view class="nav-list">
<view wx:for="{{10}}" wx:key="index" class="nav-item">
<navigator url="" class="navigator-nav">
<image src="../../../assets/images/cate-1.png" mode="" class="nav-img"/>
<text class="nav-text">鲜花玫瑰</text>
</navigator>
</view>
</view>
导航分类样式
.nav-list {
//设置弹性布局
display: flex;
//设置换行
flex-wrap: wrap;
margin: 20rpx;
border-radius: 18rpx;
padding: 10px 0px 10px 10px;
background-color: white;
}
.nav-item {
.navigator-nav {
//更改主轴方向
//由默认的横向排列更改为纵向排列
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-right: 10px;
margin-top: 10px;
.nav-text {
margin-top: 4px;
font-size: 12px;
}
.nav-img {
width: 66rpx;
height: 66rpx;
}
}
}
1.6完成广告区域
广告区域结构
<!-- 广告区域 -->
<view class="adver">
<view class="adver-left">
<navigator url="">
<image src="../../assets/images/love.jpg" mode="widthFix" />
</navigator>
</view>
<view class="adver-right">
<view>
<navigator url="">
<image src="../../assets/images/elder.jpg" mode="widthFix" />
</navigator>
</view>
<view>
<navigator url="">
<image src="../../assets/images/friend.jpg" mode="widthFix" />
</navigator>
</view>
</view>
</view>
广告区域样式
.adver {
display: flex;
margin:0 auto;
width: 96%;
padding: 18rpx;
box-sizing: border-box;
background-color:rgb(177, 54, 54);
border-radius: 18rpx;
.adver-left{
width: 50%;
padding: 8rpx 8rpx 0rpx 8rpx;
}
.adver-right{
width: 50%;
padding: 8rpx 8rpx 0rpx 6rpx;
view:laat-child{
padding-top: 10rpx;
}
}
样式图:
1.7注册goods-card和goods-list全局组件
在index.wxml设置两个标题
1.7.1完成goods-card组件
在goods-card.wxml中构建结构
<view class="goods_cart_container">
<navigator url="" class="navigator-nav">
<image src="../../assets/images/floor.jpg" mode="widthFix" class="good_img" />
<!-- 详细信息-->
<view class="goods_item_info">
<!-- 商品名称-->
<text class="goods_item_info_name">亲爱的/情人节网红款/19枝</text>
<!-- 商品描述-->
<text class="goods_item_info_promo">情人节新品情人节新品情人节新品</text>
<!-- 商品价钱-->
<view class="goods_item_info_bottom">
<!-- 优惠价钱 -->
<view class="goods_item_info_price">
<text class="text">$</text>99
</view>
<!-- 原价 -->
<view class="goods_item_info_origin_price">
<text class="text">$</text>199
</view>
<!-- 购物车 -->
<view class="goods_item_info_btn">
<image class="goods_image" src="../../assets/images/buybtn.png" mode="" />
</view>
</view>
</view>
</navigator>
</view>
在goods-card.scss中构建样式
.goods_cart_container{
width: 350rpx;
margin-top: 18rpx;
background: #fff;
border-radius: 18rpx;
}
.good_img{
width: 100%;
max-height: 360rpx;
border-top-left-radius: 18rpx;
border-top-right-radius: 18rpx ;
}
.goods_item_info{
//设置弹性布局
display: flex;
//更改主轴方向为纵轴
flex-direction: column;
padding: 10rpx 20rpx;
}
.goods_item_info .goods_item_info_name{
//设置字体粗细
font-weight: 600;
font-size: 30rpx;
line-height: 20px;
//溢出隐藏
overflow: hidden;
//超过一行就算溢出
white-space: nowrap;
//溢出之后的文本为省略号
text-overflow: ellipsis;
}
.goods_item_info .goods_item_info_promo{
padding-top: 20rpx;
padding-bottom: 3px;
font-size: 12px;
color: #71797f;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.goods_item_info_bottom{
//弹性布局 在同一行显示
display: flex;
line-height: 50rpx;
margin-top: 20rpx;
}
.goods_item_info_bottom .goods_image{
width: 48rpx;
height: 48rpx;
}
.goods_item_info_price{
font-size: 30rpx;
font-weight: bold;
color: #f3514f;
}
.goods_item_info_price .text{
font-size: 24rpx;
padding-right: 4rpx;
font-weight: normal;
}
.goods_item_info_origin_price{
//设置flex为1 则该元素拥有所有剩余部分
flex:1;
font-size: 20rpx;
color: #71797f;
text-decoration-line:line-through;
margin-left: 6%;
margin-top: 4rpx;
}
.goods_item_info_origin_price .text{
font-size: 20rpx;
}
1.7.2完成goods-list组件
在goods-list.wxml中构建结构
<!-- 商品列表组件-->
<view class="goods_container">
<!-- 标题-->
<view class="goods_title">{{ title }}</view>
<!-- 列表区域-->
<view class="goods_card_list">
<block wx:for="{{ 3 }}" wx:key="index">
<goods-card />
</block>
</view>
</view>
<!-- 查看更多-->
<view class="goods_more">
<navigator url="" class="goods_more_btn">查看更多</navigator>
</view>
在goods-list.scss中构建样式
.goods_title{
//设置文本居中
text-align: center;
font-size: 40rpx;
line-height: 52rpx;
font-weight: bold;
color: #232628;
padding: 20rpx 0 0rpx 0rpx;
}
.goods_card_list{
display: flex;
//设置换行
flex-wrap: wrap;
//设置元素在主轴上的排列方式
justify-content: space-between;
}
.goods_card_list::after{
content:'' ;
width: 350rpx;
}
.goods_more{
margin: 10rpx 0;
}
.goods_more_btn{
width: 95%;
display: block;
margin: 0 auto;
background: rgb(233, 94, 94);
margin: 0 auto;
border-radius: 20rpx;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 14px;
color: rgba(35,38,40,0.7);
}
样式图
Ⅴ.分类
1.1分类结构
<view>
<view class="category-container">
<scroll-view class="category-left-view" scroll-y>
<view class="left-view-item active">爱礼精选</view>
<view class="left-view-item ">鲜花玫瑰</view>
<view class="left-view-item ">永生玫瑰</view>
<view class="left-view-item ">玫瑰珠宝</view>
</scroll-view>
<scroll-view class="category-right-view" scroll-y>
<view class="test">
<view wx:for="{{ 10 }}" wx:key="index" class="right-view-item">
<navigator class="navigator" url="">
<image class="" src="../../assets/images/cate-1.png" mode="" />
<text class="goods_item_name">真情告白</text>
</navigator>
</view>
</view>
</scroll-view>
</view>
</view>
1.2分类样式
.category-container {
display: flex;
.category-left-view {
width: 220rpx;
height: 100vh;
background: #fff !important;
.left-view-item {
line-height: 99rpx;
//文本排列方式
text-align: center;
font-size: 26rpx;
}
.active {
background-color: #ffffff;
position: relative;
color: #f3514f;
//&表示当前标签
//::before是伪元素选择器
//在指定元素的添加内容
&::before {
content: '';
display: block;
width: 6rpx;
height: 66rpx;
background-color: #f3514f;
position: absolute;
left: 0;
top: 50%;
//沿着y轴平移
transform: translateY(-50%);
}
}
}
}
.category-right-view{
width: 100%;
height: 100vh;
flex-wrap: wrap;
background: #fff !important;
margin-left: 8rpx;
.right-view-item{
width: 33%;
float: left;
margin-top: 30rpx;
.navigator{
display: flex;
flex-direction: column;
align-items: center;
}
image{
width: 90rpx;
height: 90rpx;
}
text{
font-size: 26rpx;
margin-top: 18rpx;
}
&::before{
content: '';
display: block;
width: 6rpx;
height: 100vh;
background-color: rgb(177, 174, 174);
position: absolute;
left: 0;
top: 0%;
transform: translateY();
}
}
}
1.2.1伪元素选择器
所谓“伪元素” 就是在dom结构本来是不存在的 但是通过css创建出来的元素
::before ::after
用于向指定元素的前面或者后面加入特定的内容
样式图
Ⅵ.购物车
1.1购物车结构
<view class="container">
<!-- 购物车列表区域 -->
<view class="carList-container" wx:if="{{carList.length}}">
<view class="carList-container-cell" wx:for="{{carList}}" wx:key="index">
<van-swipe-cell right-width="{{ 65 }}" left-width="{{ 65 }}">
<view slot="left" class="van-swipe-cell__left">选择</view>
<van-cell-group>
<view class="goods-info">
<view class="left">
<van-checkbox value="{{ false }}" checked-color="#e60017" bind:change="onChange">
</van-checkbox>
</view>
<view class="mid">
<image src="../../assets/images/floor-img.jpg" mode="" />
</view>
<view class="right">
<view class="title">【11枝红玫瑰】买玫瑰送老婆</view>
<view class="buy">
<view class="price">¥99.00</view>
<view class="buy-btn">
<van-stepper value="{{ 1 }}" bind:change="onChange" />
</view>
</view>
</view>
</view>
</van-cell-group>
<view slot="right" class="van-swipe-cell__right">删除</view>
</van-swipe-cell>
</view>
</view>
<!-- 购物车列表为空的情况 -->
<van-empty description="还没有商品,快去添加吧~" wx:else>
<navigator url="">
<van-button round type="danger">去购物</van-button>
</navigator>
<navigator url="">
<van-button round type="danger">去登录</van-button>
</navigator>
</van-empty>
<!-- 提交订单栏区域 -->
<van-submit-bar price="{{ 3050 }}" button-text="提交订单" bind:submit="onClickButton" tip="{{ true }}">
<van-checkbox value="{{ true }}" checked-color="#e60017" bind:change="onChange">
全选
</van-checkbox>
</van-submit-bar>
</view>
1.1.1 wx:for嵌套
wx:for 是用来做列表渲染,在组件上使用wx:for绑定一个数组,数组的下标变量名默认为index,数组当前项的变量名默认为item.
1.1.2 wx:key遍历数组
wx:key 提升性能。
wx:key 属性值有两种添加属性。
1. 字符串,需要是遍历的数组中 item 的某个属性,要求该属性是列表中唯一的字符串或者数字,不能进行动态改变。
2. 保留关键字 *this ,*this代表的是 item 本身,item 本身是唯一的字符串或者数字
1.2购物车样式
.container {
background-color: whitesmoke;
height: 100vh;
}
.carList-container {
.carList-container-cell {
.goods-info {
display: flex;
background-color: white;
border-radius: 16rpx;
margin: 20rpx 20rpx 5rpx 20rpx;
padding: 24rpx 16rpx;
.left {
display: flex;
align-items: center;
}
.mid {
width: 200rpx;
height: 230rpx;
image {
width: 100%;
height: 100%;
}
}
.right {
display: flex;
flex-direction: column;
height: 230rpx;
justify-content: space-between;
padding-left: 20rpx;
.title {
font-size: 26rpx;
}
.buy {
display: flex;
justify-content: space-between;
.price {
font-size: 30rpx;
color: #fa4126;
}
}
}
}
}
}
.van-empty__bottom {
height: 250rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
1.2.1 margin和padding的使用(内外边距)
外边距(margin):
外边距定义了元素与其周围元素之间的空白区域。
外边距可以设置为正值、负值或百分比。
外边距可以用来控制元素之间的间距、对齐元素、扩展元素的可点击区域等。
外边距不会影响元素的背景颜色或边框。
内边距(padding):
内边距定义了元素的内容与其边框之间的空白区域。
内边距可以设置为正值、负值或百分比。
内边距可以用来控制元素内容与边框之间的间距、增加元素的可点击区域等。
内边距会影响元素的背景颜色。
在CSS中,可以使用以下属性来控制外边距和内边距:
外边距属性:
margin-top:顶部外边距
margin-right:右侧外边距
margin-bottom:底部外边距
margin-left:左侧外边距
内边距属性:
padding-top:顶部内边距
padding-right:右侧内边距
padding-bottom:底部内边距
padding-left:左侧内边距
这些属性可以接受不同的值,例如像素(px)、百分比(%)、em等
1.2.2 justify-content
justify-content 属性:设置主轴的对齐方式,弹性子元素在主轴方向上的对齐方式,
justify-content: flex-start; 默认值,主轴顶端对齐
justify-content: flex-end; 主轴的末端对齐
justify-content: center; 居中对齐,子元素位于弹性容器的中心
justify-content: space-between; 两端对齐,子元素和子元素之间有空白空间,项目之间的间隔都相等。
justify-content: space-around; 子元素之前、之间、之后都留有空白空间,且空间自行分配,项目之间的间隔比项目与边框的间隔大一倍。
space-evenly:弹性项目平均分布在该行上,相邻项目的间隔,项目与容器之间空间相等
1.3效果图
Ⅶ.我的
1.1我的界面解构
<!--pages/info/info.wxml-->
<view class="container">
<!-- 顶部展示图 -->
<view class="top-show">
<image
mode="widthFix"
class="top-show-img"
src="/assets/images/banner.jpg"
></image>
</view>
<view class="bottom-show">
<!-- 未登录面板 -->
<view class="user-container section" bindtap="toLoginPage">
<view class="avatar-container">
<image src="/assets/images/avatar.png"></image>
<view class="no-login">
<text class="ellipsis">未登录</text>
<text>点击授权登录</text>
</view>
</view>
</view>
<!-- 登录以后得面板 -->
<!-- <view class="user-container section">
<view class="avatar-container">
<image src="/assets/images/avatar.png"></image>
<view class="no-login">
<text class="ellipsis">用户昵称</text>
</view>
</view>
<view class="setting">
<navigator url="/pages/settings/settings"> 设置 </navigator>
</view>
</view> -->
<!-- 订单面板 -->
<view class="order section">
<view class="order-title-wrap">
<text class="title">我的订单</text>
<text class="more">查看更多></text>
</view>
<view class="order-content-wrap">
<view class="order-content-item" wx:for="{{ initpanel }}">
<navigator url="{{ item.url }}">
<view class="iconfont {{ item.iconfont }}"></view>
<text>{{ item.title }}</text>
</navigator>
</view>
</view>
</view>
<!-- 关于售前售后服务面板 -->
<view class="after-scale section">
<view class="order-title-wrap">
<text class="title">关于售前售后服务</text>
</view>
<view class="after-scale-item">
<view class="iconfont icon-kefufenxiermaikefu"></view>
<text>可与小程序客服实时聊天或电话咨询</text>
</view>
<view class="after-scale-item">
<view class="iconfont icon-shijian"></view>
<text>小程序客服工作时间为: 8:30 ~ 20:30</text>
</view>
<view class="after-scale-item">
<view class="iconfont icon-dizhiguanli"></view>
<text>鲜花制作完毕情况下暂不支持退款</text>
</view>
<view class="after-scale-item">
<view class="iconfont icon-zhangben"></view>
<text>鲜花可以提前7-15天预订重大节假日不支持定时配送</text>
</view>
</view>
<!-- 底部面板 -->
<view class="info-footer"> 智谷星图技术支持 </view>
</view>
</view>
1.1.1bindtap 和 catchtap 的区别
事件冒泡:bindtap会将事件传递给父节点进行处理,而catchtap会阻止事件继续冒泡到父节点。换句话说,当一个元素上的bindtap事件被触发时,如果该元素的父节点也有相同类型的bindtap事件,父节点的事件处理函数也会被执行;而catchtap则只会触发当前元素的事件处理函数。
绑定顺序:多个元素同时绑定了bindtap和catchtap事件时,它们的触发顺序是不同的。bindtap的触发顺序是由子元素向父元素冒泡的顺序(即从内到外);而catchtap的触发顺序是由父元素向子元素捕获的顺序(即从外到内)。
阻止默认行为:对于某些具有默认行为的元素(如<form>、<input type="submit">等),bindtap可以通过返回false来阻止默认行为的触发;而catchtap无法阻止这些默认行为。
用途:在一般情况下,推荐使用bindtap来进行事件绑定,因为它可以与父元素的事件一起工作,并且在处理冒泡事件时更加灵活。只有在确实需要阻止事件冒泡或不想触发父元素的事件处理函数时,才使用catchtap。
1.2我的界面样式
.container {
padding: 0rpx !important;
}
.top-show {
width: 100%;
height: 360rpx;
.top-show-img {
width: 100%;
height: 100%;
}
}
.bottom-show {
margin: 0 16rpx;
.section {
background-color: #fff;
border-radius: 20rpx;
padding: 20rpx;
}
.user-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: -86rpx;
color: #999;
.avatar-container {
display: flex;
align-items: center;
image {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.no-login {
display: flex;
flex-direction: column;
font-size: 24rpx;
text:first-child {
font-size: 28rpx;
}
.ellipsis {
width: 400rpx;
overflow: hidden;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
}
.order {
background-color: #fff;
margin-top: 20rpx;
.order-title-wrap,
.order-content-wrap {
padding: 20rpx;
display: flex;
justify-content: space-between;
}
.order-title-wrap {
.title {
color: #444;
// font-weight: 700;
}
.more {
color: #ccc;
font-size: 24rpx;
}
}
.order-content-wrap {
display: flex;
.iconfont {
font-size: 60rpx;
text-align: center;
}
text {
font-size: 25rpx;
margin-top: 20rpx;
}
}
.order-content-item {
display: flex;
flex-direction: column;
align-items: center;
}
}
.after-scale {
margin-top: 30rpx;
.order-title-wrap {
line-height: 50rpx;
}
.after-scale-item {
display: flex;
margin: 25rpx 15rpx;
color: #999;
line-height: 50rpx;
text {
font-size: 25rpx;
margin-left: 20rpx;
}
.iconfont {
color: #a2b364;
}
}
}
.info-footer {
height: 100rpx;
line-height: 100rpx;
text-align: center;
color: #aaa;
font-size: 25rpx;
}
}
1.2.1 overflow:hidden
<div class="container">
<div class="div1"></div>
<div class="div2"></div>
</div>
.container{
background-color: black;
}
.div1{
background-color: aqua;
width: 100px;
height: 200px;
}
.div2{
background-color: red;
width: 100px;
height: 100px;
}
效果图
使用overflow:hideen隐藏溢出
当父元素拥有固定高度时,比如height:50px,我们可以使用overflow:hideen来隐藏溢出。
使用overflow:hidden清除浮动
当我们为div1和div2加上float:left
后,由于浮动的元素脱离了文档流,不浮动的元素会忽略浮动元素,此时父标签 height:auto,因此,界面显示
1.3我的效果图
Ⅷ.商品细节界面
1.1界面结构
<view class="container goods-detail">
<!-- 商品大图 -->
<view class="banner-img">
<image class="img" src="/assets/images/floor-img.jpg" />
</view>
<!-- 商品的基本信息 -->
<view class="content">
<view class="price">
<view class="price-num">¥299</view>
<view class="price-origin-num">¥399</view>
</view>
<view class="title">亲爱的/情人节网红款/19枝亲爱的/情人节网红款</view>
<view class="desc">用最温暖的最有情的心意,用最温暖的最有情的心意</view>
</view>
<!-- 商品的详细信息 -->
<view class="detail">
<image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
<image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
<image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
</view>
<!-- 商品的底部商品导航 -->
<van-goods-action>
<navigator url="/pages/index/index" open-type="switchTab">
<van-goods-action-icon icon="wap-home-o" text="首页" />
</navigator>
<navigator url="/pages/cart/cart" open-type="switchTab">
<van-goods-action-icon icon="cart-o" text="购物车" info="{{ allCount }}" />
</navigator>
<van-goods-action-icon
open-type="contact"
icon="chat-o"
text="客服"
bind:click="onClickIcon"
/>
<van-goods-action-button text="加入购物车" type="warning" bindtap="handleAddcart" />
<van-goods-action-button text="立即购买" bindtap="handeGotoBuy" />
</van-goods-action>
<!-- 加入购物车、立即购买弹框 -->
<!-- show 控制弹框的隐藏和展示 -->
<!-- bind:close 点击关闭弹框时触发的回调 -->
<van-action-sheet show="{{ show }}" sh>
<view class="sheet-wrapper">
<view class="goods-item">
<!-- 需要购买的商品图片 -->
<view class="mid">
<image class="img" src="/assets/images/floor-img.jpg" />
</view>
<!-- 商品基本信息 -->
<view class="right">
<!-- 商品名字 -->
<view class="title"> 亲爱的/情人节网红款/19枝 </view>
<!-- 商品价格 -->
<view class="buy">
<view class="price">
<view class="symbol">¥</view>
<view class="num">100</view>
</view>
<!-- 步进器组件控制购买数量 -->
<view class="buy-btn">
<!-- Stepper 步进器,由增加按钮、减少按钮和输入框组成,控制购买数量 -->
<van-stepper value="{{ count }}" bind:change="onChangeGoodsCount" />
</view>
</view>
</view>
</view>
<!-- 祝福语输入框 -->
<view class="time-wraper">
<view class="title">祝福语</view>
<textarea
model:value="{{ blessing }}"
bindinput="onTextAreaChange"
class="form-textarea"
placeholder="必填,写上您的祝福语,给心爱的他(她)送上你的祝福(请勿填写特殊符号或表情符号)"
name="textarea"
/>
</view>
<!-- 确定按钮 -->
<view class="sheet-footer-btn">
<van-button block type="primary" round> 确定 </van-button>
</view>
</view>
</van-action-sheet>
</view>
1.1.1步进器
微信小程序步进器(stepper)是一个自定义组件,其代码相对简单,适合新手学习使用。步进器常用于购物车等需要增减数量的场景,也用于一些旅游项目中增减房间数和人数等。从开发的角度来看,步进器需要适应多种场景和控制一些状态,如最小值、最大值、每次增加或减少的值、是否禁用以及组件的索引值等。
此外,微信小程序步进器是微信小程序开发中的一个重要概念,开发者可以通过使用步进器组件,方便地实现用户输入数量的增加或减少的功能,提升了用户的使用体验。
1.2界面样式
/* pages/goods/detail/index.wxss */
.container {
padding: 0rpx !important;
}
.goods-detail {
margin-bottom: 100px;
}
// 商品大图
.banner-img {
height: 800rpx;
image {
height: 100%;
}
}
// 商品的基本信息
.content {
margin: 0 16rpx;
background: white;
padding: 40rpx;
position: relative;
border-radius: 18rpx;
top: -80px;
height: 170rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
overflow: hidden;
.price {
display: flex;
.price-num {
font-size: 18px;
color: #fa4126;
font-weight: bold;
}
.price-origin-num {
font-size: 12px;
color: #b4babf;
margin-left: 4px;
text-decoration: line-through;
margin-top: 6px;
}
}
.title {
font-size: 16px;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc {
font-size: 12px;
color: #999999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
// 详细图片
.detail {
margin: -130rpx 16rpx 100rpx;
background: white;
padding: 20rpx 16rpx;
border-radius: 16rpx;
}
// 加入购物车、立即购买弹框
.sheet-wrapper {
padding: 16px;
.sheet-footer-btn {
padding: 16px;
}
}
// 商品详情
.goods-item {
display: flex;
align-items: center;
padding: 0 32rpx 40rpx 0;
.left {
width: 56px;
display: flex;
align-items: center;
justify-content: center;
}
.mid {
width: 114px;
height: 125px;
image {
height: 100%;
}
}
.right {
height: 125px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 10px;
.title {
flex: 1;
flex-shrink: 0;
font-size: 28rpx;
color: #333;
line-height: 40rpx;
font-weight: 400;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
word-break: break-word;
}
.buy {
display: flex;
justify-content: space-between;
.price {
display: flex;
/* align-items: flex-end; */
color: #fa4126;
font-size: 36rpx;
.symbol {
font-size: 10px;
margin-right: 2px;
margin-top: 8px;
}
}
}
}
}
// 祝福语
.time-wraper {
margin-bottom: 12px;
.title,
.time {
justify-content: space-between;
font-size: 14px;
color: #333333;
}
.form-textarea {
border-radius: 12px;
background-color: #f7f8fa;
padding: 16px 12px;
font-size: 13px;
margin-top: 12px;
width: 94%;
height: 84px;
}
}
1.2.1定位position
CSS 中的position属性用来设置元素在页面中的位置,通过该属性您可以把任何属性放置在任何您认为合适的位置。position 属性有 5 个可选值,分别对应 5 种不同的定位方式,如下所示
1.2.2 white-space
white-space属性值
normal:忽略多余的空白,只保留一个空白(默认);
pre:保留空白(行为方式类似于html中的pre标签);
nowrap:只保留一个空白,文本不会换行,会在在同一行上继续,直到遇到br标签为止。
pre-wrap:保留空白符序列,正常地进行换行;
pre-line:合并空白符序列,保留换行符;
inherit:从父元素继承white-space属性的值。
1.2.3 word-break
word-break 属性规定自动换行的处理方法。
提示:通过使用 word-break 属性,可以让浏览器实现在任意位置的换行。
1.3效果图
Ⅸ.订单页面
1.1订单结构
<!--pages/goods/list/index.wxml-->
<view class="container">
<!-- 商品列表功能 -->
<view class="goods-list">
<block>
<goods-card></goods-card>
<goods-card></goods-card>
<goods-card></goods-card>
<goods-card></goods-card>
</block>
<!-- 数据是否加载完毕 -->
<view class="finish" hidden="{{ !isFinish }}">数据加载完毕~~~</view>
</view>
<!-- 商品为空的时候展示的结构 -->
<!-- <van-empty description="该分类下暂无商品,去看看其他商品吧~">
<van-button round type="danger" class="bottom-button" bindtap="gotoBack">
查看其他商品
</van-button>
</van-empty> -->
</view>
1.2订单样式
/* pages/goods/list/index.wxss */
.container {
padding-top: 0rpx !important;
}
.goods-list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.finish {
height: 80rpx;
line-height: 80rpx;
display: block !important;
overflow: hidden;
width: 100%;
text-align: center;
color: #f3514f;
border-top: 1rpx solid #ccc;
font-size: 28rpx;
}
}
1.2.1 line-height
-
定义与用途:
line-height
属性定义了元素中文本行之间的最小距离,即基线间的距离。这不仅影响了文本的垂直间距,还可能与字号一起影响文本之间的空白距离。 -
语法与取值:
line-height
的语法包括多种取值方式,如normal
(默认值,通常为1到1.2倍的字体尺寸)、实数(缩放因子)、长度值(如像素值)、百分比(基于元素的字体尺寸)以及inherit
(继承父元素的行高)。 -
适用范围:
line-height
适用于所有元素,但在微信小程序中,通常直接应用于text
组件或其父级容器,以调整文本内容的行高。 -
设置方式:在WXSS(微信小程序样式表)中,可以通过类选择器或ID选择器等方式为元素设置
line-height
属性。例如:.finish { height: 80rpx; line-height: 80rpx; display: block !important; overflow: hidden; width: 100%; text-align: center; color: #f3514f; border-top: 1rpx solid #ccc; font-size: 28rpx; }
1.3效果图
Ⅹ.通用模块封装
1.wx.showToast()基本使用
App({
onShow(){
wx.showToast({
title: '消息提示框',
//success(成功)、error(失败)、loading(加载)、none(不显示图标)
icon:'success',
duration:2000,
//是否显示透明蒙层
mask:true
})
}
})
1.1生命周期函数
onload:页面加载时的生命周期函数
onShow:页面显示生命周期函数,没打开页面就会调用一次
onReady:页面初次渲染完成生命周期函数,页面初次渲染完成时触发
onHide:页面隐藏生命周期函数 如页面切入到后台或通过底部tab栏到其他页面
onUnload:页面卸载生命周期函数
1.2封装思路
a.创建一个toast方法对wx.showToast()方法进行封装
b.调用该方法时 传递对象作为参数
如果没有传递任何参数 设置一个空对象{}作为默认参数
从对象中包含 title 、 icon 、 duration 、 mask 参数,并给参数设置默认值
const toast = ({title="消息提示框",icon='success',duration=2000,mask=true} ={}) => {
wx.showToast({
title,
icon,
duration,
mask
})
//局部暴露toast方法
export { toast }
//全局挂载方法
wx.toast = toast
1.3 模块对话封装
// //用户使用modal函数时 使用showmodel的默认参数
const defaultOpt = {
title:'提示',
content:'你确定执行该操作嘛',
confirmColor:'#f2514f',
//接口调用结束后的回调函数
complete({confirm,cancel}){
confirm && console.log('点击了确定');
cancel && console.log('点击了取消');
}
}
a:对 wx.showModal() ⽅法进⾏封装, 封装后的新⽅法叫 modal。
b:调⽤该⽅法时,传递对象作为参数,对象的参数同 wx.showModal() 参数⼀致。
c:封装的 modal ⽅法的内部通过 Promise 返回⽤户执⾏的操作(确定和取消,都通过 resolve 返 回)。
d:在需要显示模态对话框的时候调⽤ modal ⽅法,并传⼊相关的参数
不传递参数 使用默认参数
传递参数 不使用默认参数
1.4代码实现
//普通函数
//function name(params) {}
//箭头函数
//name => (参数) {函数体}
// toast = ({默认参数}) = {实际参数} => {函数体}
//()里为参数
//()等号左边为函数toast默认的参数
//()等号右边为调用函数toast传入的参数
// const toast = ({title="消息提示框",icon='success',duration=2000,mask=true} ={}) => {}
const toast = ({title="消息提示框",icon='success',duration=2000,mask=true} ={}) => {
wx.showToast({
title,
icon,
duration,
mask
})
}
//局部暴露toast方法
export { toast }
//全局挂载方法
wx.toast = toast
//在调用modal方法是 可以传递参数 也可以不传递参数
//如果不传递参数 默认值就是空对象
//如果传递参数 参数需要是一个对象 对象中的属性需要和wxwx.showModal参数保持一致
const modal = (options = {}) => {
// //通过new关键词构建一个promise对象
// //在方法内部通过promise返回用户的操作
// //resolve为用户点击确认框的结果
return new Promise((resolve) => {
// //用户使用modal函数时 使用showmodel的默认参数
const defaultOpt = {
title:'提示',
content:'你确定执行该操作嘛',
confirmColor:'#f2514f',
//接口调用结束后的回调函数
complete({confirm,cancel}){
confirm && console.log('点击了确定');
cancel && console.log('点击了取消');
}
}
//Object.assign()方法用于将对象复制到目标对象
//通过Object.assign()方法将参数合并
//如果用户传递进来了options就会覆盖默认参数
//第一个空对象参数会被赋值合并后的参数
const opts = Object.assign({},defaultOpt,options)
wx.showModal({
//...扩展运算符
//将合并后的参数通过展开运算符赋值给wx.showModal对象
...opts,
complete({confirm,cancel}){
//如果用户点击了确认 通过resolve抛出true
confirm && console.log('点击了确定');
//如果用户点击了取消,通过resolve抛出false
cancel && console.log('点击了取消');
}
})
})
}
//局部暴露modal方法
export {modal}
//全局挂载方法
//wx.modal = modal
拾壹.网络请求封装
1.1请求封装-request方法
//1.使用了微信自带的请求api wx.request
//2.将wx.request封装到了一个名为request的函数中
//3.将函数封装到了一个名为WxRequest的类中
//创建一个WxRequest类
//通过类的方式进行封装 会让代码更具有复用性
//也可以方便添加新的属性和方法
class WxRequest {
//默认参数对象
defaults = {
//请求基地址
baseURL:'',
//服务器接口地址
url:'',
//请求方式
method:'GET',
//请求参数
data:null,
//请求头
header: {
'Content-type': 'application/json' // 设置数据的交互格式
},
//默认超时时间为一分钟
timeout:100,
}
//定义拦截对象 包括请求拦截和响应拦截方法 方便在请求或响应之前进行处理
interceptors = {
//请求拦截器
request:(config) => config,
//响应拦截器
response:(response) => response
}
//用于创建和初始化类的属性和方法
//params为用户传入的请求配置项
constructor(params={}){
//使用Object.assign方法合并默认参数以及传递的请求参数
//需要传入的参数 会覆盖默认的参数 因此传入的参数放在最后
this.defaults = Object.assign({},this.defaults,params)
}
//request实例要接受一个对象类型的参数
request(options){
//拼接完整的请求路径
options.url = this.defaults.baseURL + options.url
//合并请求参数
options = {...this.defaults,...options}
//发送请求之前添加loading
wx.showLoading({})
//在发送请求之前调用请求拦截器
options = this.interceptors.request(options)
console.log(options);
return new Promise((resolve,reject) => {
wx.request({
//使用拓展运算符将request函数传来的对象参数展开
...options,
//当接口调用成功就会触发success回调函数
success:(res) => {
//不管接口成功还是失败 都需要调用响应拦截器
//响应拦截器需要接受服务器响应的数据 然后对数据进行逻辑处理 处理好后进行返回
//在给响应拦截器传递参数时 需要将请求参数也一起上传
//方便进行代码的调式或者其他逻辑处理 所以需要合并数据
//然后将合并的参数给响应拦截器
//第一个参数:需要合并的目标对象
//第二个参数:服务器响应的数据
//第三个参数:请求配置以及自定义属性
//不管请求失败还是请求成功 都会将响应的数据传递给响应拦截器
//这个时候合并参数时 就需要追加一个属性:isSuccess
//如果属性值为true,说明执行了success回调函数
const mergetRes = Object.assign({},res,{config:options,isSuccess:true})
//resolve(res)
resolve(this.interceptors.response(mergetRes))
},
//当接口调用失败时会触发fail回调函数
fail:(err) => {
//如果属性值为false,说明执行了fail回调函数
const mergetErr = Object.assign({},err,{config:options,isSuccess:false})
// reject(err)
reject(this.interceptors.response(mergetErr))
},
//不管promise请求是否成功
//都会执行complete里面的内容
complete:()=> {
wx.hideLoading()
}
})
})
}
//封装GET方法
get(url,data={},config={}){
return this.request(Object.assign({url,data,method:'GET',config}))
}
//封装POST实例方法
post(url,data={},config={}){
return this.request(Object.assign({url,data,method:'POST',config}))
}
//封装PUT实例方法
put(url,data={},config={}){
return this.request(Object.assign({url,data,method:'PUT',config}))
}
//封装DELETE实例方法
delete(url,data={},config={}){
return this.request(Object.assign({url,data,method:'DELETE',config}))
}
//用来处理并发请求
all(...promise){
//通过展开运算符接受传递的参数
//展开运算符会将传入的参数转为数组
console.log(promise);
return Promise.all(promise)
}
}
export default WxRequest
1.2 request方法使用
<!--pages/test/test.wxml-->
<!-- <text>pages/test/test.wxml</text> -->
<view class="box">
<!-- 设置一个按钮 并给按钮设置一个名为handler的点击事件 点击按钮会发送请求 -->
<button type="warn" size="mini" plain bindtap="handler">测试发送请求</button>
<button type="primary" size="mini" plain bindtap="handler1">测试发送请求</button>
<button type="primary" size="mini" plain bindtap="AllHandler">测试并发请求</button>
</view>
1.3 请求封装-设置请求参数
在发起网络请求时,需要配置⼀些请求参数
//默认参数对象
defaults = {
//请求基地址
baseURL:'',
//服务器接口地址
url:'',
//请求方式
method:'GET',
//请求参数
data:null,
//请求头
header: {
'Content-type': 'application/json' // 设置数据的交互格式
},
//默认超时时间为一分钟
timeout:100,
默认参数:在 WxRequest 类中添加 defaults 实例属性来设置默认值
实例化时参数:在对 WxRequest 类进行实例化时传入相关的参数,需要在 constructor 构造 函数形参进行接收 调用实例方法时传入请求参数
1.4封装请求快捷方法
GET、POST、PUT、DELETE封装方法
//封装GET方法
get(url,data={},config={}){
return this.request(Object.assign({url,data,method:'GET',config}))
}
//封装POST实例方法
post(url,data={},config={}){
return this.request(Object.assign({url,data,method:'POST',config}))
}
//封装PUT实例方法
put(url,data={},config={}){
return this.request(Object.assign({url,data,method:'PUT',config}))
}
//封装DELETE实例方法
delete(url,data={},config={}){
return this.request(Object.assign({url,data,method:'DELETE',config}))
}
通过使用方式,我们可以得出结论: 可以在 WxRequest 类内部定义 interceptors 实例属性,属性中需要包含 request 以及 response 方法
需要注意:在发送请求时,还需要区分是否通过实例调用了拦截器:
没有通过实例调用拦截器,需要定义默认拦截器,在默认拦截器中,需要将请求参数进行返回
通过实例调用拦截器,那么实例调用的拦截器会覆盖默认的拦截器方法,然后将新增或修改的请求 参数进行返回