微信小程式自定義picker
- 前言
- 實作
-
- 蒙層
- 底部内容
- 内容頂部
- picker
- 布局實作
- js實作
- 樣式
- 使用姿勢
- 代碼擷取
- 尾巴
前言
之前UI丢了一張類似這樣的效果圖(當然這個是本文的效果圖,不是原圖,不過差不多)給我:
當時看到圖就想這個還不簡單,直接使用picker就行了。然後就是一頓操作,選擇mode為date,最終出現了效果圖:
正當我沉浸在完成功能的喜悅中的時候,心裡有個聲音一直在提醒我:你沒有達到UI需求效果,你沒有達到UI需求效果,你沒有達到UI需求效果…
定睛一看果然和UI效果圖有些許差別,UI左上角顯示的是【全部】,而我們現在是【取消】,頂部是圓角,而我們現在是直角。第二個問題影響顯然比第一個問題影響小,我們直接通過微信提供的picker相關API把左上角的字修改成【全部】勉強也能用,那我們就去檢視下相關API。
查遍picker這貨的所有API,竟然不支援修改左上角的文字。然後我們會妥協,讓UI把這個全部功能去掉或者移動到其他地方麼?不,這輩子都不可能妥協,程式猿永不為奴!!!既然這樣,那我們就自己來實作個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'
})
}
})
最終效果圖:
代碼擷取
如果你想要擷取完整代碼
請戳↓↓↓↓
點選用微信開發者工具打開
尾巴
這裡還是要吐槽下微信小程式的API設計,這麼一個簡單的API都沒有提供給開發者,為了這麼一個小功能還得自己整一個picker。不過雖然折騰了下,我怎麼覺得自定義的這個picker比官方的更好看,哈哈。
文章中關鍵位置已經做好注釋,如果有問題歡迎留言。
老規矩,喜歡我的文章,歡迎素質三連:點贊,評論,關注,謝謝大家!