天天看點

微信小程式自定義picker前言實作使用姿勢代碼擷取尾巴

微信小程式自定義picker

  • 前言
  • 實作
    • 蒙層
    • 底部内容
    • 内容頂部
    • picker
    • 布局實作
    • js實作
    • 樣式
  • 使用姿勢
  • 代碼擷取
  • 尾巴

前言

之前UI丢了一張類似這樣的效果圖(當然這個是本文的效果圖,不是原圖,不過差不多)給我:

微信小程式自定義picker前言實作使用姿勢代碼擷取尾巴

當時看到圖就想這個還不簡單,直接使用picker就行了。然後就是一頓操作,選擇mode為date,最終出現了效果圖:

微信小程式自定義picker前言實作使用姿勢代碼擷取尾巴

正當我沉浸在完成功能的喜悅中的時候,心裡有個聲音一直在提醒我:你沒有達到UI需求效果,你沒有達到UI需求效果,你沒有達到UI需求效果…

定睛一看果然和UI效果圖有些許差別,UI左上角顯示的是【全部】,而我們現在是【取消】,頂部是圓角,而我們現在是直角。第二個問題影響顯然比第一個問題影響小,我們直接通過微信提供的picker相關API把左上角的字修改成【全部】勉強也能用,那我們就去檢視下相關API。

微信小程式自定義picker前言實作使用姿勢代碼擷取尾巴

查遍picker這貨的所有API,竟然不支援修改左上角的文字。然後我們會妥協,讓UI把這個全部功能去掉或者移動到其他地方麼?不,這輩子都不可能妥協,程式猿永不為奴!!!既然這樣,那我們就自己來實作個picker把,開幹~~

微信小程式自定義picker前言實作使用姿勢代碼擷取尾巴

實作

通過分析UI圖可以發現,整個是由四部分組成:

  • 蒙層
  • 底部内容
  • 内容頂部按鈕
  • picker滾動區域

蒙層

.mask {
  position: fixed;
  width: 100%;
  height: 100%;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: flex;
  background-color: rgba(0,0,0,0.7);
  z-index: 9999;
  flex-direction: column;
  justify-content: flex-end;
 }
           

z-index是設定顯示層級,為了讓内容顯示在底部,使用column布局方式,并且justify-content為flex-end。這些知識在我之前系列的文章微信小程式布局技巧裡面有提到,不太清楚的可以看之前的文章。

底部内容

.content {
  display: flex;
  flex-direction: column;
  width: 100%;
  background: white;
  border-top-right-radius: 20rpx;
  border-top-left-radius: 20rpx;
}
           

布局是上下排列,是以使用column布局方式,然後通過border-top-right-radius和border-top-left-radius來實作左上角和右上角的圓角。

内容頂部

.top {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  height: 100rpx;
  border-bottom: 1rpx solid #d3cfcf;
}

.top-text {
  font-size: 30rpx;
  width: 150rpx;
  height: 100rpx;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
           

橫向排列按鈕,是以選用row布局,然後設定字型樣式。

picker

這裡主要是使用的系統提供的picekr-view實作,後面會給出完整代碼。

布局實作

<view class='mask' wx:if="{{isShow}}" catchtap="cancel">
	<view class="content" style="height:500rpx" animation="{{animation}}">
		<view class="top">
			<view class="top-text top-left-color" hover-class="top-left-color-hover" catchtap="lefttap">全部</view>
			<view class="top-text top-right-color" hover-class="top-right-color-hover" catchtap="righttap">确定</view>
		</view>
		<picker-view style="width: 100%; height: 400rpx;" value="{{value}}" bindchange="bindChange" catchtap="no">
			<picker-view-column>
				<view wx:for="{{years}}" style="line-height: 50px" class="item">{{item}}年</view>
			</picker-view-column>
		</picker-view>
	</view>
</view>
           

js實作

我們這裡為了更好的封裝采用component形式:

var that
Component({
  /**
   * 元件的屬性清單
   */
  properties: {
  	//開始年份
    start: {
      type: Number,
      value: 1900
    },
    //結束年份
    end: {
      type: Number,
      value: 9999
    }
  },

  /**
   * 元件的初始資料
   */
  data: {
    isShow: false,
    value: [0],//設定picker-view預設哪項選中
    years: [],
    year: 1900,
    current: 1900,
    dialogh: 0
  },
  attached: function () {
    console.log('attached')
    that = this
    //動畫
    that.animation = wx.createAnimation({
      duration: 300
    })
    //500rpx轉成px
    var dialoghpx = 500 / 750 * wx.getSystemInfoSync().windowWidth
    that.setData({
      dialogh: dialoghpx
    })
  },
  detached: function () {
    console.log('detached')
  },
  pageLifetimes: {
    //元件所在的頁面被展示時執行 最低版本2.2.3
    show: function () {
      console.log('頁面show')
      var yearstemp = []
      for(var i = that.properties.start; i <= that.properties.end; i ++){
        yearstemp.push(i)
      }
      //通過配置屬性擷取years
      that.setData({
        years: yearstemp
      })
    },
    //元件所在的頁面被隐藏時執行 最低版本2.2.3
    hide: function () {
      console.log('頁面被隐藏')
    },
    //這個函數一般使用場景較少,了解就可以了  最低版本2.4.0
    resize: function (size) {
      console.log('頁面尺寸變化')
    }
  },
  /**
   * 元件的方法清單
   */
  methods: {
    bindChange: function (e) {
      const val = e.detail.value
      that.setData({
        year: this.data.years[val[0]]
      })
    },
    //這個current不放properties中是因為properties中的屬性隻會初始化一次,而這裡需要動态改變
    showDialog(current){
      that.setData({
        isShow: true
      })
      var currentindex = 0
      //篩選出預設選擇項目
      that.data.years.forEach(function(v,i,s){
        if(current == v){
          currentindex = i
        }
      })
      that.setData({
        [`value[0]`] : currentindex,
        year: that.data.years[currentindex],
        current: current
      })
	  //先向下移動dialog高度,然後恢複原位進而形成從下向上彈出效果
      that.animation.translateY(that.data.dialogh).translateY(0).step()
      that.setData({animation: that.animation.export()})
    },
    cancel(){
      //綁定cancel事件
      this.triggerEvent("cancel")
      that.dimsss()
    },
    dimsss(){
      //從原位向下移動dailog高度,形成從上向下的收起效果
      that.animation.translateY(that.data.dialogh).step()
      that.setData({animation: that.animation.export()})
      //動畫結束後蒙層消失
      setTimeout(() => {
        that.setData({
          isShow: false
        })
     }, 300)
    },
    lefttap(){
      //綁定lefttap事件
      this.triggerEvent("lefttap")
      that.dimsss()
    },
    righttap(){
      //綁定righttap事件
      this.triggerEvent("righttap",{
        year: that.data.year
      })
      that.dimsss()
    }
  }
})

           

樣式

.mask {
  position: fixed;
  width: 100%;
  height: 100%;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: flex;
  background-color: rgba(0,0,0,0.7);
  z-index: 9999;
  flex-direction: column;
  justify-content: flex-end;
 }

 .content {
  display: flex;
  flex-direction: column;
  width: 100%;
  background: white;
  border-top-right-radius: 20rpx;
  border-top-left-radius: 20rpx;
}

.top {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  height: 100rpx;
  border-bottom: 1rpx solid #d3cfcf;
}

.top-text {
  font-size: 30rpx;
  width: 150rpx;
  height: 100rpx;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

.top-left-color {
  color: #878787;
}

.top-left-color-hover {
  color: #f1eaea;
}

.top-right-color {
  color: #1296DB;
}

.top-right-color-hover {
  color: #82ccf3;
}

.item {
  width: 100%;
  align-items: center;
  justify-content: center;
  display: flex;
  flex-direction: row;
  font-size: 35rpx;
}

           

使用姿勢

json中引用元件:

"usingComponents": {
    "custom-picker":"../component/datepickerview/datepickerview"
  }
           

布局檔案:

<button bindtap="showpicker">自定義picker</button>
<custom-picker id="custom-picker" start="2018" end="2020" bind:lefttap='_lefttap' bind:righttap='_righttap' bindcancel="_cancel"/>
           

js檔案:

const app = getApp()
var that
Page({
  data: {
    current: 2019
  },
  onLoad: function () {
    that = this
  },
  onReady: function () {
    that.picker = that.selectComponent("#custom-picker")
  },
  showpicker(){
    that.picker.showDialog(that.data.current)
  },
  _lefttap(){
    wx.showToast({
      title: '左邊按鈕被點選',
      icon: 'none'
    })
  },
  _righttap(e){
    var year = e.detail.year
    wx.showToast({
      title: '右邊按鈕被點選,選擇的值為:'+year,
      icon: 'none'
    })
    //儲存選擇的年份
    that.setData({
      current:year
    })
  },
  _cancel(){
    wx.showToast({
      title: 'picker被取消',
      icon: 'none'
    })
  }
})

           

最終效果圖:

微信小程式自定義picker前言實作使用姿勢代碼擷取尾巴

代碼擷取

如果你想要擷取完整代碼

請戳↓↓↓↓

點選用微信開發者工具打開

尾巴

這裡還是要吐槽下微信小程式的API設計,這麼一個簡單的API都沒有提供給開發者,為了這麼一個小功能還得自己整一個picker。不過雖然折騰了下,我怎麼覺得自定義的這個picker比官方的更好看,哈哈。

微信小程式自定義picker前言實作使用姿勢代碼擷取尾巴

文章中關鍵位置已經做好注釋,如果有問題歡迎留言。

老規矩,喜歡我的文章,歡迎素質三連:點贊,評論,關注,謝謝大家!