github地址:https://github.com/yexiaochai/wxdemo
我們這裡繼續實現我們的日曆元件,這個日曆元件稍微有點特殊,算是相對複雜的元件了,然後一般的日曆元件又會有很多的變化,所以我們這裡實現最基本的標籤即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
let View = require('behavior-view'); const util = require('../utils/util.js'); // const dateUtil = util.dateUtil; Component({ behaviors: [ View ], properties: { }, data: { weekDayArr: ['日', '一', '二', '三', '四', '五', '六'], displayMonthNum: 1, //當前顯示的時間 displayTime: null, //可以選擇的最早時間 startTime: null, //最晚時間 endTime: null, //當前時間,有時候是讀取伺服器端 curTime: new Date() }, attached: function () { //console.log(this) }, methods: { } }) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
<wxs module="dateUtil"> var isDate = function(date) { return date && date.getMonth; }; var isLeapYear = function(year) { //傳入為時間格式需要處理 if (isDate(year)) year = year.getFullYear() if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) return true; return false; }; var getDaysOfMonth = function(date) { var month = date.getMonth(); //注意此處月份要加1,所以我們要減一 var year = date.getFullYear(); return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; } var getBeginDayOfMouth = function(date) { var month = date.getMonth(); var year = date.getFullYear(); var d = getDate(year, month, 1); return d.getDay(); } var getDisplayInfo = function(date) { if (!isDate(date)) { date = getDate(date) } var year = date.getFullYear(); var month = date.getMonth(); var d = getDate(year, month); //這個月一共多少天 var days = getDaysOfMonth(d); //這個月是星期幾開始的 var beginWeek = getBeginDayOfMouth(d); /* console.log('info',JSON.stringify( { year: year, month: month, days: days, beginWeek: beginWeek })); */ return { year: year, month: month, days: days, beginWeek: beginWeek } } module.exports = { getDipalyInfo: getDisplayInfo } </wxs> <view class="cm-calendar"> <view class="cm-calendar-hd "> <block wx:for="{{weekDayArr}}"> <view class="item">{{item}}</view> </block> </view> <view class="cm-calendar-bd "> <view class="cm-month "> </view> <view class="cm-day-list"> <block wx:for="{{dateUtil.getDipalyInfo(curTime).days + dateUtil.getDipalyInfo(curTime).beginWeek}}" wx:for-index="index"> <view wx:if="{{index < dateUtil.getDipalyInfo(curTime).beginWeek }}" class="item active"></view> <view wx:else class="item">{{index + 1 - dateUtil.getDipalyInfo(curTime).beginWeek}}</view> </block> <view class=" active cm-item--disabled " data-cndate="" data-date=""> </view> </view> </view> </view> |
這個是非常簡陋的日曆雛形,在程式碼過程中有以下幾點比較痛苦:
① WXML與js間應該只有資料傳遞,根本不能傳遞方法,應該是兩個webview的通訊,而日曆元件這裡在WXML層由不得不寫一點邏輯
② 本來在WXML中寫邏輯已經不太對了,而我們引入的WXS,使用與HTML中的js片段也有很大的不同
這些問題,一度讓程式碼變得複雜,而可以看到一個簡單的元件,還沒有複雜功能,涉及到的檔案都太多了,這裡是呼叫層:
1 |
<ui-calendar is-show="" ></ui-calendar> |
事實上,我們以上資料根本不應該寫到data裡面,應該屬性傳遞,我們這裡先為了簡單實現功能,接下來我們繼續完善這個元件,具體程式碼請看git:
這個日曆元件應該是在小程式中寫的最複雜的元件了,尤其是很多邏輯判斷的程式碼都放在了WXML裡面,根據之前的瞭解,小程式渲染在一個webview中,js邏輯在一個webview中,他這樣做的目的可能是想讓效能更好,但是我這裡程式碼寫起來事實上是有點痛苦的,我們這裡開始組裝元件,將資料配置放到屬性上,開始組裝abstract-page,事實上我認為日曆這種非全域性元件本來不應該放到基類中:
① 因為Component提供的是一個標籤,而且涉及的檔案很多,加上繼承關係很不好管理
② 因為日曆元件事實上是一個標籤,所以我們會有一個引入的基礎WXML,一個使用的js,完全獨立一個檔案更加複雜
③ 本來小程式或者複雜的頁面都應該元件化開發,所以我們簡歷一個頁面級別的元件,分散到對應的頁面中
小程式像是給靈活的HTML&JS戴上了枷鎖,只允許在其允許的範圍靈活,我們這裡嘗試對頁面進行再拆分:
1 2 3 4 5 6 |
<import src="./mod.searchbox.wxml" /> <view> <template is="searchbox" /> </view> <include src="./mod/calendar.wxml"/> <include src="../../utils/abstract-page.wxml"/> |
1 2 3 4 |
<ui-calendar displayTime="{{CalendarDisplayTime}}" selectedDate="{{CalendarSelectedDate}}" displayMonthNum="{{CalendarDisplayMonthNum}}" is-show="{{isCalendarShow}}" ></ui-calendar> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* 事實上一個mod就只是一個物件,只不過為了方便拆分,將物件分拆成一個個的mod 一個mod對應一個wxml,但是共享外部的css,暫時如此設計 所有日曆模組的需求全部再此實現 */ module.exports = { q: 1, ddd: function(){}, data: { isCalendarShow: '', CalendarDisplayMonthNum: 2, CalendarDisplayTime: new Date(), CalendarSelectedDate: null } } |
核心程式碼還是在abstract-page裡面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
//pageData為頁面級別資料,mod為模組資料,要求一定不能重複 initPage(pageData, mod) { //debugger; let _pageData = {}; let key, value, k, v; //為頁面動態新增操作元件的方法 Object.assign(_pageData, this.getPageFuncs(), pageData); //生成真實的頁面資料 _pageData.data = {}; Object.assign(_pageData.data, this.getPageData(), pageData.data || {}); for( key in mod) { value = mod[key]; for(k in value) { v = value[k]; if(k === 'data') { Object.assign(_pageData.data, v); } else { _pageData[k] = v; } } } console.log(_pageData); return _pageData; } |
這裡再改造一下,我們基本的日曆元件便完成了80%了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* 事實上一個mod就只是一個物件,只不過為了方便拆分,將物件分拆成一個個的mod 一個mod對應一個wxml,但是共享外部的css,暫時如此設計 所有日曆模組的需求全部再此實現 */ module.exports = { q: 1, ddd: function(){}, onCalendarDayTap: function (e) { let data = e.detail; var date = new Date(data.year, data.month, data.day); console.log(date) this.setData({ calendarSelectedDate: date }); }, data: { isCalendarShow: '', calendarDisplayMonthNum: 2, calendarDisplayTime: new Date(), calendarSelectedDate: null } } |
至此,我們元件相關課題基本結束,接下來,我們開始我們的業務程式碼