前言
github地址:https://github.com/yexiaochai/wxdemo
这里来说一说我们的理念,我们也学习小程序开发有一周多了,从近期的使用上来说,小程序可以作为底层,但是缺少一个框架层,这个框架层需要提供:
① 组件库
② 更好的代码组织方式,也就是让我们可以做到轻松的组件化开发
我们从最开始到现在,都在沿着这个方向去分解小程序学习,其实小程序本身的东西差不多了,但是我们代码过程中有时候却越高越复杂,多了很多封装,其实这所有的复杂都是为了设置一个基本的架构,一个标准的开发模式,让后面写业务代码的同学能更高效的写代码,经过一年多的发展,事实上这种较为成熟的框架已经有了,比如我们正在使用的:
https://tencent.github.io/wepy/
但是,可以看到小程序基本还是原生JS,这其实是个非常好的学习整理机会,所以我这边一步步和大家对小程序进行了拆分,期望能形成一套还能用的雏形,帮助大家理解,所以我们继续今天的学习吧,为了降低单页面难度,我们将首页进行下改造。
首页
首页做了一点改造,变成了这个样式了:
这里需要三个点击时间点,因为日历组件,我们昨天就做好了,而他这个出发日期事实上就是我们日历组件的selecedDate,处理这块逻辑:
1 <template name="searchbox"> 2 <view class="c-row search-line" data-flag="start"> 3 <view class="c-span3"> 4 出发</view> 5 <view class="c-span9 js-start search-line-txt"> 6 请选择出发地</view> 7 </view> 8 <view class="c-row search-line" data-flag="arrive"> 9 <view class="c-span3"> 10 到达</view> 11 <view class="c-span9 js-arrive search-line-txt"> 12 请选择到达地</view> 13 </view> 14 <view class="c-row search-line" data-flag="arrive"> 15 <view class="c-span3"> 16 出发日期</view> 17 <view class="c-span9 js-arrive search-line-txt"> 18 {{calendarSelectedDate || \'请选择出发日期\'}} </view> 19 </view> 20 <view class="c-row " data-flag="arrive"> 21 <span class="btn-primary full-width js_search_list">查询</span> 22 </view> 23 </template>
1 <view class="c-row search-line" data-flag="arrive"> 2 <view class="c-span3"> 3 出发日期</view> 4 <view class="c-span9 js-arrive search-line-txt"> 5 {{calendarSelectedDate || \'请选择出发日期\'}} </view> 6 </view>
点击时候我们弹出我们的日历,这个时候我们日历模块释放一个事件显示日历:
PS:template不与页面级别WXML共享一个作用域,所以我暂时都采用的include引入
1 <view class="c-row search-line" data-flag="start"> 2 <view class="c-span3"> 3 出发</view> 4 <view class="c-span9 js-start search-line-txt"> 5 请选择出发地</view> 6 </view> 7 <view class="c-row search-line" data-flag="arrive"> 8 <view class="c-span3"> 9 到达</view> 10 <view class="c-span9 js-arrive search-line-txt"> 11 请选择到达地</view> 12 </view> 13 <view class="c-row search-line" data-flag="arrive" ontap="showCalendar"> 14 <view class="c-span3"> 15 出发日期</view> 16 <view class="c-span9 js-arrive search-line-txt"> 17 {{calendarSelectedDateStr}}</view> 18 </view> 19 <view class="c-row " data-flag="arrive"> 20 <span class="btn-primary full-width js_search_list">查询</span> 21 </view> 22 <include src="./mod/calendar.wxml" /> 23 <include src="../../utils/abstract-page.wxml" />
1 <view class="c-row search-line" data-flag="arrive" ontap="showCalendar"> 2 <view class="c-span3"> 3 出发日期</view> 4 <view class="c-span9 js-arrive search-line-txt"> 5 {{calendarSelectedDateStr}}</view> 6 </view>
1 /* 2 事实上一个mod就只是一个对象,只不过为了方便拆分,将对象分拆成一个个的mod 3 一个mod对应一个wxml,但是共享外部的css,暂时如此设计 4 所有日历模块的需求全部再此实现 5 */ 6 const util = require(\'../../../utils/util.js\') 7 8 let selectedDate = new Date(); 9 10 module.exports = { 11 showCalendar: function () { 12 this.setData({ 13 isCalendarShow: \'\' 14 }); 15 }, 16 onCalendarDayTap: function (e) { 17 let data = e.detail; 18 var date = new Date(data.year, data.month, data.day); 19 console.log(date) 20 this.setData({ 21 calendarSelectedDate: date, 22 calendarSelectedDateStr: util.dateUtil.format(date, \'Y年M月D日\') 23 }); 24 }, 25 data: { 26 isCalendarShow: \'none\', 27 calendarDisplayMonthNum: 2, 28 calendarDisplayTime: new Date(), 29 calendarSelectedDate: selectedDate, 30 calendarSelectedDateStr: util.dateUtil.format(selectedDate, \'Y年M月D日\') 31 } 32 }
显然,这里的日历这样摆设有点丑,我们这里将其封装成一个弹出层,所以我们这里再做一个容器类组件,专门用于装载页面样式用:
1 <view class="cm-modal " style="z-index: {{uiIndex}}; position: fixed; display: {{isShow}}; "> 2 <slot ></slot> 3 </view> 4 <view class="cm-overlay" bindtap="onMaskEvent" style="z-index: {{maskzIndex}}; display: {{isShow}}" > 5 </view>
1 <ui-container bindonContainerHide="onContainerHide" is-show="{{isCalendarShow}}" > 2 <view class="calendar-wrapper-box"> 3 <view class="box-hd"> 4 <text class="fl icon-back js_back "></text> 5 <text class="fr icon-next js_next"></text> 6 </view> 7 <ui-calendar bindonDayTap="onCalendarDayTap" displayTime="{{calendarDisplayTime}}"
selectedDate="{{calendarSelectedDate}}" displayMonthNum="{{calendarDisplayMonthNum}}"
is-show="{{isCalendarShow}}"></ui-calendar> 8 </view> 9 </ui-container>
但是这里也引起了其他问题,因为引入了shadow-dom概念,我的样式不能重用,组件内部样式与外部是不能通信的,但是这里是页面级别容器,内容的样式肯定是来源页面的,这里没什么问题,所以我们这里显示的是正确的,但是我这里想做一个出格一点的操作,我想用样式将这里日历月标题换个位置:
而日历组件和外部是不能通信的,我们这里该如何处理呢,我这里想了两个方案:
① 设置一个全局使用的组件库样式,让所有组件继承,但是不知道这里对性能是否有影响,因为这样的话体积不会太小
② 小程序设计了可以传入组件的方法,比如我们这里的日历组件我们可以这样改变其样式
1 .calendar-cm-month { 2 position: absolute; 3 top: 0; 4 height: 90rpx; 5 line-height: 90rpx; 6 width: 100%; 7 color: #00b358; 8 text-align: center; 9 }
1 Component({ 2 externalClasses: [\'ex-class\'], 3 behaviors: [ 4 View 5 ], 6 properties: { 7 displayMonthNum: { 8 type: Number 9 }, 10 displayTime: { 11 type: Date 12 }, 13 selectedDate: { 14 type: Date 15 } 16 }, 17 data: { 18 weekDayArr: [\'日\', \'一\', \'二\', \'三\', \'四\', \'五\', \'六\'], 19 }, 20 21 attached: function () { 22 //console.log(this) 23 // debugger 24 }, 25 methods: { 26 onDayTap: function (e) { 27 this.triggerEvent(\'onDayTap\', e.currentTarget.dataset) 28 } 29 } 30 })
1 <ui-container bindonContainerHide="onContainerHide" is-show="{{isCalendarShow}}" > 2 <view class="calendar-wrapper-box"> 3 <view class="box-hd"> 4 <text class="fl icon-back js_back "></text> 5 <text class="fr icon-next js_next"></text> 6 </view> 7 <ui-calendar ex-class="calendar-cm-month" bindonDayTap="onCalendarDayTap"
displayTime="{{calendarDisplayTime}}" selectedDate="{{calendarSelectedDate}}"
displayMonthNum="{{calendarDisplayMonthNum}}" is-show="{{isCalendarShow}}"></ui-calendar> 8 </view> 9 </ui-container>
具体各位去github上查看,总而言之,我们的页面变成了这个样子了:
PS:这里发现一个不知道是不是坑点的点,我们这里属性传递的是一个date对象,但是到了组件层之间变成了对象,不知微信底层做了什么:
calendarDisplayTime: new Date()
好像变成了一个空对象,这里可能发生的情况是,经过传递的日期对象会被某种特殊处理,但是具体发生了什么事情就不知道了,这个却引起了我们不小的麻烦,这里大概去翻开了一下源码:
极有可能,小程序本身就不支持date属性的传递,我们的日历组件能跑起来的原因是什么,我这里都有点疑惑了......
而且就算以对象方式传递到组件的date类型都会变成莫名其妙的东西:
1 ttt: { 2 key: \'date\', 3 value: selectedDate 4 },
这个特性有点令人抓不住头脑了,这里根据探查,很有可能Component将date对象传入WXML解释时候,自动转为了日期字符串了,所以我们这里看上去是对象的东西其实是字符串,这里的建议是:跟组件的date传递,暂时全部使用字符串代替,以免自我麻烦,然后我们先将之前的日历操作全部变成字符串,再为我们的前后按钮加上事件:
1 module.exports = { 2 showCalendar: function () { 3 this.setData({ 4 isCalendarShow: \'\' 5 }); 6 }, 7 hideCalendar: function () { 8 this.setData({ 9 isCalendarShow: \'none\' 10 }); 11 }, 12 preMonth: function () { 13 14 this.setData({ 15 calendarDisplayTime: util.dateUtil.preMonth(this.data.calendarDisplayTime).toString() 16 }); 17 }, 18 nextMonth: function () { 19 this.setData({ 20 calendarDisplayTime: util.dateUtil.nextMonth(this.data.calendarDisplayTime).toString() 21 }); 22 }, 23 onCalendarDayTap: function (e) { 24 let data = e.detail; 25 var date = new Date(data.year, data.month, data.day); 26 console.log(date) 27 this.setData({ 28 isCalendarShow: \'none\', 29 calendarSelectedDate: date.toString(), 30 calendarSelectedDateStr: util.dateUtil.format(date, \'Y年M月D日\') 31 }); 32 }, 33 onContainerHide: function () { 34 this.hideCalendar(); 35 }, 36 37 data: { 38 ttt: { 39 key: \'date\', 40 value: selectedDate 41 }, 42 isCalendarShow: \'\', 43 calendarDisplayMonthNum: 1, 44 calendarDisplayTime: new Date(2018, 9).toString(), 45 calendarSelectedDate: selectedDate, 46 calendarSelectedDateStr: util.dateUtil.format(new Date(selectedDate), \'Y年M月D日\') 47 } 48 }
虽然看上去恶心了一点,但是总是不会出什么明显的问题,忍一忍吧......日期部分基本结束了,还有些小的限制没有做上,比如哪些时段能选,哪些不能,这块就有待各位发现吧,我们这里毕竟是学习,做细了很花功夫,我们接下来做出发目的地选择部分。
数据请求
城市列表
城市列表这里看起来需要新开一个页面,但是我这里想做在一个页面中,考虑篇幅,我们使用弹出层容器组件看并且尽量削弱一些特性,几天下来别说写的还有些累......
这个又作为首页的一个模块而存在:
1 <view style="display: {{isCityShow}}; " class="city-wrapper" > 2 <view class="city-list"> 3 <view class="list-name">A</view> 4 <view class="list-item">成都</view> 5 <view class="list-item">成都</view> 6 <view class="list-item">成都</view> 7 <view class="list-item">成都</view> 8 <view class="list-item">成都</view> 9 <view class="list-item">成都</view> 10 </view> 11 <view class="city-list"> 12 <view class="list-name">A</view> 13 <view class="list-item">成都</view> 14 <view class="list-item">成都</view> 15 <view class="list-item">成都</view> 16 <view class="list-item">成都</view> 17 <view class="list-item">成都</view> 18 <view class="list-item">成都</view> 19 </view> 20 </view>
1 /* 2 事实上一个mod就只是一个对象,只不过为了方便拆分,将对象分拆成一个个的mod 3 一个mod对应一个wxml,但是共享外部的css,暂时如此设计 4 所有日历模块的需求全部再此实现 5 */ 6 const util = require(\'../../../utils/util.js\') 7 8 let selectedDate = new Date().toString(); 9 10 module.exports = { 11 showCitylist: function (e) { 12 let flag = e.currentTarget.dataset.flag; 13 14 if(flag === \'start\') { 15 16 } else { 17 18 } 19 }, 20 //用于设置城市数据 21 setCityData: function (data) { 22 23 }, 24 showCity: function () { 25 this.setData({ 26 isCityShow: \'\' 27 }); 28 }, 29 shideCity: function () { 30 this.setData({ 31 isCityShow: \'none\' 32 }); 33 }, 34 data: { 35 isCityShow: \'\' 36 } 37 }
首页调用代码:
1 //获取公共ui操作类实例 2 const _page = require(\'../../utils/abstract-page.js\'); 3 let modCalendar = require(\'./mod/calendar.js\'); 4 let modCity = require(\'./mod/city.js\'); 5 6 //获取应用实例 7 const app = getApp() 8 9 Page(_page.initPage({ 10 data: { 11 }, 12 // methods: uiUtil.getPageMethods(), 13 methods: { 14 }, 15 onShow: function () { 16 global.sss = this; 17 let scope = this; 18 }, 19 onLoad: function () { 20 // this.setPageMethods(); 21 } 22 }, { 23 modCalendar: modCalendar, 24<
请发表评论