|
看完官方的(de)文檔介(jie)紹(shao)后,就想找個簡(jian)單的(de)例子(zi)來驗證實現一下(xia),TodoList MVC就很好(hao)了(le),簡(jian)單容易。 之前都(dou)用JQ、Backbone、vue簡單擼過,大概功能如(ru)下:
根據(ju)以上功能,小程序完成如下(xia): GitHub:
下面記錄一下我的完成過程:下載(zai)小(xiao)程序開(kai)發(fa)工具(ju):開(kai)發(fa)者工具(ju)下載(zai) 安裝完成后,使用微信掃(sao)(sao)一掃(sao)(sao)登錄(lu),選好(hao)文件夾后創建即可,開(kai)發工具會自動生成以下目錄(lu): pages/ app.js app.json app.wxss 文錄紹構和(he)具體(ti)配(pei)置(zhi)查看官方文檔: mp.weixin.qq.com/debug/wxado… 基本配置由于平時開發(fa)習(xi)慣用(yong)Less,如果在直接(jie)使用(yong)小(xiao)程(cheng)序(xu)的(de)wxss來編寫的(de)話,就恢復原生編寫方式,大大的(de)不便,所以直接(jie)使用(yong)了gulp來實(shi)時編譯Less,和修改文件(jian)名為wxss。小(xiao)程(cheng)序(xu)開發(fa)工(gong)具是不支持Less,直接(jie)用(yong)vscode來開發(fa),小(xiao)程(cheng)序(xu)開發(fa)工(gong)具是用(yong)實(shi)時預覽(lan)和調試即(ji)可,vscode也(ye)有豐(feng)富的(de)插件(jian)支待小(xiao)程(cheng)序(xu)語法(fa)提示(shi)。
// gulpfile.js
var gulp = require('gulp')
var less = require('gulp-less')
var plumber = require('gulp-plumber')
var rename = require('gulp-rename')
gulp.task('less', function () {
return gulp.src('./app.less')
.pipe(plumber()) // 錯誤處理
.pipe(less()) // 編譯less
.pipe(rename((path) => path.extname = '.wxss')) // 編譯后生成文件修改后綴為.wxss
.pipe(gulp.dest('./'));
});
gulp.watch('./app.less', ['less']); // 實時監控app.less文件變化,運行任務
UI組件(jian)也直接引用了(le)小程序(xu)支持的 weui-wxss @import "./weui.wxss"; 在app.json定義好小(xiao)程(cheng)序頁面路由和配色:
{
"pages":[
"pages/index/index"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#ca2100",
"navigationBarTitleText": "TodoList",
"navigationBarTextStyle":"white"
}
}
頁面開發頁(ye)(ye)面(mian)文件(jian)都存放(fang)在(zai)pages/目(mu)錄下,每個(ge)功能頁(ye)(ye)面(mian)都會創建一個(ge)文件(jian)夾,TodoList現只需一個(ge)頁(ye)(ye)面(mian)完(wan)成即可 數(shu)據綁定(ding)使用 Mustache 語法(雙大括號)將變量包起來
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
<!-- 三元運算 -->
<text class="{{status === '1'?'active':''}}" data-status="1" bindtap="showStatus">全部</text>
添加todo使用字(zi)段(duan) addShow 來(lai)判斷添加(jia)輸(shu)入層顯示隱藏即可 input輸出(chu)框(kuang)這里不是雙向綁定,所(suo)以(yi)這里添加一個事件 bindinput="setInput" 來賦值實時變(bian)化
<view class="addForm {{addShow?'':'hide'}}">
<view class="addForm-div">
<input class="weui-input" placeholder="請輸入todo" value="{{addText}}" bindinput="setInput" focus="{{focus}}" />
<view class="addForm-btn">
<button class="weui-btn mini-btn" type="warn" bindtap="addTodo" size="mini">確定添加</button>
<button class="weui-btn mini-btn" type="default" bindtap="addTodoHide" size="mini">取消</button>
</view>
</view>
</view>
實時賦值事件處理(li)
setInput: function (e) {
this.setData({
addText: e.detail.value
})
}
取消時(shi),需(xu)要(yao)清空input的(de)值,input里(li)需(xu)要(yao)綁定(ding) value="{{addText}}"
Page({
data:{
//...
},
//...
addTodoHide: function () {
this.setData({
addShow: false, // 控制添加輸入面板隱藏
focus: false, // 失去焦點
addText: '' // 清空值
})
}
//...
})
添加(jia)todo
Page({
data:{
//...
},
//...
addTodo: function () {
// 檢查有沒有輸入
if (!this.data.addText.trim()) {
return
}
var temp = this.data.lists // 取出lists
var addT = {
id: new Date().getTime(), // 取當前時間
title: this.data.addText,
status: '0'
}
temp.push(addT) // 添加新的todo
this.showCur(temp) // 處理當前狀態的方法
this.addTodoHide() // 添加成功后,隱藏添加面板方法
wx.setStorage({ // 小程序異步緩存
key:"lists",
data: temp
})
wx.showToast({ // weui toast組件
title: '添加成功!',
icon: 'success',
duration: 1000
});
}
//...
})
列表部分scroll-view內滾動 列(lie)表渲染,事件觸發,利(li)用data傳參,bind綁定事件
<scroll-view class="lists" scroll-y>
<!-- 判斷列表是否為空 -->
<block wx:if="{{curLists.length < 1}}">
<view class="nodata">暫無數據</view>
</block>
<!-- 列表渲染 -->
<view class="item" wx:for="{{curLists}}" wx:key="index">
<!-- 內容view,綁定touch三個件事,來實現滑動冊除 -->
<view class="content" style="{{item.txtStyle}}" data-index="{{index}}" bindtouchstart="touchS" bindtouchmove="touchM" bindtouchend="touchE">
<!-- checkbox圖標,changeTodo事件來控制狀態切換 -->
<icon class="icon-small" type="{{item.status === '0'?'circle':'success'}}" size="23" data-item="{{item.id}}" bindtap="changeTodo"></icon>
<text class="title {{item.status === '1'?'over':''}}">{{item.title}}</text>
<!-- api.formatTime是使用了wxs模塊化編寫的模塊 -->
<text class="time">{{api.formatTime(item.id)}}</text>
</view>
<!-- 刪除按鈕,綁定刪除事件 -->
<view class="del" data-item="{{item.id}}" bindtap="delTodo"><text>刪除</text></view>
</view>
</scroll-view>
滑動刪除效果:當向左(zuo)(zuo)滑(hua)動(dong)(dong)時(shi),content跟隨手指像左(zuo)(zuo)移動(dong)(dong),同時(shi)右(you)側(ce)出(chu)現del按鈕(niu);當滑(hua)動(dong)(dong)距離大(da)于(yu)(yu)按鈕(niu)寬度一半(ban)松(song)開手指時(shi)自動(dong)(dong)滑(hua)動(dong)(dong)到(dao)左(zuo)(zuo)側(ce)顯示出(chu)按鈕(niu),小于(yu)(yu)一半(ban)時(shi)自動(dong)(dong)回到(dao)原來的位置,隱藏按鈕(niu)。 實現思路:content和(he)del按(an)鈕分別是絕(jue)對定位,利用(yong)z-index層來控(kong)制(zhi)讓(rang)content來蓋住del,當content向左滑動時(shi),del按(an)鈕就會露出來。 微信(xin)小程序api提供的touch對象和3個有關手(shou)指觸(chu)摸的函數(touchstart,touchmove,touchend)來實現content隨手(shou)指移動
詳細api說明,請查看: mp.weixin.qq.com/debug/wxado… 列表的content已(yi)綁定(ding)這個三個事件: bindtouchstart="touchS" bindtouchmove="touchM" bindtouchend="touchE" 實現方法: 注(zhu)意(yi) txtStyle ,在(zai)content在(zai)綁定這個屬性的(de),實現跟隨手指(zhi)移動的(de) style="{{item.txtStyle}}" delBtnWidth 為(wei)了(le)del按鈕的寬度,這里以rpx為(wei)單位
Page({
data:{
//...
},
//...
touchS: function (e) {
// console.log('開始:' + JSON.stringify(e))
// 是否只有一個觸摸點
if(e.touches.length === 1){
this.setData({
// 觸摸起始的X坐標
startX: e.touches[0].clientX
})
}
},
touchM: function (e) {
// console.log('移動:' + JSON.stringify(e))
var _this = this
if(e.touches.length === 1){
// 觸摸點的X坐標
var moveX = e.touches[0].clientX
// 計算手指起始點的X坐標與當前觸摸點的X坐標的差值
var disX = _this.data.startX - moveX
// delBtnWidth 為右側按鈕區域的寬度
var delBtnWidth = _this.data.delBtnWidth
var txtStyle = ''
if (disX == 0 || disX < 0){ // 如果移動距離小于等于0,文本層位置不變
txtStyle = 'left:0'
} else if (disX > 0 ){ // 移動距離大于0,文本層left值等于手指移動距離
txtStyle = 'left:-' + disX + 'rpx'
if(disX >= delBtnWidth){
// 控制手指移動距離最大值為刪除按鈕的寬度
txtStyle = 'left:-' + delBtnWidth + 'rpx'
}
}
// 獲取手指觸摸的是哪一個item
var index = e.currentTarget.dataset.index;
var list = _this.data.curLists
// 將拼接好的樣式設置到當前item中
list[index].txtStyle = txtStyle
// 更新列表的狀態
this.setData({
curLists: list
});
}
},
touchE: function (e) {
// console.log('停止:' + JSON.stringify(e))
var _this = this
if(e.changedTouches.length === 1){
// 手指移動結束后觸摸點位置的X坐標
var endX = e.changedTouches[0].clientX
// 觸摸開始與結束,手指移動的距離
var disX = _this.data.startX - endX
var delBtnWidth = _this.data.delBtnWidth
// 如果距離小于刪除按鈕的1/2,不顯示刪除按鈕
var txtStyle = disX > delBtnWidth/2 ? 'left:-' + delBtnWidth + 'rpx' : 'left:0'
// 獲取手指觸摸的是哪一項
var index = e.currentTarget.dataset.index
var list = _this.data.curLists
list[index].txtStyle = txtStyle
// 更新列表的狀態
_this.setData({
curLists: list
});
}
}
//...
})
WXS實現時間格式實現在(zai)效(xiao)果如下:
這里我使用小(xiao)程序(xu)的WXS WXS(WeiXin Script)是小(xiao)程序的一套腳本語言(yan),結合 WXML,可以構建出(chu)頁(ye)面的結構。了解(jie)詳細 新(xin)建一個(ge)api.wxs文件,然(ran)后在index.wxml引用(yong),定義模塊名即(ji)可引用(yong):
<!-- index.wxml -->
<wxs src="./api.wxs" module="api" />
...
<text class="time">{{api.formatTime(item.id)}}</text>
每個(ge) wxs 模塊均有一個(ge)內置的(de) module 對象 api.wxs文(wen)件(jian)和時間(jian)格(ge)式(shi)實現方法:
var formatTime = function(time){
// 獲取當前時間
var getUnix = function () {
var date = getDate()
return date.getTime()
}
// 獲取今天零點時間
var getTodayUnix = function () {
var date = getDate()
date.setHours(0)
date.setMinutes(0)
date.setSeconds(0)
date.setMilliseconds(0)
return date.getTime()
}
// 獲取今年的1月1日零點時間
var getYearUnix = function () {
var date = getDate()
date.setMonth(0)
date.setDate(1)
date.setHours(0)
date.setMinutes(0)
date.setSeconds(0)
date.setMilliseconds(0)
return date.getTime()
}
// 獲取標準時間
var getLastDate = function (time) {
var date = getDate(time)
var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
var day = date.getDay() < 10 ? '0' + (date.getDay()) : date.getDay()
return date.getFullYear() + '-' + month + '-' + day
}
// 轉換時間
var getFormatTime = function (timestamp) {
var now = getUnix()
var today = getTodayUnix()
var year = getYearUnix()
var timer = (now - timestamp) / 1000
var tip = ''
if (timer <= 0) {
tip = '剛剛'
} else if (Math.floor(timer / 60) <= 0) {
tip = '剛剛'
} else if (timer < 3600) {
tip = Math.floor(timer / 60) + '分鐘前'
} else if (timer >= 3600 && (timestamp - today >= 0)) {
tip = Math.floor(timer / 3600) + '小時前'
} else if (timer / 86400 <= 31) {
tip = Math.ceil(timer / 86400) + '天前'
} else {
tip = getLastDate(timestamp)
}
return tip
}
return getFormatTime(+time)
}
// es6方法一樣,導出formatTime方法
module.exports.formatTime = formatTime;
這里需要(yao)注意的是獲(huo)取當前時間,WXS是不(bu)支持(chi) new Date() ,它有(you)自己(ji)本身的方法 getDate() 。使用(yong)方法跟 new Date() 一樣。 至此已完成,TodoList實踐例子,功能簡單,入(ru)門好(hao)例子。 希望(wang)對大家(jia)有幫助,不足的地方請大家(jia)指點,剛(gang)啃完官(guan)方文檔擼(lu)的例子(zi)。 |