github地址:https://github.com/yexiaochai/wxdemo
我们这里继续实现我们的日历组件,这个日历组件稍微有点特殊,算是相对复杂的组件了,然后一般的日历组件又会有很多的变化,所以我们这里实现最基本的标签即可:
1 let View = require('behavior-view'); 2 const util = require('../utils/util.js'); 3 4 // const dateUtil = util.dateUtil; 5 6 Component({ 7 behaviors: [ 8 View 9 ],10 properties: {11 12 },13 data: {14 weekDayArr: ['日', '一', '二', '三', '四', '五', '六'],15 displayMonthNum: 1,16 17 //当前显示的时间18 displayTime: null,19 //可以选择的最早时间20 startTime: null,21 //最晚时间22 endTime: null,23 24 //当前时间,有时候是读取服务器端25 curTime: new Date()26 27 },28 29 attached: function () { 30 //console.log(this)31 },32 methods: {33 34 }35 })
1 <wxs module="dateUtil"> 2 var isDate = function(date) { 3 return date && date.getMonth; 4 }; 5 6 var isLeapYear = function(year) { 7 //传入为时间格式需要处理 8 if (isDate(year)) year = year.getFullYear() 9 if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) return true;10 return false;11 };12 13 var getDaysOfMonth = function(date) {14 var month = date.getMonth(); //注意此处月份要加1,所以我们要减一15 var year = date.getFullYear();16 return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];17 }18 19 var getBeginDayOfMouth = function(date) {20 var month = date.getMonth();21 var year = date.getFullYear();22 var d = getDate(year, month, 1);23 return d.getDay();24 }25 26 var getDisplayInfo = function(date) {27 if (!isDate(date)) {28 date = getDate(date)29 }30 var year = date.getFullYear();31 32 var month = date.getMonth();33 var d = getDate(year, month);34 35 //这个月一共多少天36 var days = getDaysOfMonth(d);37 38 //这个月是星期几开始的39 var beginWeek = getBeginDayOfMouth(d);40 41 /*42 console.log('info',JSON.stringify( {43 year: year,44 month: month,45 days: days,46 beginWeek: beginWeek47 }));48 */49 50 return {51 year: year,52 month: month,53 days: days,54 beginWeek: beginWeek55 }56 }57 58 module.exports = {59 getDipalyInfo: getDisplayInfo60 }61 </wxs>62 63 64 <view class="cm-calendar">65 <view class="cm-calendar-hd ">66 <block wx:for="{{weekDayArr}}">67 <view class="item">{{item}}</view>68 </block>69 </view>70 <view class="cm-calendar-bd ">71 <view class="cm-month ">72 </view>73 <view class="cm-day-list">74 75 <block wx:for="{{dateUtil.getDipalyInfo(curTime).days + dateUtil.getDipalyInfo(curTime).beginWeek}}" wx:for-index="index">76 77 <view wx:if="{{index < dateUtil.getDipalyInfo(curTime).beginWeek }}" class="item active"></view>78 <view wx:else class="item">{{index + 1 - dateUtil.getDipalyInfo(curTime).beginWeek}}</view>79 80 </block>81 82 <view class=" active cm-item--disabled " data-cndate="" data-date="">83 84 </view>85 </view>86 </view>87 </view>
这个是非常简陋的日历雏形,在代码过程中有以下几点比较痛苦:
① WXML与js间应该只有数据传递,根本不能传递方法,应该是两个webview的通信,而日历组件这里在WXML层由不得不写一点逻辑
② 本来在WXML中写逻辑已经不太对了,而我们引入的WXS,使用与HTML中的js片段也有很大的不同
这些问题,一度让代码变得复杂,而可以看到一个简单的组件,还没有复杂功能,涉及到的文件都太多了,这里是调用层:
<ui-calendar is-show="" ></ui-calendar>
事实上,我们以上数据根本不应该写到data里面,应该属性传递,我们这里先为了简单实现功能,接下来我们继续完善这个组件,具体代码请看git:
这个日历组件应该是在小程序中写的最复杂的组件了,尤其是很多逻辑判断的代码都放在了WXML里面,根据之前的了解,小程序渲染在一个webview中,js逻辑在一个webview中,他这样做的目的可能是想让性能更好,但是我这里代码写起来事实上是有点痛苦的,我们这里开始组装组件,将数据配置放到属性上,开始组装abstract-page,事实上我认为日历这种非全局组件本来不应该放到基类中:
① 因为Component提供的是一个标签,而且涉及的文件很多,加上继承关系很不好管理
② 因为日历组件事实上是一个标签,所以我们会有一个引入的基础WXML,一个使用的js,完全独立一个文件更加复杂
③ 本来小程序或者复杂的页面都应该组件化开发,所以我们简历一个页面级别的组件,分散到对应的页面中
小程序像是给灵活的HTML&JS戴上了枷锁,只允许在其允许的范围灵活,我们这里尝试对页面进行再拆分:
1 <import src="./mod.searchbox.wxml" />2 <view>3 <template is="searchbox" />4 </view>5 <include src="./mod/calendar.wxml"/>6 <include src="../../utils/abstract-page.wxml"/>
<ui-calendar displayTime="{{CalendarDisplayTime}}"selectedDate="{{CalendarSelectedDate}}"displayMonthNum="{{CalendarDisplayMonthNum}}"is-show="{{isCalendarShow}}" ></ui-calendar>
1 /* 2 事实上一个mod就只是一个对象,只不过为了方便拆分,将对象分拆成一个个的mod 3 一个mod对应一个wxml,但是共享外部的css,暂时如此设计 4 所有日历模块的需求全部再此实现 5 */ 6 module.exports = { 7 q: 1, 8 ddd: function(){}, 9 10 data: {11 isCalendarShow: '',12 CalendarDisplayMonthNum: 2,13 CalendarDisplayTime: new Date(),14 CalendarSelectedDate: null15 }16 }
核心代码还是在abstract-page里面:
1 //pageData为页面级别数据,mod为模块数据,要求一定不能重复 2 initPage(pageData, mod) { 3 //debugger; 4 let _pageData = {}; 5 let key, value, k, v; 6 7 //为页面动态添加操作组件的方法 8 Object.assign(_pageData, this.getPageFuncs(), pageData); 9 10 //生成真实的页面数据11 _pageData.data = {};12 Object.assign(_pageData.data, this.getPageData(), pageData.data || {});13 14 for( key in mod) {15 value = mod[key];16 for(k in value) {17 v = value[k];18 if(k === 'data') {19 Object.assign(_pageData.data, v);20 } else {21 _pageData[k] = v;22 }23 }24 }25 26 console.log(_pageData);27 return _pageData;28 }
这里再改造一下,我们基本的日历组件便完成了80%了:
1 /* 2 事实上一个mod就只是一个对象,只不过为了方便拆分,将对象分拆成一个个的mod 3 一个mod对应一个wxml,但是共享外部的css,暂时如此设计 4 所有日历模块的需求全部再此实现 5 */ 6 module.exports = { 7 q: 1, 8 ddd: function(){}, 9 onCalendarDayTap: function (e) {10 let data = e.detail;11 var date = new Date(data.year, data.month, data.day);12 console.log(date)13 this.setData({14 calendarSelectedDate: date15 });16 },17 data: {18 isCalendarShow: '',19 calendarDisplayMonthNum: 2,20 calendarDisplayTime: new Date(),21 calendarSelectedDate: null22 }23 }
至此,我们组件相关课题基本结束,接下来,我们开始我们的业务代码