1. 程式人生 > >使用微信小程式自定義元件實現的tabs選項卡功能

使用微信小程式自定義元件實現的tabs選項卡功能

一個自定義元件由 json wxml wxss js 4個檔案組成。要編寫一個自定義元件,首先需要在 json 檔案中進行自定義元件宣告(將 component 欄位設為 true 可這一組檔案設為自定義元件)

components/navigator/index.json

{
  "component": true
}

components/navigator/index.wxml

<!-- 自定義tab標籤元件-->
<!-- 標題列表-->
<scroll-view scroll-x="true" class="scroll-view-x" wx:if
="
{{!ttype || ttype==2}}"> <view class="scroll-view-item" wx:for="{{tList}}" wx:key="*this"> <view class="{{currentTab==(index) ? 'on' : ''}}" bindtap="_swichNav" data-current="{{index}}">{{ !tname ? item.name : item[tname].name }}</view> </view> </scroll-view>
<!--內容列表--> <slot> </slot>

components/navigator/index.js

//元件的對外屬性,是屬性名到屬性設定的對映表,屬性設定中可包含三個欄位, type 表示屬性型別、 value 表示屬性初始值、 observer 表示屬性值被更改時的響應函式
Component({
  properties:{
    //標題列表
    tList:{
      type: Array,
      value:[]
    }, 
    //當前tab index
    currentTab:{
      type:Number
, value:0, observer: function (newVal, oldVal) { this.setData({ currentTab : newVal }) } } }, //元件的方法,包括事件響應函式和任意的自定義方法,關於事件響應函式的使用 methods:{ // 內部方法建議以下劃線開頭 _swichNav:function(e){ //自定義元件觸發事件時,需要使用 triggerEvent 方法,指定事件名、detail物件和事件選項 this.triggerEvent('changeCurrent', { currentNum: e.currentTarget.dataset.current }) } } })

components/navigator/index.wxss

.scroll-view-x{
  background-color: #fff;
  white-space: nowrap;
  position:fixed;
  z-index:10;
  top:0
}
.scroll-view-x .scroll-view-item{
  display:inline-block;
  margin:0 35rpx;
  line-height: 33px;
  cursor: pointer;
}
.on{
  border-bottom: 2px solid red;
  color: red
}

使用自定義元件

使用已註冊的自定義元件前,首先要在頁面的 json 檔案中進行引用宣告。此時需要提供每個自定義元件的標籤名和對應的自定義元件檔案路徑:

pages/order-list/index.json

{
    "navigationBarTitleText":"訂單列表",
    "usingComponents": {
      "slideTab": "../../components/navigator/index"
    }
}

這樣,在頁面的 wxml 中就可以像使用基礎元件一樣使用自定義元件。節點名即自定義元件的標籤名,節點屬性即傳遞給元件的屬性值。
pages/order-list/index.wxml

<view >
    <slideTab tList="{{statusType}}"   bind:changeCurrent="swichNav" currentTab="{{currentType}}" >
      <swiper current="{{currentType}}" duration="300" bindchange="bindChange" style="height: {{windowHeight-35}}px;margin-top:35px;">
        <block>
          <swiper-item wx:for="{{list}}">
            <view class="no-order" hidden="{{item.length ? true : false}}">
              <image src="../../assets/imgs/no-order.png" class="no-order-img"></image>
              <view class="text">暫無訂單</view>
            </view>
            <scroll-view scroll-y="true" class="order-list" scroll-with-animation="true" lower-threshold="1" bindscrolltolower="scrolltolower" style="height: {{windowHeight-35}}px;" hidden="{{item ? flase : true}}">
              <view class="a-order" wx:for="{{item}}"  wx:key="childIndex" wx:for-item="childItem" >
                <view class="order-date">
                    <view class="date-box">下單時間:{{childItem.dateAdd}}</view>
                    <view class="status {{(childItem.status==-1 || childItem.status==4) ? '':'red'}}">{{item.statusStr}}</view>
                </view>
                <view class="goods-info" bindtap="orderDetail" data-id="{{childItem.id}}">
                    <view class="goods-des">
                      <view>訂單號 : {{childItem.orderNumber}} </view>
                      <view wx:if="{{childItem.remark && childItem.remark != ''}}">備註: {{item.remark}}</view>
                    </view>
                </view>
                <view >
                    <scroll-view class="goods-img-container" scroll-x="true">
                        <view class="img-box" wx:for="{{goodsMap[currentType][childItem.id]}}" wx:for-item="child_item">
                            <image src="{{child_item.pic}}" class="goods-img"></image>
                        </view>
                    </scroll-view>
                </view>
                <view class="price-box">
                    <view class="total-price">合計:¥ {{childItem.amountReal}}</view>
                    <view class="btn cancel-btn" hidden="{{childItem.status==0? false : true}}" bindtap="cancelOrderTap"  data-id="{{childItem.id}}">取消訂單</view>
                    <view class="btn topay-btn" hidden="{{childItem.status==0? fslse : true}}" bindtap="toPayTap" data-id="{{childItem.id}}" data-money="{{childItem.amountReal}}">馬上付款</view>        
                </view>  
              </view>
            </scroll-view>
          </swiper-item>
        </block>
      </swiper>
    </slideTab>
</view>

pages/order-list/index.js

var wxpay = require('../../utils/pay.js')
var app = getApp();
Page({
  data:{
    statusType:[
      {name:"待付款",page:0},
      {name:"待發貨",page:0},
      {name:"待收貨",page:0},
      {name:"待評價",page:0},
      {name:"已完成",page:0}],
    currentType:0,
    list:[[],[],[],[],[]],
    goodsMap:[{},{},{},{},{}],
    logisticsMap:[{},{},{},{},{}],
    windowHeight:''
  },
  onLoad(options){
    this.getList();
    var systemInfo = wx.getSystemInfoSync()
    this.setData({
      windowHeight: systemInfo.windowHeight,
      currentType:options.id ? options.id:0
    })
  },
  // 點選tab切換 
  swichNav: function (res) {
    if (this.data.currentType == res.detail.currentNum) return;
    this.setData({
      currentType: res.detail.currentNum
    })
  } , 
  bindChange:function(e){
    this.setData({
      currentType: e.detail.current
    })
    if (!this.data.list[e.detail.current].length)
      this.getList();
  } ,
  getList(){
    wx.showLoading();
    var that = this;
    var postData = {
      token: app.globalData.token,
      status: that.data.currentType
    };
    var _page = that.data.statusType[that.data.currentType].page+1 ;;
    wx.request({
      url: app.globalData.baseUrl + '/order/list',
      data: postData,
      success: (res) => {
        wx.hideLoading();
        var param = {}, str1 = "list[" + that.data.currentType + "]", str2 = 'statusType[' + that.data.currentType + '].page', str3 = "logisticsMap[" + that.data.currentType + "]", str4 = "goodsMap[" + that.data.currentType + "]" ;
        if (res.data.code == 0) {
          param[str1] = res.data.data.orderList ;
          param[str2] = _page ;
          param[str3] = res.data.data.logisticsMap ;
          param[str4] = res.data.data.goodsMap ;
          that.setData(param);
        } else {
          param[str1] = [];
          param[str3]= {};
          param[str4] = {};
          this.setData(param);
        }
      }
    })
  },
  orderDetail: function (e) {
    var orderId = e.currentTarget.dataset.id;
    wx.navigateTo({
      url: "/pages/order-details/index?id=" + orderId
    })
  },
  cancelOrderTap: function (e) {
    var that = this;
    var orderId = e.currentTarget.dataset.id;
    wx.showModal({
      title: '確定要取消該訂單嗎?',
      content: '',
      success: function (res) {
        if (res.confirm) {
          wx.showLoading();
          wx.request({
            url: app.globalData.baseUrl + '/order/close',
            data: {
              token: app.globalData.token,
              orderId: orderId
            },
            success: (res) => {
              wx.hideLoading();
              if (res.data.code == 0) {
                var param = {}, str = 'statusType[' + that.data.currentType + '].page';
                param[str]=0;
                that.getList();
              }
            }
          })
        }
      }
    })
  }
})

pages/order-list/index.wxss

.container{
    width: 100%;
    background-color: #F2f2f2;
}
.status-box{
    width:100%;
    height: 88rpx;
    line-height: 88rpx;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #fff;
}
.status-box .status-label{
    width: 150rpx;
    height: 100%;
    text-align: center;
    font-size:28rpx;
    color:#353535;
    box-sizing: border-box;
    position: relative;
}
.status-box .status-label.active{
    color:#e64340;
    border-bottom: 6rpx solid #e64340;
}
.status-box .status-label .red-dot{
    width: 16rpx;
    height: 16rpx;
    position: absolute;
    left: 116rpx;
    top:23rpx;
    background-color: #f43530;
    border-radius: 50%;
}
.no-order{
    width: 100%;
    position: absolute;
    bottom: 0;
    top:0;
    left: 0;
    right: 0;
    text-align: center;
    padding-top: 203rpx;
    background-color: #F2f2f2;
}
.no-order-img{
    width: 81rpx;
    height: 96rpx;
    margin-bottom: 31rpx;
}
.no-order .text{
    font-size:28rpx;
    color:#999999;
    text-align: center
}
.order-list{
    width: 100%;
}
.order-list .a-order{
    width: 100%;
    background-color: #fff;
    margin-top: 20rpx;
}
.order-list .a-order .order-date{
    padding: 0 30rpx;
    height: 88rpx;
    display: flex;
    justify-content: space-between;
    font-size:26rpx;
    color:#000000;
    align-items: center;
}
.order-list .a-order .order-date .red{
    font-size:26rpx;
    color:#e64340;
}
.a-order  .goods-info,
.goods-img-container{
    width: 720rpx;
    margin-left: 30rpx;
    border-top: 1rpx solid #eee;
    border-bottom: 1rpx solid #eee;
    padding: 30rpx 0;
    display: flex;
    align-items: center;
}
.goods-info .img-box{
    width: 120rpx;
    height: 120rpx;
    overflow: hidden;
    margin-right: 30rpx;
    background-color: #f7f7f7;
}
.goods-info .img-box .goods-img,
.goods-img-container .img-box .goods-img{
    width: 120rpx;
    height: 120rpx;
}
.goods-info  .goods-des{
    width: 540rpx;
    height: 78rpx;
    line-height: 39rpx;
    font-size:26rpx;
    color:#000000;
    overflow: hidden;
}
.goods-img-container{
    height: 180rpx;
    box-sizing: border-box;
    white-space: nowrap;
}
.goods-img-container .img-box{
    width: 120rpx;
    height: 120rpx;
    overflow: hidden;
    margin-right: 20rpx;
    background-color: #f7f7f7;
    display: inline-block;
}
.order-list .a-order .price-box{
    position: relative;
    width: 720rpx;
    height: 100rpx;
    margin-left: 30rpx;
    box-sizing: border-box;
    padding: 20rpx 30rpx 20rpx 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size:26rpx;
}
.order-list .a-order .price-box .total-price{
    font-size:26rpx;
    color:#e64340;
}
.a-order .price-box .btn{
    width: 166rpx;
    height: 60rpx;
    box-sizing: border-box;
    text-align: center;
    line-height: 60rpx;
    border-radius: 6rpx;
    margin-left: 20rpx;
}
.a-order .price-box .cancel-btn{
    border: 1rpx solid #ccc;
    position: absolute;
    right: 216rpx;
    top:20rpx;
}
.a-order .price-box .topay-btn{
    border:1px solid #e64340;
    color: #e64340;
}

效果圖
這裡寫圖片描述