微信小程序sku商品规格选择器

最近做了一个电商类的微信小程序项目,因为业务的需求不得不用到sku商品规格选择器,本来是想在网上随便找一个,然后简单改改样式,无奈都是JQ的实现方案,所以也只能按照JQ的实现原理自己写一套微信小程序的实现方案。

演示效果

sku演示.gif

代码实现

demo.wxml文件代码如下:



  
    立即购买
  
  
  
    
      
      
        ¥{{selPrice}}
        已选:{{selTypeList}}
        库存:{{selStock}}
      
    
    
      
        {{wrapItem[0].name}}
        
          {{item.val}}
        
      
                 
    
    
      +
      {{selNum}}
      -  
    
    确认
  


demo.wxssl文件代码如下:

/* pages/demo/demo.wxss */
.container .footer-box{
  position: fixed;
  bottom: 0rpx;
  margin: auto;
  height: 100rpx;
  width:100%;
  background-color: #E40112;
  text-align: center;
  line-height: 100rpx;
  color: #fff;
  font-size: 32rpx;
}
.container .btn-hover{
  opacity: 0.8;
}
.container .mark{
  position: fixed;
  z-index: 10;
  height: 100%;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.75)
}
.container .detail-box{
  position: fixed;
  z-index: 10;
  bottom: -980rpx;
  height: 980rpx;
  width: 100%;
  background-color: #fff;
}
.container .detail-box .goods-img-box{
  height: 240rpx;
  box-sizing: border-box;
  padding: 24rpx;
  border-bottom: solid 1rpx #e3e3e3;
}
.container .detail-box .goods-img-box .goods-img{
  height: 192rpx;
  width: 192rpx;
  float: left;
}
.container .detail-box .goods-img-box .right-side{
  float: left;
  padding-top: 10rpx;
}
.container .detail-box .goods-img-box .right-side .price{
  font-size: 32rpx;
  color: #E40112;
  font-weight: bold;
}
.container .detail-box .goods-img-box .right-side .type{
  font-size: 24rpx;
  color: #333;
  margin-top: 8rpx;
  margin-bottom: 8rpx;
  overflow : hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;  
}
.container .detail-box .goods-img-box .right-side .inventory{
  font-size: 24rpx;
  color: #999;
}

.container .detail-box .sel-box{
  height: 560rpx;
  width: 100%;
  box-sizing: border-box;
  padding-bottom: 24rpx;
  overflow-y: auto;
}

.container .detail-box .sel-box .sel-list {

}
.container .detail-box .sel-box .sel-list .sel-title{
  font-size: 28rpx;
  color: #333;
  line-height: 60rpx;
  padding-left: 24rpx;
}
.container .detail-box .sel-box .sel-list .type-list{
  padding-left: 24rpx;
}
.container .detail-box .sel-box .sel-list .type-list {
  overflow: hidden;
} 
.container .detail-box .sel-box .sel-list .type-list .type-item{
  display: inline-block;
  float: left;
  height: 50rpx;
  line-height: 48rpx;
  border: solid 1rpx #999;
  padding-left: 15rpx;
  padding-right: 15rpx;
  font-size: 24rpx;
  color: #666;
  border-radius: 5rpx;
  margin-right: 24rpx;
  margin-bottom: 24rpx;
}
.container .detail-box .sel-box .sel-list .type-list .sel{
  border: solid 1rpx #f63636;
  color: #f63636;
}
.container .detail-box .sel-box .sel-list .type-list .ban{
  background-color: #f5f5f5;
  border: solid 1rpx #f5f5f5;  
}
.container .detail-box .confirm-btn{
  height: 100rpx;
  background-color: #E40112;
  text-align: center;
  line-height: 100rpx;
  color: #fff;
  font-size: 30rpx;
}
.container .detail-box .buy-ban{
  background-color: #ddd;
}
.container .detail-box .number-box{
  padding-left: 24rpx;
  padding-right: 24rpx;
  height: 80rpx;
  box-sizing: border-box;
  border-top: solid 1rpx #e3e3e3;
}
.container .detail-box .number-box .control{
  margin-top: 14rpx;
  float: right;
  height: 52rpx;
  width: 52rpx;
  background-color: #e3e3e3;
  text-align: center;
  line-height: 52rpx;
  color: #666;
  font-size: 36rpx;
  border-radius: 5rpx;
  margin-left: 4rpx;
}
.container .detail-box .number-box .ban{
  background-color: #F0F0F0;
}
.container .detail-box .number-box .num{
  width: 100rpx;
  font-size: 26rpx;
  background-color: #f0f0f0;
  font-family: Arial, Helvetica, sans-serif; 
}

demo.js代码如下:

Page({
  /**
   * 页面的初始数据
   */
  data: {
    animationDataSel: {},//动态弹出框所需参数
    selHidden:true,//模态框是否隐藏
    btnType:"buy-ban",//确定按钮禁用标记
    minusBan:"ban",//减号禁用标记
    plusBan: "ban",//加号禁用标记
    normalImg:"../../dist/images/1.jpg",//商品初始化时显示的图片
    selImg:"../../dist/images/1.jpg",//当前选择的商品图片
    selPrice: '350.00',//当前选择的商品价格
    selTypeList:"-",//当前选择的商品类别详情
    selStock:"-",//当前选择的商品库存
    selNum:1,//要购买的数量
    all_ids:[],//sku相关数据,用于后续操作
    key: [
      [{ val: "塞尔达传说", state: "", name: "游戏", images: "../../dist/images/1.jpg" },{ val: "马里欧赛车", state: "", name: "游戏", images: "../../dist/images/2.jpg"},{ val: "马里欧奥德赛", state: "", name: "游戏", images: "../../dist/images/3.jpg"} ,{ val: "异度之刃2", state: "", name: "游戏", images: "../../dist/images/4.jpg"}],
      [{ val: "中国大陆",name: "版本", state: ""}, { val: "日版", name: "版本",state: "" }, { val:"美版",name: "版本", state: "" }, { val: "欧版",name: "版本", state: "" }],
      [{ val: "东风快递",name: "快递", state: "" }, { val: "美团外卖",name: "快递", state: "" }, { val: "EMS",name: "快递", state: "" }, { val: "顺丰快递",name: "快递", state: "" }],

    ],//商品类型相关数据,一般通过调用服务端接口获取(这里可以自行修改数据,我写的数据比较简略)
    sku_list: [
    {
      'attrs': '塞尔达传说|日版|EMS',
      'num': 10,
      'price':"330.00",
      'sku_id':"a1",
    },
    {
      'attrs': '塞尔达传说|欧版|东风快递',
      'num': 6,
      'price':"350.00",
      'sku_id':"a2",
    },
    {
      'attrs': '马里欧赛车|中国大陆|美团外卖',
      'num': 11,
      'price':"295.00",
      'sku_id':"a3",
    },
    {
      'attrs': '马里欧奥德赛|中国大陆|EMS',
      'num': 3,
      'price':"305.00",
      'sku_id':"a4",
    },
    {
      'attrs': '异度之刃2|日版|顺丰快递',
      'num': 1,
      'price':"450.00",
      'sku_id':"a5",
    },    
    ]////商品详情数据,一般通过调用服务端接口获取
  },
  minus:function(){
    //减少购买数量
    let that=this;
    if (that.data.minusBan=="ban"){
      return;
    }else{
      that.setData({
        selNum: that.data.selNum-1
      })
      if (that.data.selNum==1){
        that.setData({
          minusBan:"ban"
        })
      }
    }
    if (that.data.selNum == that.data.selStock) {
      that.setData({
        plusBan: "ban"
      })
    }else{
      that.setData({
        plusBan: ""
      })      
    }
  },
  plus:function(){
    //增加购买数量
    let that = this;
    if (that.data.plusBan == "ban"){
      return;
    }else{
      that.setData({
        selNum: that.data.selNum + 1
      })
      if (that.data.selNum == that.data.selStock) {
        that.setData({
          plusBan: "ban"
        })
      }
      if (that.data.selNum == 1) {
        that.setData({
          minusBan: "ban"
        })
      }else{
        that.setData({
          minusBan: ""
        })        
      }
    }
  },
  buy:function(){
    //立即购买按钮触发
    this.showSelBox();
  },
  confirm:function(){
    //弹窗确认按钮触发
    if (this.data.btnType == "buy-ban") {
      return
    }else{
      let sku_id=this.data.sku_id;
      let selNum=this.data.selNum;
      wx.showToast({
        title: `商品sku_id是${sku_id},购买数量为${selNum}`,
        icon: 'none',
        duration: 2000
      })
      this.hiddenSel();
    }    
  },
  hiddenSel: function () {//隐藏选项
    let that = this;
    let animation = wx.createAnimation({ //动画
      duration: 300, //动画持续时间
      timingFunction: 'linear', //动画的效果 动画从头到尾的速度是相同的
      transformOrigin: "50% 50% 0",
    })
    let systemInfo = wx.getSystemInfoSync();
    let px = 980 / 750 * systemInfo.windowWidth;
    animation.translateY(px).step() //在Y轴偏移tx,单位px    
    this.setData({
      animationDataSel: animation.export(),
      selHidden: true
    })
  },
  showSelBox: function (e) {//显示选项
    let that = this;
    let systemInfo = wx.getSystemInfoSync();
    let px = 980 / 750 * systemInfo.windowWidth;

    this.animation.translateY(-px).step() //在Y轴偏移tx,单位px
    this.setData({
      animationDataSel: that.animation.export(),
      selHidden: false,
    })
  },      
  //获取所有包含指定节点的路线
  filterProduct: function (ids) {
    let result = [];
    this.data.sku_list.forEach(function (v, k) {
      let _attr = '|' + v['attrs'] + '|';
      let _all_ids_in = true;
      for (k in ids) {
        if (_attr.indexOf('|' + ids[k] + '|') == -1) {
          _all_ids_in = false;
          break;
        }
      }
      if (_all_ids_in) {
        result.push(v);
      }
    });
    return result;
  },
  //获取经过已选节点 所有线路上的全部节点
  // 根据已经选择得属性值,得到余下还能选择的属性值
  filterAttrs:function(ids){
    var products = this.filterProduct(ids);
    var result = [];
    products.forEach(function (v, k) {
      result = result.concat(v['attrs'].split('|'));
    });
    return result;
  },
  //获取选中的id数组
  getSelAttrId:function(){
    let list=[];
    for(let i=0;i 1) {
        that.setData({
          minuslBan: "",
        })
      } else {
        that.setData({
          minuslBan: "ban",
        })
      }
      if (that.data.selNum>=that.data.selStock){
        that.setData({
         plusBan: "ban",
        })  
      }else{
        that.setData({
          plusBan: "",
        })       
      }
    }else{
      that.setData({
        btnType: "buy-ban",
        selTypeList:"-",
        selStock:"-",
        minusBan:"ban",
        plusBan: "ban",        
      })      
    }   
  },
  set_block:function(){
    //sku相关操作
    let list = [];
    let listTemp=[];
    for(let a=0;a aSet.has(v) && !bSet.has(v))))
    for (let i = 0; i < differenceNew.length;i++){
      for (let j = 0; j < this.data.key[differenceNew[i]].length;j++){
        if (this.data.key[differenceNew[i]][j].state != "sel"){
          if (this.data.all_ids.includes(this.data.key[differenceNew[i]][j].val)) {
            this.data.key[differenceNew[i]][j].state = "";
          } else {
            this.data.key[differenceNew[i]][j].state = "ban";
          }
        }
      }
    }
    this.setData({
      key:this.data.key
    })
  },
  update:function(){
    //sku相关操作
    let that=this;
    let list=[];
    let select_ids=this.getSelAttrId();
    for (let i = 0; i < this.data.key.length; i++) {
      for (let j = 0; j < this.data.key[i].length; j++) {
        if (this.data.key[i][j].state == "sel") {
          list.push(i)
          break;
        }
      }
    }
    for (let a = select_ids.length - 1; a >=0;a--){
      let select_ids2 = this.del_array_val(select_ids, select_ids[a]);
      let all_ids = this.filterAttrs(select_ids2);
      that.data.key[list[a]].forEach((v1,k1)=>{
        if (v1.state != "sel") {
          if (all_ids.includes(v1.val)) {
            that.data.key[list[a]][k1].state = "";
          } else {
            that.data.key[list[a]][k1].state = "ban";
          }
        }
      })
    }
    this.setData({
      key: this.data.key
    })             
  },
  del_array_val:function(arr,val){
    //去除 数组 arr中的 val ,返回一个新数组
    var a = [];
    for (let k in arr) {
      if (arr[k] != val) {
        a.push(arr[k]);
      }
    }
    return a;
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    let that = this
    that.animation = wx.createAnimation({ //动画
      duration: 300, //动画持续时间
      timingFunction: 'linear', //动画的效果 动画从头到尾的速度是相同的
      transformOrigin: "50% 50% 0",
    })  
  },
})

结束语

以上代码复制粘贴到自己的微信小程序项目中就能够正常运行,如有错误或需要改进的地方还请与我联系,我将及时进行改正。

你可能感兴趣的:(微信小程序sku商品规格选择器)