效果图如下:
代码:
/**
* Created by SharkMarine on 2017/10/31
*/
(function () {
var item_default;
var selectDate;
var selectNode;//选中的年月日用于滚动
var curMonthDayCount;//某年某月有多少天
var preTouch;
//==========立体效果参数============begin====
var ITEM_SPACE_Y = 40;//子项之间的y间距
var ITEM_SCALE_Y = 0.4;//scaleY
var ITEM_POS_X = 10;//x坐标的缩进
var ITEM_SKEW_X = 40;//倾斜度
var ITEM_OPACITY = 0.5;//透明度
//==========立体效果参数============begin====
DatePicker = cc.Layer.extend({
daySpace: 0,
jsBind: {
_event: {
updateGuildInfo: function (data) {
var guildid = data.guildid;
// 玩家被踢出群删除此界面
if (guildid == jsclient.datepicker.guildid) {
if (jsclient.datepicker) {
jsclient.datepicker.removeFromParent(true);
jsclient.datepicker = null;
}
}
}
},
block: {
_layout: [[1, 1], [0.5, 0.5], [0, 0], true]
},
back: {
_layout: [[911 / 1280, 0], [0.5, 0.45], [0, 0]],
close: {
_click: function (btn) {
selectNode = null;
jsclient.datepicker.removeFromParent();
delete jsclient.datepicker;
}
},
btn_sure: {
_click: function (btn) {
if (jsclient.datepicker) {
var pDestString = jsclient.datepicker.getSelectDate();
// 把日期文字写到按钮上
if (jsclient.datepicker.callback) {
jsclient.datepicker.callback(pDestString);
}
jsclient.datepicker.removeFromParent();
delete jsclient.datepicker;
}
}
},
item_default: {
_visible: false,
_run: function () {
this.ignoreContentAdaptWithSize(true);
item_default = this;
}
},
Panel: {
_run: function () {
var children = this.getChildren();
for (var i = 0; i < children.length; i++) {
var pChild = children[i];
if (pChild.getName() == "year" || pChild.getName() == "month" || pChild.getName() == "day") {
pChild.addTouchEventListener(function (sender, type) {
switch (type) {
case ccui.Widget.TOUCH_BEGAN:
case ccui.Widget.TOUCH_MOVED:
selectNode = sender;
break;
case ccui.Widget.TOUCH_ENDED:
case ccui.Widget.TOUCH_CANCELED:
selectNode = null;
break;
}
}, pChild);
}
}
}
}
}
},
ctor: function (callback, guildid) {
this._super();
if (jsclient.datepicker) {
jsclient.datepicker.removeFromParent();
}
selectNode = null;
jsclient.datepicker = this;
jsclient.datepicker.guildid = guildid;
jsclient.datepicker.callback = callback;
var jNode = ccs.load("res/DatePicker.json");
jsclient.datepicker.jNode = jNode.node;
ConnectUI2Logic(jNode.node, this.jsBind);
this.addChild(jNode.node);
},
onEnter: function () {
this._super();
//this.scheduleUpdate();
cc.eventManager.addListener(jsclient.datepicker.getTouchListener(this), -1);
//初始化
this.initScrollItems();
},
initScrollItems: function () {
var Panel = getChildByNameOverWrite(this.jNode, "Panel");
var year = Panel.getChildByName("year");
var month = Panel.getChildByName("month");
var day = Panel.getChildByName("day");
initScrollItem(year);
initScrollItem(month);
initScrollItem(day);
selectDate = jsclient.datepicker.getCurrentDate();
function initScrollItem(target) {
var curDate = new Date();
var suffix;
var pName = target.getName();
var suffixIndex = -1;
var date;
switch (pName) {
case "year":
suffix = "年";
suffixIndex = 0;
date = curDate.getFullYear();
break;
case "month":
suffix = "月";
suffixIndex = 1;
date = curDate.getMonth() + 1;
break;
case "day":
suffix = "日";
suffixIndex = 2;
date = curDate.getDate();
//date = jsclient.datepicker.getPreDate(-8);
break;
}
// 刷新当前月的天数
if (suffixIndex == 2) {
curMonthDayCount = jsclient.datepicker.getDayNumForMonth(curDate.getFullYear(),curDate.getMonth()+1);
}
var pSize = target.getContentSize();
//默认初始化8个元素
for (var i = 8; i >= 0; i--) {
var pItem = item_default.clone();
pItem.setName("item_" + i);
var pText = pItem.getChildByName("text");
var pTag = date + i - 4;
pText.setString(date + i - 4 + suffix);
// 验证 月 和 日的合法性,不能为负数
if (suffixIndex == 1) {
if (pTag > 12) {
pTag = pTag % 12;
pText.setString(pTag + suffix);
}
else if (pTag <= 0) {
pTag = 12 - Math.abs(pTag);
pText.setString(pTag + suffix);
}
}
else if (suffixIndex == 2) {
if (pTag > curMonthDayCount) {
pTag = pTag % curMonthDayCount;
pText.setString(pTag + suffix);
}
else if (pTag <= 0) {
pTag = curMonthDayCount - Math.abs(pTag);
pText.setString(pTag + suffix);
}
}
pText.setTag(pTag);
pItem.setTag(i);
pItem.visible = true;
pItem.setPositionY((i - 4) * ITEM_SPACE_Y + pSize.height / 2);
jsclient.datepicker.setItemCommonAttribute(pSize, pItem, suffixIndex);
if (i == 4) {
pText.setColor(cc.color(146, 78, 42));
}
else {
pText.setColor(cc.color(229, 211, 173));
}
target.addChild(pItem);
}
}
},
setItemCommonAttribute: function (pSize, pItem, suffixIndex) {
var topY = pSize.height + ITEM_SPACE_Y;
var bottomY = -ITEM_SPACE_Y;
var pText = pItem.getChildByName("text");
var delta = Math.abs(pItem.getPositionY() - pSize.height / 2) / (topY - pSize.height / 2);
pItem.setScaleY(1 - ITEM_SCALE_Y * delta);
pText.setOpacity(255 * (1 - ITEM_OPACITY * delta));
if (suffixIndex == 0) {
pText.setTextHorizontalAlignment(cc.TEXT_ALIGNMENT_LEFT);
pItem.setPositionX(pSize.width / 2 + ITEM_POS_X * delta);
pItem.setSkewX(-ITEM_SKEW_X / 2 + ITEM_SKEW_X * (pItem.getPositionY() - bottomY) / (topY - bottomY));
}
else if (suffixIndex == 1) {
pItem.setPositionX(pSize.width / 2);
pText.setTextHorizontalAlignment(cc.TEXT_ALIGNMENT_CENTER);
}
else if (suffixIndex == 2) {
pItem.setPositionX(pSize.width / 2 - (ITEM_POS_X) * delta);
pText.setTextHorizontalAlignment(cc.TEXT_ALIGNMENT_RIGHT);
}
},
adaptItems: function (target, spaceY, isEnd) {
if (!target) return;
var pSize = target.getContentSize();
var topY = pSize.height + ITEM_SPACE_Y;
var bottomY = -ITEM_SPACE_Y;
var children = target.getChildren();
var selectNode = null;
var suffix;
var pName = target.getName();
var suffixIndex = -1;
switch (pName) {
case "year":
suffix = "年";
suffixIndex = 0;
break;
case "month":
suffix = "月";
suffixIndex = 1;
break;
case "day":
suffix = "日";
suffixIndex = 2;
break;
}
for (var i = children.length - 1; i >= 0; i--) {
var pItem = children[i];
var pText = pItem.getChildByName("text");
var targetPY = pItem.getPositionY() + spaceY;
if (targetPY > topY) {
targetPY = (bottomY + (targetPY - topY));
var preItem = target.getChildByTag(((pItem.getTag() + 1) % children.length));
var pTextTag = preItem.getChildByName("text").getTag() - 1;
if (suffixIndex == 1) {
// 月份判断
if (pTextTag == 0) {
pTextTag = 12;
}
}
else if (suffixIndex == 2) {
if (pTextTag <= 0) {
pTextTag = curMonthDayCount;
}
}
pText.setString(pTextTag + suffix);
pText.setTag(pTextTag);
}
else if (targetPY < bottomY) {
targetPY = topY + (targetPY - bottomY);
var preItem = target.getChildByTag((pItem.getTag() + children.length - 1) % children.length);
var pTextTag = preItem.getChildByName("text").getTag() + 1;
if (suffixIndex == 1) {
// 月份判断
if (pTextTag > 12) {
pTextTag = 1;
}
}
else if (suffixIndex == 2) {
if (pTextTag > curMonthDayCount) {
pTextTag = 1;
}
}
pText.setString(pTextTag + suffix);
pText.setTag(pTextTag);
}
pItem.setPositionY(targetPY);
if (isEnd == true) {
if (!selectNode) {
selectNode = pItem;
}
else {
if (Math.abs(targetPY - pSize.height / 2) < Math.abs(selectNode.getPositionY() - pSize.height / 2)) {
selectNode = pItem;
}
}
}
jsclient.datepicker.setItemCommonAttribute(pSize, pItem, suffixIndex);
}
if (isEnd && selectNode) {
var isMonthDayCountChanged = false;
var pSpaceY = pSize.height / 2 - selectNode.getPositionY();
// 设置色值
for (var i = 0; i < children.length; i++) {
var pItem = children[i];
var pText = pItem.getChildByName("text");
if (pItem.getName() == selectNode.getName()) {
pText.setColor(cc.color(146, 78, 42));
// 更新选中的年月日
selectDate[suffixIndex] = pText.getTag();
//当年和月发生变化时刷新day的列表项
if (suffixIndex < 2) {
// 判断对应年月下对应的当月的天数
var pMonthDayCount = curMonthDayCount;
var curDate = new Date(selectDate[0], selectDate[1], 0);
pMonthDayCount = jsclient.datepicker.getDayNumForMonth(curDate.getFullYear(), curDate.getMonth()+1);
// 天数不一样
if (pMonthDayCount != curMonthDayCount) {
isMonthDayCountChanged = true;
curMonthDayCount = pMonthDayCount;
}
}
}
else {
pText.setColor(cc.color(229, 211, 173));
}
}
// 改变年或月后,重置天数显示
if (suffixIndex < 2 && isMonthDayCountChanged) {
var panelDay = getChildByNameOverWrite(target.getParent(), "day");
var pDayChildren = panelDay.getChildren();
var selectIndexForDay = null;
for (var i = 0; i < pDayChildren.length; i++) {
var pItem = pDayChildren[i];
var pText = pItem.getChildByName("text");
if (pText.getTag() == selectDate[2]) {
selectIndexForDay = pItem.getTag();
break;
}
}
if (selectDate[2] > curMonthDayCount) {
selectDate[2] = curMonthDayCount;
}
for (var i = 4; i >= -4; i--) {
var pIndex = (9 + i + selectIndexForDay) % 9;
var pItem = panelDay.getChildByTag(pIndex);
//var pName =pItem.getName();
var pText = pItem.getChildByName("text");
var pTag = selectDate[2] + i;
pText.setString(pTag + "日");
if (pTag > curMonthDayCount) {
pTag = pTag % curMonthDayCount;
}
else if (pTag <= 0) {
pTag = curMonthDayCount - Math.abs(pTag);
}
pText.setString(pTag + "日");
pText.setTag(pTag);
}
}
this.adaptItems(target, pSpaceY);
}
},
getCurrentDate: function () {
var now = new Date();
var year = now.getFullYear(); //年
var month = now.getMonth() + 1; //月
var day = now.getDate(); //日
var date = [year, month, day];
return date;
},
getDayNumForMonth: function (year, month) {
var curDate = new Date(year, month, 0);
return curDate.getDate();
},
_handlePressLogic: function (touch) {
this._startRecordSlidAction();
this._bePressed = true;
},
_handleMoveLogic: function (spaceY, selectNode) {
if (!selectNode) {
return;
}
this.adaptItems(selectNode, spaceY);
},
_handleReleaseLogic: function (touch) {
this._endRecordSlidAction();
this._bePressed = false;
},
_startRecordSlidAction: function () {
if (this._autoScroll)
this._stopAutoScrollChildren();
this._slidTime = 0.0;
},
_endRecordSlidAction: function () {
if (!this._checkNeedBounce() && this.inertiaScrollEnabled) {
if (this._slidTime <= 0.016)
return;
var totalDis = 0, dir;
var touchEndPositionInNodeSpace = this.convertToNodeSpace(this._touchEndPosition);
var touchBeganPositionInNodeSpace = this.convertToNodeSpace(this._touchBeganPosition);
switch (this.direction) {
case ccui.ScrollView.DIR_VERTICAL :
totalDis = touchEndPositionInNodeSpace.y - touchBeganPositionInNodeSpace.y;
dir = (totalDis < 0) ? ccui.ScrollView.SCROLLDIR_DOWN : ccui.ScrollView.SCROLLDIR_UP;
break;
case ccui.ScrollView.DIR_HORIZONTAL:
totalDis = touchEndPositionInNodeSpace.x - touchBeganPositionInNodeSpace.x;
dir = totalDis < 0 ? ccui.ScrollView.SCROLLDIR_LEFT : ccui.ScrollView.SCROLLDIR_RIGHT;
break;
case ccui.ScrollView.DIR_BOTH :
var subVector = cc.pSub(touchEndPositionInNodeSpace, touchBeganPositionInNodeSpace);
totalDis = cc.pLength(subVector);
dir = cc.pNormalize(subVector);
break;
default:
dir = cc.p(0, 0);
break;
}
var orSpeed = Math.min(Math.abs(totalDis) / (this._slidTime), ccui.ScrollView.AUTO_SCROLL_MAX_SPEED);
this._startAutoScrollChildrenWithOriginalSpeed(dir, orSpeed, true, -1000);
this._slidTime = 0;
}
},
update: function (dt) {
if (this._autoScroll)
this._autoScrollChildren(dt);
if (this._bouncing)
this._bounceChildren(dt);
this._recordSlidTime(dt);
},
_stopAutoScrollChildren: function () {
this._autoScroll = false;
this._autoScrollOriginalSpeed = 0;
this._autoScrollAddUpTime = 0;
},
_recordSlidTime: function (dt) {
if (this._bePressed)
this._slidTime += dt;
},
_autoScrollChildren: function (dt) {
var lastTime = this._autoScrollAddUpTime;
this._autoScrollAddUpTime += dt;
if (this._isAutoScrollSpeedAttenuated) {
var nowSpeed = this._autoScrollOriginalSpeed + this._autoScrollAcceleration * this._autoScrollAddUpTime;
if (nowSpeed <= 0) {
this._stopAutoScrollChildren();
this._checkNeedBounce();
} else {
var timeParam = lastTime * 2 + dt;
var offset = (this._autoScrollOriginalSpeed + this._autoScrollAcceleration * timeParam * 0.5) * dt;
var offsetX = offset * this._autoScrollDir.x;
var offsetY = offset * this._autoScrollDir.y;
if (!this._scrollChildren(offsetX, offsetY)) {
this._stopAutoScrollChildren();
this._checkNeedBounce();
}
}
} else {
if (this._needCheckAutoScrollDestination) {
var xOffset = this._autoScrollDir.x * dt * this._autoScrollOriginalSpeed;
var yOffset = this._autoScrollDir.y * dt * this._autoScrollOriginalSpeed;
var notDone = this._checkCustomScrollDestination(xOffset, yOffset);
var scrollCheck = this._scrollChildren(xOffset, yOffset);
if (!notDone || !scrollCheck) {
this._stopAutoScrollChildren();
this._checkNeedBounce();
}
} else {
if (!this._scrollChildren(this._autoScrollDir.x * dt * this._autoScrollOriginalSpeed,
this._autoScrollDir.y * dt * this._autoScrollOriginalSpeed)) {
this._stopAutoScrollChildren();
this._checkNeedBounce();
}
}
}
},
getTouchListener: function (target) {
return {
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: false,
status: null,
onTouchBegan: function (touch, event) {
if (item_default && jsclient.datepicker) {
jsclient.datepicker._handlePressLogic(touch);
preTouch = touch.getLocation();
}
return true;
},
onTouchMoved: function (touch, event) {
if (selectNode && preTouch) {
var spaceY = cc.pSub(touch.getLocation(), preTouch);
preTouch = touch.getLocation();
jsclient.datepicker.adaptItems(selectNode, spaceY.y);
}
},
onTouchEnded: function (touch, event) {
if (selectNode && preTouch) {
var spaceY = cc.pSub(touch.getLocation(), preTouch);
jsclient.datepicker.adaptItems(selectNode, spaceY.y, true);
preTouch = null;
}
},
onTouchCancelled: function (touch, event) {
}
};
},
getSelectDate: function () {
var isValidate = true;
if (isNaN(selectDate[0])) {
isValidate = false;
}
if (isNaN(selectDate[1]) || selectDate[1] > 12 || selectDate[1] < 1) {
isValidate = false;
}
if (isNaN(selectDate[2]) || selectDate[2] > curMonthDayCount || selectDate[2] < 1) {
isValidate = false;
}
if (!isValidate) {
selectDate = this.getCurrentDate();
}
// 拼字符串
var pDestString = "" + selectDate[0];
if (selectDate[1] < 10) {
pDestString += "0" + selectDate[1];
}
else {
pDestString += selectDate[1];
}
if (selectDate[2] < 10) {
pDestString += "0" + selectDate[2];
}
else {
pDestString += selectDate[2];
}
return pDestString;
}
});
})();
注意问题:JavaScript的setMonth
如果使用不好会导致显示的日期不对,比如说2017-10-31,可能没有31日等。
问题原因:比如说curDate 为:2017-10-31
curDate.setMonth(curDate.getMonth() + 1); curMonthDayCount = jsclient.datepicker.getDayNumForMonth(curDate);
因为今天是10-31,
curDate.setMonth(curDate.getMonth() + 1);
后变为11-31,因为11月没有31号,所以日期变为12-1,导致月份直接+2。
最终导致以下方法获取的当前月的天数错误(实际上获取的是11月份的天数),同理setMonth(*,0);会导致直接跳转到上个月的最大天数,和setMonth(*,31);一样存在边界问题。
getDayNumForMonth: function (date) { var curDate = new Date(date); /* 获取当前月份 */ var curMonth = curDate.getMonth(); /* 生成实际的月份: 由于curMonth会比实际月份小1, 故需加1 */ curDate.setMonth(curMonth); /* 将日期设置为0, 这里为什么要这样设置, 我不知道原因, 这是从网上学来的 */ curDate.setDate(0); /* 返回当月的天数 */ return curDate.getDate(); }