【微信小程序】微信小程序购物商城[项目总结]

技术文章 胡成
文章标签: 微信小程序

前言

最近这俩天做了个微信小程序商城,想总结下项目过程中的知识点于难点。先上小程序效果展示下。

微信小程序.gif

开发要用到的:

1:微信开发者工具

概览

为了帮助开发者简单和高效地开发和调试微信小程序,我们在原有的公众号网页调试工具的基础上,推出了全新的 微信开发者工具,集成了公众号网页调试和小程序调试两种开发模式。

  • 使用公众号网页调试,开发者可以调试微信网页授权和微信JS-SDK 详情
  • 使用小程序调试,开发者可以完成小程序的 API 和页面的开发调试、代码查看和编辑、小程序预览和发布等功能。
具体使用方法可以点链接去看,传送门链接微信开发者工具


 2: WeUI for 为微信小程序量身设计的框架

概述

WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。包含buttoncelldialog、 progress、 toastarticleactionsheeticon等各式元素。

具体使用方法可以点链接去看,传送门链接WeUI for 小程序文档

项目开发步骤

1:底部选项栏

先在app.json文件配置(全局配置或者局部配置里一定要注意是不能写注释的 不然会报错!!!)

{
  "pages": [//页面路径列表
    "pages/shopping/shopping",
    "pages/index/index", 
    "pages/mycenter/mycenter",
    "pages/classify/classify",
    "pages/search/search",
    "pages/logs/logs"
    
  ],
  "window": {//全局的默认窗口表现
    "backgroundTextStyle": "#E02E24",
    "navigationBarBackgroundColor": "#E02E24",
    "navigationBarTitleText": "首页",
    "navigationBarTextStyle": "black"
  },
  "tabBar": {//底部 tab 栏的表现
    "color": "#333",
    "selectedColor": "red",
    "backgroundColor": "#fff",
    "position": "bottom",
    "list": [//tab 的列表,详见 list 属性说明,最少2个、最多5个 tab
      {
        "pagePath": "pages/index/index",//页面路径,必须在 pages 中先定义
        "text": "首页",//tab 上按钮文字
        "iconPath": "/images/nav/home-off.png",//默认图片路径
        "selectedIconPath": "/images/nav/home-on.png"//选中时的图片路径,
      },
      {
        "pagePath": "pages/classify/classify",
        "text": "分类",
        "iconPath": "/images/nav/fenlei01.png",
        "selectedIconPath": "/images/nav/fenlei02.png"
      },
      {
        "pagePath": "pages/shopping/shopping",
        "text": "购物车",
        "iconPath": "/images/nav/cart-off.png",
        "selectedIconPath": "/images/nav/cart-on.png"
      },
      {
        "pagePath": "pages/mycenter/mycenter",
        "text": "个人中心",
        "iconPath": "/images/nav/my-off.png",
        "selectedIconPath": "/images/nav/my-on.png"
      }
    ]
  }
}



2:商城首页

首页头部使用的滚动视图:

  <scroll-view class='scroll-view scoll-view-fixed' scroll-x scroll-with-animation="true">
    <view bindtap='setActiveIndex' class="scroll-view-item {{activeIndex==index?'active':''}}" wx:for='{{protype}}' data-index='{{index}}'>
      {{item}}
    </view>
  </scroll-view>

注意点:scroll-x:允许横向滚动,其次就是设置容器里的元素强制不换行

.scroll-view {

white-space: nowrap; /* 强制不进行换行 */

}

轮播图

    <swiper indicator-dots autoplay circular="true">
      <block wx:for="{{imgUrls}}">
        <swiper-item>
          <image src="{{item}}" class="slide-image" />
        </swiper-item>
      </block>
    </swiper>

注意点:轮播图使用的是 swiper 组件,组件元素的其他元素在这就不多说了,具体可以看文档。

向上滚动广告:

  <view class='view-adv'>
    <view style="float: left;">公告:</view>
    <swiper class='swiper-adv' autoplay vertical circular>
      <swiper-item>
        <text>今年的深圳雨水比较多</text>
      </swiper-item>
      <swiper-item>
        <text>预计16号-18号“山竹”将会席卷深圳</text>
      </swiper-item>
      <swiper-item>
        <text>第22号超强台风“山竹”登入深圳!</text>
      </swiper-item>
      <swiper-item>
        <text>今年的深圳将会体验冰火俩重天</text>
      </swiper-item>
    </swiper>
  </view>
<view>

注意点:这个其实也是个视图滑块只是滑的方向不同而已,使用元素vertical:滑动方向是否为纵向

热销商品:

<view>
    <scroll-view class='hot-prod' scroll-x bindscroll='hotProdScroll'>
      <view class="one-row">
        <view class="row-item" wx:for='{{6}}'>
          <image src='{{hotprods[index]}}'></image>
          <view>热销{{index+1}}</view>
        </view>
      </view>
      <view class="one-row">
        <view class="row-item" wx:for='{{5}}'>
          <image src='{{hotprods[index+6]}}'></image>
          <view>热销{{index+1+6}}</view>
        </view>
      </view>  
    </scroll-view>
</view>
  <!-- 显示进度 -->
<view class='prod-progress'>
    <view class='progress-outer'>
      <view class='progress-inner' style='margin-left:{{hotProdMarginLeft}}px'></view>
    </view>
</view>

注意点:热销商品使用也是 scroll-view 滚动容器用法同顶部栏一样在这就不多说了。

热销商品的进度条用的也是scroll-view滚动容器用法同上一样,但是多了个滚动容器事件bindscroll='hotProdScroll' 当事件执行会获取滚动的距离赋值给进度条的左外边距,添加上样式后就能展示出进度条效果了。

进度条JS代码:

//监听热销商品滚动事件
  hotProdScroll(e){
    // console.log(e)
    this.setData({
      hotProdMarginLeft: e.detail.scrollLeft//获取元素中水平偏移的值赋给变量
    })
  }

商品展示列表:

<!-- 商品列表 -->
<view class='commodity'>
  <view class='commodity-vd' wx:for="{{commodity}}">
      <view class='commodity-img'>
        <image src='{{item.pic}}'></image>
      </view>
      <view class='commodity-name'>{{item.name}}</view>
      <view class='commodity-price'>¥{{item.price}}</view>
  </view>
</view>

注意点:布局使用的时弹性盒子一行俩列

商品布局样式:

/* 商品列表 */
.commodity{
  /* 弹性盒子*/
  display:flex;
  padding: 15rpx;
  background-color: rgb(248, 248, 248);
  /* 换行 */
  flex-wrap:wrap;
  /* 盒子内容俩端对齐  */
  justify-content: space-between;
}

.commodity-vd{
  width: 350rpx;
  height: 470rpx;
  background-color: #fff;
  margin-bottom: 24rpx;
  box-sizing: border-box;
  overflow: hidden;

}
.commodity-vd .commodity-img{
  width: 350rpx;
  height:350rpx;
  overflow: hidden;
}

.commodity-vd .commodity-img image{
  width: 350rpx;
  height:350rpx;
}

.commodity-name{
   width: 320rpx;
   white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  padding:15rpx 10rpx;
}

.commodity-price{
  color: #e02e24;
  padding:0rpx 10rpx;
}



2:分类页面

<!-- 商品分类页面 -->
<view class='classify'>
  <view class='classify-searchbtn'>
      <navigator  url='/pages/search/search' open-type='navigate' class='classify-navigator'>
        <image src='/images/search.png'></image>
        搜索商品
      </navigator>
  </view>
</view>
<!-- 侧边栏 -->
<view class='broadside'>
    <!-- 侧边栏商品分类 -->
    <view class='broadside-left'>
      <scroll-view class='broadside-scroll' scroll-y style='height:{{leftHeight}}px'>
          <view wx:for="{{protype}}" bindtap='setActiveIndex' data-index='{{index}}'  class='broadside-item{{activeIndex==index?"active":""}}'>
            {{item}}
          </view>
      </scroll-view>
    </view>
    <!-- 商品信息 -->
    <view class='broadside-rigth' >
      <scroll-view scroll-y style='height:{{leftHeight}}px'>
        <view class='broadside-rigth-vew' wx:for="{{goods}}">
            <view class='broadside-rigth-left'><image src='{{item.pic}}'></image></view>
            <view class='broadside-rigth-rigth'>
              <view class='broadside-rigth-name'>{{item.name}}</view>
              <view>已售<text style='color:red;padding:0rpx 5rpx;'>0</text>件</view>
              <view><text style='color:red;'>¥{{item.price}}</text><text class='broadside-rigth-original'>¥299</text></view>
            </view>
        </view>
      </scroll-view>
        
      
    </view>
</view>

分类页面布局使用弹性盒子父容器设置 display: flex; 子容器左部分设置 flex: 1; /*剩下空间会被右容器占满*/

侧边栏与商品展示区同是使用 scroll-view 用法跟之前说的一样。

重点:竖向滚动是需要一个固定高度,侧边栏的高度是视图窗口的高减去搜索栏的高度,

JS代码:

// pages/goodstype/goodstype.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
     //类别名称
    protype: ['热销', '集成灶', '蒸箱烤箱', '水槽', '夏季焕新', '生鲜食品', '美妆服饰', '家居家电', '新鲜水果', '品质家纺', '酒水饮料', '美容护肤', '家用电器', '内衣鞋袜', '休闲零食'],
    //商品信息
    goods: [{ name: '御泥坊男士黑茶清爽控油矿物泥浆面膜去黑头祛痘收缩毛孔补水新品', price: 2323, pic: '/images/goods/1.jpg' },
    { name: '台湾欣兰黑里透白冻膜225g竹炭清洁收缩毛孔温和去黑白头面膜', price: 169, pic: '/images/goods/2.jpg' },
    { name: 'SHERO CHING', price: 178, pic: '/images/goods/3.jpg' },
    { name: 'JS-sdsosodsd', price: 545, pic: '/images/goods/4.jpg' },
    { name: 'asdsaasddsads', price: 20, pic: '/images/goods/5.jpg' },
    { name: '3223434', price: 199, pic: '/images/goods/6.jpg' },
    { name: '【两瓶420】【欣欣】佑珍提拉面膜紧致改善细纹抬头法令纹去黄', price: 240, pic: '/images/goods/7.jpg' },
    { name: '韩国A. by Bom超能婴儿叶子面膜冰凝叶清凉舒缓补水保湿10片包邮', price: 99, pic: '/images/goods/8.jpg' },
    { name: '手串手串手串', price: 200, pic: '/images/goods/9.jpg' },
    { name: 'Bershka 女士 2017秋冬新款粉色飞行员夹克短外套 01232551622', price: 2323, pic: '/images/goods/10.jpg' },
    { name: '御泥坊清爽平衡泥浆面膜清洁 男女泥膜收缩毛孔 去黑头竹炭火山泥', price: 454, pic: '/images/goods/11.jpg' },
    { name: '御泥坊美白嫩肤蚕丝面膜20片男女蚕丝玻尿酸面膜补水美白淡斑保湿', price: 444, pic: '/images/goods/12.jpg' },
    { name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮', price: 455, pic: '/images/goods/13.jpg' },
    { name: '御泥坊清润莹亮黑面膜控油收缩毛孔深清洁玻尿酸男女补水保湿面膜', price: 454, pic: '/images/goods/14.jpg' },
    { name: '御泥坊美白嫩肤黑面膜贴女士蚕丝玻尿酸祛斑面膜补水美白淡斑保湿', price: 3434, pic: '/images/goods/15.jpg' },
    { name: '御泥坊人参矿物蚕丝面膜7片*3盒 紧致抗皱去皱淡化细纹补水正品女', price: 5454, pic: '/images/goods/16.jpg' },
    { name: '御泥坊玫瑰滋养睡眠面膜免洗补水保湿护肤品夜间男女学生收缩毛孔', price: 344, pic: '/images/goods/17.jpg' },
    { name: '御泥坊红豆薏米面膜100g提亮肤色改善暗黄红润调理泥膜正品女包邮', price: 545, pic: '/images/goods/18.jpg' },
    { name: '御泥坊旗舰店葡萄籽美白淡斑祛黄黑面膜套21片 清洁补水保湿嫩肤', price: 434, pic: '/images/goods/19.jpg' },
    { name: '御泥坊水润黑白面膜贴补水保湿收缩毛孔亮肤玻尿酸护肤套装正品女', price: 69, pic: '/images/goods/20.jpg' },
    { name: '御泥坊小迷糊阿狸加菲猫玻尿酸秋季补水保湿亮肤黑面膜花瑶花男女', price: 233, pic: '/images/goods/21.jpg' },
    ],
    activeIndex: 0, //激活列表
    windowHeight: 0, //窗体的高度
    leftHeight: 0, //除了搜索框剩余的高度
  },
  // 获取下标事件
  setActiveIndex(e){//事件传递个参数
    // console.log(e)
    this.setData({
      activeIndex: e.target.dataset.index
    })
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    //获取屏幕高度,导航栏和底部工具之间的高度
    var _wHeight = wx.getSystemInfoSync().windowHeight//获取视图窗口高度赋给变量 555
    
    //创建一个节点查询器
    var query = wx.createSelectorQuery();//节点查询API
    var searchBox = query.select('.classify-searchbtn')//获取查询到的节点赋给变量searchBox
    var that = this;

    // 获取节点高度
    searchBox.boundingClientRect(function (rect) {// 执行查询节点信息事件返回个对象
      var height = rect.height//将高度赋给变量
      that.setData({//视图改变
        windowHeight: _wHeight,//视图窗口高度
        leftHeight:_wHeight-height,//剩余高度
      })
    }).exec(); 
    // console.log(that.data.leftHeight)
  },


})



3:搜索页面

搜索页面没什么好说的,搜索框和按钮都是weui的组件

html代码:

<!-- 搜索页面 -->
<view class='search'>
    <view class='search-container'> 
      <view class="page__bd">
        <view class="weui-search-bar">
          <view class="weui-search-bar__form">
            <view class="weui-search-bar__box">
              <icon class="weui-icon-search_in-box" type="search" size="14"></icon>
              <input type="text" class="weui-search-bar__input" placeholder="搜索" value="{{inputVal}}" focus="{{inputShowed}}" bindinput="inputTyping" bindblur='hideInput' />
              <view class="weui-icon-clear" wx:if="{{inputVal.length > 0}}" bindtap="clearInput">
                <icon type="clear" size="14"></icon>
              </view>
            </view>
            <label class="weui-search-bar__label" hidden="{{inputShowed}}" bindtap="showInput">
              <icon class="weui-icon-search" type="search" size="14"></icon>
              <view class="weui-search-bar__text">搜索</view>
            </label>
          </view>
          <view class="weui-search-bar__cancel-btn" hidden="{{!inputShowed}}" bindtap="hideInput">取消</view>
        </view> 
      </view>
    </view>
    <!-- 历史搜索 -->
    <view style='width: 100%;line-height: 44rpx;'>
      <view class='seek-Histories'>
        <view class='seek-Historiestxt'>历史搜索</view>
        <view class='seek-Historiesimg'><image src='/images/delete.png'></image></view>
      </view>
    </view>
    <view class='history-item'>        
           <button class="weui-btn mini-btn" type="default" size="mini">春秋被子</button>  
    </view>
    <!-- 热门搜索 -->
    <view style='margin-top:100rpx; margin-left:35rpx;'>
      <view>热门搜索</view>
      <view class='history-items'>        
           <button class="weui-btn mini-btn" type="default" size="mini">春秋被子</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">春秋椅垫</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">女加厚内衣</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">女睡衣春秋</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">月子服厚</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">学生被子冬季</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">门帘子冬天</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">春秋被子</button>  
           <button class="weui-btn mini-btn" type="default" size="mini">加厚运动装女</button>    
    </view>
    </view>
</view>

CSS代码:

page{
  background-color: #f7f7f7;
}
.searchbar-result{
    margin-top: 0;
    font-size: 14px;
}
.searchbar-result:before{
    display: none;
}
.weui-cell{
    padding: 12px 15px 12px 35px;
}

/* 历史搜索 */
.seek-Histories{
  display: flex;
  padding-top: 75rpx;

}

.seek-Historiestxt{
  flex: 1;
  margin-left: 30rpx;
}

.seek-Historiesimg{
  width: 35rpx;
  height:35rpx;
  padding-right: 35rpx;
  padding-top:5rpx;

}

.seek-Historiesimg image{
  width: 100%;
  height: 100%;
}

.history-item{
  margin:32rpx 0rpx 0rpx 35rpx;
}

.history-item button{
  padding:0rpx 15rpx;
}

.history-items button{
  margin-right: 25rpx;
  padding:0rpx 15rpx;

}

js:

// pages/usercenter/usercenter.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    inputShowed: false,//输入的时候显示
    inputVal: "" //输入的值
  },
  //事件部分
  //显示输入状态的ui
  showInput: function () {
    this.setData({
      inputShowed: true
    });
  },
  //隐藏输入状态
  hideInput: function () {
    this.setData({
      inputVal: "",
      inputShowed: false
    });
  },
  //清除内容
  clearInput: function () {
    this.setData({
      inputVal: ""
    });
  },
  //实时获取输入的内容
  inputTyping: function (e) {
    this.setData({
      inputVal: e.detail.value
    });
    console.log(e)
  }

})

4:个人中心

个人中心页面比较简单使用了weui框架的list布局,稍微修改下就可以了具体的就不细说了看代码

html:

<view>
<!-- 头部 -->
  <view class='center-top'>
      <view class='center-top-img'>
        <open-data type="userAvatarUrl"></open-data>
      </view>
      <open-data type="userNickName" class='center-top-name'></open-data>
  </view>

  <!-- 中心 -->
  <view class='center-center'>

        <view class='weui-cells weui-cells_after-title'>
          <navigator class="weui-cell" style='font-size:32rpx;' bindtap='classifypage'>
              <view class="weui-cell__bd">我的订单</view>
              <view class="weui-cell__ft orders">全部订单
                <image class='img-more' src="/images/more.png"></image>
              </view>
          </navigator>
        </view>

        <view class='center-center-vw' style='font-size:32rpx;'>
            <view class='center-center-vw-itm'>
                <image src='/images/order/待付款.png'></image>
                <text>待付款</text>
            </view>
            <view class='center-center-vw-itm'>
                <image src='/images/order/fahuo.png'></image>
                <text>待发货</text>
            </view>
            <view class='center-center-vw-itm'>
                <image src='/images/order/shouhuo.png'></image>
                <text>待收货</text>
            </view>
            <view class='center-center-vw-itm'>
                <image src='/images/order/pingjia.png'></image>
                <text>待评价</text>
            </view>
            <view class='center-center-vw-itm'>
                <image src='/images/order/wancheng.png'></image>
                <text>已完成</text>
            </view>
        </view>

  </view>
  <view style='height:20rpx;background:#EEEEEE;'></view>
  <!-- 底部 -->
  <view class='center-buttom'>
      <view class='weui-cells' style='font-size:32rpx;'>
        <navigator class='weui-cell' url=''>
          <view class='weui__hd'>
            <image class='icon' src="/images/my-info/myquan.png"></image>
          </view>
          <view class='weui__bd'>我的优惠券</view>
        </navigator>
        <navigator class='weui-cell' url=''>
          <view class='weui__hd'>
            <image class='icon' src="/images/my-info/tuikuan.png"></image>
          </view>
          <view class='weui__bd'>退款,售后</view>
        </navigator>
        <navigator class='weui-cell' url=''>
          <view class='weui__hd'>
            <image class='icon' src="/images/my-info/dizhi.png"></image>
          </view>
          <view class='weui__bd'>收货地址</view>
        </navigator>
        <navigator class='weui-cell' url=''>
          <view class='weui__hd'>
            <image class='icon' src="/images/my-info/kefu.png"></image>
          </view>
          <view class='weui__bd'>官方客服</view>
        </navigator>
        <navigator class='weui-cell' url=''>
          <view class='weui__hd'>
            <image class='icon' src="/images/my-info/shezhi.png"></image>
          </view>
          <view class='weui__bd'>设置</view>
        </navigator>  
      </view>
      <view>
        <navigator class='weui-cell weui-cell_access' url='' style='font-size:32rpx;'>
            <view class='weui-cell__bd'>关于我们</view>
            <view class="weui-cell__ft weui-cell__ft_in-access"></view>
        </navigator> 
      </view>
       
  </view>

</view>

css:

/* 头部 */
.center-top{
  width: 100%;
  height: auto;
  background:#E02E24;
  display: flex;
  flex-direction:column;
  text-align: center;
  padding: 20rpx 0rpx;
}

.center-top-img{
  width: 160rpx;
  height: 160rpx;
  border-radius: 50%;
  overflow: hidden;
  margin: 0px auto;
}

.center-top-name{
  padding: 20rpx 0rpx;
  color: white;
}

/* 中心部分 */
.img-more{
  width: 40rpx;
  height: 40rpx;
  vertical-align: middle;
  padding-bottom:6rpx;

}

.orders{
  vertical-align: middle;
  color: red;
}

.center-center-vw{
  display: flex;
  justify-content:space-around;
}

.center-center-vw-itm{
  padding: 20rpx;
  text-align: center
}

.center-center-vw-itm image{
  width: 45rpx;
  height: 45rpx;
}
.center-center-vw-itm text{
  display: block;
}

/* 底部部分 */
.icon{
  width: 45rpx;
  height: 45rpx;
  padding-top:14rpx;
  margin-right: 25rpx;
}

js:

// pages/shopcar/shopcar.js
Page({

  data: {

  },
  // 跳转到购物车
  classifypage(){
    wx.switchTab({//路由跳转
      url: '/pages/shopping/shopping',//购物车路径
    })
  }
})

主要点:用户头像信息的获取  使用<open-data type="userAvatarUrl">获取用户头

使用<open-data type="userNickName"> 获取用户昵称,还有等等其他使用类型请参考文档



5:购物车页面

购物车页面是这次项目的重点,第一个遇到的问题点就是向左滑动删除,这个问题点我到现在都还半懵的状态我,我就不多说了,先上代码:

html:

<view class='shopping-box'>
    <view class='shopping-top'>
       <view class='shopping-top-left'>购物车</view>
       <view class='shopping-top-right'>{{items.length}}件</view>
    </view>
    <!-- 顶部结束 -->
    <view class="container">
      <view wx:if='{{item.length!=0}}' class="touch-item {{item.isTouchMove ? 'touch-move-active' : ''}}" data-index="{{index}}" bindtouchstart="touchstart" catchtap='toggleBuy' bindtouchmove="touchmove" wx:for="{{items}}" wx:key="">
        <view class="content">
          <view class='weui-panel weui-panel_access' style='height: 220rpx;'>
            <view class='weui-panel__bd' style='padding-left:20px;'>
                <view class='weui-media-box__hd weui-media-box__hd_in-appmsg'>
                  <icon color='red' size='20' type='success' wx:if='{{item.blo}}'></icon>
                  <icon  size='20' type='circle' wx:else></icon>
                  <image src='{{item.img}}' ></image>
                </view>
                <view class='weui-media-box__bd weui-media-box__bd_in-appmsg'>
                    <view class='name'>{{item.name}}</view>
                    <view class='pricesty'> 
                      <text style='color:red;'>¥{{item.price}}</text> 
                      <button type='default' catchtap='reduceNumber' data-index='{{index}}' >-</button>
                      <input type="number" value="{{item.quantity}}"></input>
                      <button type='default' catchtap='addNumber' data-index='{{index}}'>+</button>
                    </view>
                </view>
            </view>
          </view>
        </view>
        <view class="del" catchtap="del" data-index="{{index}}">删除</view>
      </view>
    </view>
</view>
<view>购物车已经空了,快去购物吧~!</view>
  <!-- 购物车底部 -->
  <view class='car-footer-container'>
    <view class='car-footer'>
      <view class='select-all {{selectAll?"active":""}}' bindtap='selectAll'>全选</view>
      <view class='btn-buy'>
        <text style='color:red;padding:0 10px;'>合计:¥{{totalPrice}}</text>
        <button type='warn' bindtap='settle' disabled='{{totalPrice==0}}'>去结算</button>
      </view>
    </view>
  </view>

css:

/* 顶部 */
.shopping-top{
background: #EFEFEF;
display: flex;
justify-content:space-between;
height: 80rpx;
line-height: 80rpx;
}

.shopping-top-left{
padding-left: 26rpx;
}

.shopping-top-right{
padding-right: 26rpx;
}
/* 商品信息 */
.container {
height:100%;
display:flex;
flex-direction:column;
align-items:center;
justify-content:space-between;
padding:0rpx;
box-sizing:border-box;
padding-bottom:92rpx;

}

.touch-item {
font-size: 28rpx;
display: flex;
justify-content: space-between;
border-bottom:2rpx solid #ccc;
width: 100%;
overflow: hidden
}
.content {
width: 100%;
height:220rpx;
/* padding: 10px; */
line-height: 44rpx;
margin-right:0;
-webkit-transition: all 0.4s;
transition: all 0.4s;
-webkit-transform: translateX(180rpx);
transform: translateX(180rpx);
margin-left: -180rpx
}
.del {
background-color: #E64340;
width: 120rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #fff;
-webkit-transform: translateX(180rpx);
transform: translateX(180rpx);
-webkit-transition: all 0.4s;
transition: all 0.4s;
}
.touch-move-active .content,
.touch-move-active .del {
-webkit-transform: translateX(0);
transform: translateX(0);
}
.weui-panel{
border-top: 0px;
}

.weui-media-box__hd{
height: 100%;
width: 338rpx;
margin: 0rpx;
display: inline-block;
}

.weui-media-box__hd image{
width: 180rpx;
height: 210rpx;
margin-left:72rpx;
overflow: hidden;
}

.weui-panel__bd{
height: 100%;
}
icon{
height:268rpx;
}

.weui-media-box__bd{
display: inline-block;
width: 372rpx;
height: 177rpx;
overflow: hidden;
}

.pricesty{
padding-top:34rpx;
}

.name{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

.pricesty button{
width: 44rpx;
height: 55rpx;
padding-left:8rpx;
padding-right:8rpx;
display: inline-block;
line-height:48rpx;

}

input{
display: inline-block;
border: 2rpx #EFEFEF solid;
width: 40rpx;
text-align: center
}

.pricesty text{
margin-right: 160rpx;
}

/* 购物车底部 */

.car-footer-container {
background-color: #efefef;
border-top: 2rpx solid #ddd;
position: fixed;
bottom: 0;
width: 100%;
}

.car-footer {
display: flex;
/* display: block */
}

.car-footer .select-all {
background: url(https://cdn.it120.cc/images/weappshop/gou.png) no-repeat 60rpx center;
background-size: 40rpx auto;
text-align: right;
height: 92rpx;
line-height: 92rpx;
padding-left: 120rpx;
}
.car-footer .select-all.active{
background-image: url(https://cdn.it120.cc/images/weappshop/gou-red.png);
}

.car-footer .btn-buy {
flex: 1;
text-align: right;
}

.car-footer .btn-buy button {
display: inline-block;
vertical-align: middle;
border-radius: 0;
}

/*商品购买数量*/
.number-box{
display: flex;
}
.number-box .controler{
padding: 0px 16rpx;
height: 60rpx;
line-height:60rpx;
background-color: #efefef;
border: 2rpx solid #ddd;
}
.number-box .controler.middle{
background-color: #fff;
text-align: center;
border-left: none;
border-right: none;
padding: 0 20rpx;
}
.number-box .controler.left{
border-top-left-radius: 6rpx;
border-bottom-left-radius: 6rpx;
}
.number-box .controler.right{
border-top-right-radius: 6rpx;
border-bottom-right-radius: 6rpx;
}

js:

Page({

data: {
items: [ //购物车信息
{
name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮',//商品名称
img: '/images/goods/1.jpg',//商品图片
price: 455,//单价
quantity: 1,//数量
blo: false,//单选状态
},
{
name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮',
img: '/images/goods/2.jpg',
price: 300,
quantity: 1,
blo: false,
},
{
name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮',
img: '/images/goods/3.jpg',
price: 99,
quantity: 2,
blo: false,
},
{
name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮',
img: '/images/goods/4.jpg',
price: 100,
quantity: 3,
blo: false,
},
{
name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮',
img: '/images/goods/5.jpg',
price: 110,
quantity: 1,
blo: false,
},
{
name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮',
img: '/images/goods/6.jpg',
price: 789,
quantity: 1,
blo: false,
},
{
name: '御泥坊蜂蜜矿物睡眠面膜免洗滋润补水保湿护肤化妆正品男女包邮',
img: '/images/goods/7.jpg',
price: 789,
quantity: 1,
blo: false,
},
],
startX: 0, //开始坐标
startY: 0,
totalPrice: 0, //总价
selectAll: false, //是否全选
empty:false,//购物车清空状态
},

// 页面监听事件
onLoad: function() { //循环添加商品
for (var i = 0; i < this.data.items; i++) { //当小于商品集合时循环
this.data.items.push({
isTouchMove: false //默认全隐藏删除
})
}
this.setData({ //视图层改变
items: this.data.items,
totalPrice: this.totalPrice()
})
// console.log()
},

//手指触摸动作开始 记录起点X坐标
touchstart: function(e) {
//开始触摸时 重置所有删除
this.data.items.forEach(function(v, i) {
if (v.isTouchMove) //只操作为true的
v.isTouchMove = false;
})
this.setData({ //视图改变
startX: e.changedTouches[0].clientX, //获取手指触摸时的X轴起始坐标
startY: e.changedTouches[0].clientY, //获取手指触摸时的Y轴起始坐标
items: this.data.items
})

},
//滑动事件处理
touchmove: function(e) {
var that = this,
index = e.currentTarget.dataset.index, //当前索引
startX = that.data.startX, //开始X坐标
startY = that.data.startY, //开始Y坐标
touchMoveX = e.changedTouches[0].clientX, //滑动变化坐标
touchMoveY = e.changedTouches[0].clientY, //滑动变化坐标
//获取滑动角度
angle = that.angle({
X: startX,
Y: startY
}, {
X: touchMoveX,
Y: touchMoveY
});
that.data.items.forEach(function(v, i) {
v.isTouchMove = false
//滑动超过30度角 return
if (Math.abs(angle) > 30) return;
if (i == index) {
if (touchMoveX > startX) //右滑
v.isTouchMove = false
else //左滑
v.isTouchMove = true
}
})
//更新数据
that.setData({
items: that.data.items
})
},
/**
* 计算滑动角度
* @param {Object} start 起点坐标
* @param {Object} end 终点坐标
*/
angle: function(start, end) {
var _X = end.X - start.X,
_Y = end.Y - start.Y
//返回角度 /Math.atan()返回数字的反正切值
return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
},
//删除事件
del: function(e) { //事件执行传递对象
this.data.items.splice(e.currentTarget.dataset.index, 1) //删除对应下标的商品
this.setData({ //视图层改变
items: this.data.items, //将数据改变后的购物车信息从新赋值一次
totalPrice: this.totalPrice(), //调用一次总价计算事件
})
},

//总价计算事件
totalPrice() {
var tempGoods = this.data.items; //将购物车对象赋给变量
var totalPrice = 0; //重新申个变量方便操作
//总价等于数组元素相加后的值
//reduce() 方法接收一个函数作为累加器
totalPrice = tempGoods.reduce(function(total, current) {
if (current.blo) { //判断商品是否选中,选中的计算总价
//total累加的值是商品的数量*商品单价
return total + current.price * current.quantity;
} else {
return total;
}
}, 0)
//解析一个totalPrice字符串,并返回一个浮点数,totalPrice保留小数四舍五入后的后俩位数
return parseFloat(totalPrice.toFixed(2))

},

//减少数量事件
reduceNumber(e) { //事件执行传递对象
var index = e.currentTarget.dataset.index //获取传递对象下的index属性值
if (this.data.items[index].quantity == 1) { //通过下标找到对应的商品的数量进行判断,判断数量是否等于1,判断为true return 返回,结束事件。
return;
}
this.data.items[index].quantity--; //下标对应的商品的数量--
this.setData({ //视图改变
totalPrice: this.totalPrice(), //调用一次总价计算事件
items: this.data.items //将数据改变后的购物车信息从新赋值一次
})
// console.log(this.data.items[index].quantity)
},

//增加数量事件
addNumber(e) { //事件执行传递对象
var index = e.currentTarget.dataset.index //获取传递对象下的index属性值
this.data.items[index].quantity++ //下标对应的商品的数量++
this.setData({ //视图改变
totalPrice: this.totalPrice(), //调用一次总价计算事件
items: this.data.items //将数据改变后的购物车信息从新赋值一次
})
// console.log(this.data.items[index].quantity)
},

//选择或取消购买事件
toggleBuy(e) { //传递个下标
var arr = this.data.items;
var index = e.currentTarget.dataset.index
// 每次点击时取反
this.data.items[index].blo = !this.data.items[index].blo
// 筛选数组里的blo是否为fakse,返回参数 赋值给变量
let obj = this.data.items.find((e) => !e.blo)
// console.log(obj)
// console.log(this.data.items)

//设置购买状态
this.setData({ //视图层改变
items: this.data.items, ////数据改变后重新赋值,刷新一遍
totalPrice: this.totalPrice(), //重新计算总价
// 视图层改变时做3元判断,判断obj值是否为undefined 空,如果不是obj值为false,
// 如果obj值为undefinedn那么判断为true,判断后将obj赋给selectAll 全选按钮变量
selectAll: obj == undefined ? true : false
})

},

// 全选事件
selectAll(){
var checked = !this.data.selectAll;
this.setData({
selectAll: checked
})
for (var i = 0; i < this.data.items.length;i++){
this.data.items[i].blo = checked
}
this.setData({
items:this.data.items,
totalPrice: this.totalPrice(), //调用一次总价计算事件
})
},

// 结算事件
settle(){//选中的商品事件执行删除
for (var i = 0; i < this.data.items.length; i++) {//循环购物车
if (this.data.items[i].blo==true){//判断购物车的商品是否被选中
// console.log(this.data.items[i])
this.data.items.splice(i,1)//选中的删除
i--;
}
}
this.setData({//视图改变
empty:!this.data.empty,//清空状态为true
selectAll:false,//全选按钮为false
items:this.data.items,//重新赋值下改变视图层效果
totalPrice: this.totalPrice(), //调用一次总价计算事件
})
}

})

关于购物车的逻辑事件处理代码上注释得很详细我就不多说了,基本上我的购物车项目就是这样。

总结下此次项目的心得体验。

难点:

1:对于html布局很多基础的属性忘记不会使用。

2:对于js一些事件,逻辑的运算不了解。

3:基础太差,敲代码太慢

知识点:

1:<scroll-view> 视图容器的使用

2:<swiper> 滑块视图(轮播)的使用

3:弹性盒子的布局使用

4:视图窗口高度的获取,wx.getSystemInfoSync().windowHeight

5:节点元素信息获取

var query = wx.createSelectorQuery();//节点查询API

var searchBox = query.select('.classify-searchbtn')//获取查询到的节点赋给变量searchBox

// 获取节点高度

searchBox.boundingClientRect(function (rect) {// 执行查询节点信息事件返回个对象

var height = rect.height//将高度赋给变量

that.setData({//视图改变

windowHeight: _wHeight,//视图窗口高度

leftHeight:_wHeight-height,//剩余高度

})

}).exec();

6:事件冒泡阻止 catchtap

7:数组find()和forEach()方法的使用

8:页面跳转链接的使用  navigator

完整代码案列我已经上传到资料下载库里了,有兴趣可以去下载来看看,此次项目差不多就是这样,做的也不是很美观,兼容性试了下部分设备还有样式的问题,在之后又时间我会重新再更新下。OK 就到这了。




——来自胡小哥小程序商城分享文章

还能输出{{restrictNumber}}个字符  
  • {{reply.author}}

    {{CommonUtil.formateDate(reply.ac_CommentDate).shortTime}}
  • 回复了{{Comments.author}} :