作者:小5聊基础
简介:一只喜欢全栈方向的程序员,欢迎咨询,尽绵薄之力答疑解惑
编程原则:Write Less Do More
- 选择事件组件效果
【静态布局】
1)先设置一个父级div,宽度设置100%,高度设置30vh <br/>
vh单位,类似%分号,这里表示的是占30的视窗 <br/>
2)再设置一个父级的遮罩层div,有个技巧,就是背景样式使用rgba(0,0,0,.5) <br/>
r=red=红色,g=green=绿色,b=blue=蓝色,a=alpha=透明度,.5是0.5的简写 <br/>width:100%;height:100%;position:fixed;top:0px;left:0px;
<br/>
3)内容区域的顶部,设置两个按钮,放在左右两边,中间显示选择时间文本 <br/>
按钮可以使用左右浮动方式布局,文本直接根据父级设置的居中样式即可 <br/>
- 主框架效果
- 代码
<!--时间选择组件-->
<div style="width:100%;height:100%;position:fixed;top:0px;left:0px;background:rgba(0,0,0,.3);">
<div style="width:100%;height:30vh;background:#fff;position:absolute;bottom:0px;left:0px;">
<div style="width:100%;height:35px;line-height:35px;text-align:center;border-bottom:1px solid #ccc;">
<span style="float:left;cursor:pointer;padding:0 20px;">取消</span>
<span>选择时间</span>
<span style="float:right;cursor:pointer;padding:0 20px;">确定</span>
</div>
</div>
</div>
4)接着是关键了,设置伸缩布局,左中右,分别是年月日的选择 <br/>
display:flex;
5)时间区域的父级div,设置宽度100%,高度则使用一个css函数设置 <br/>
calc(30vh - 35px),这个非常有意思,就是整体的高度减去按钮的35px高度,剩下的就是时间区域的高度 <br/>width:100%;height:calc(30vh - 35px);display:flex;
6)年份可以设置1970~当前时间,设置多个div,父级设置overflow:auto,自动隐藏,在超出高度后自动显示滚动条,每一个年份div设置宽度100%,高度和行高30px,文本居中 <br/>
7)设置一个渐变遮罩背景 <br/>
渐变样式有浏览器兼容性问题,需要设置多个 <br/>background: linear-gradient(to bottom, #ffffff, rgba(255, 255, 255, 0), #ffffff);
8)由于渐变遮罩层默认会覆盖在时间选择上面,导致无法焦点下拉,这个时候就可以给遮罩层设置一个样式, pointer-events: none; <br/>
9)通过上面的效果,4个选项不能在焦点居中,重新调整高度<br/>
整体高度可以设置235px,35px为按钮区域高度,200px为时间选择区域高度,遮罩层自然也是设置200px高度 <br/>
- 效果
10)再给中间加上居中线框,凸显焦点<br/>
【交互设置】
1、生成年份
1)时间范围,1970~当前时间 <br/>
2)给年div设置class=year-div <br/>
3)设置一个选项模板,for循环生成年份选项,将html值追加到年份div里 <br/>
- 效果
- 代码
// 生成年份
function createYear() {
var timeSelectTemplate = $("#timeSelectTemplate").html().trim();
var html_year = '';
var start_year = 1970;
var min_year = new Date().getFullYear();
for (var i = min_year; i >= start_year; i--) {
var dom = $(timeSelectTemplate);
dom.html(i);
html_year += dom.prop('outerHTML');
}
$(".year-div").html(html_year);
}
createYear();
4)到这里虽然解决年份选项生成,但是通过滚动条下拉,发现不能让第一个时间值下拉到中间焦点,显然不能满足这个需求,这个时候可以通过样式3D转换样式transform: translate3d <br/>
5)通过改变三维坐标的y轴的值来实现年份的选中 <br/>
transform: translate3d(0,0,0); 修改Y轴值得时候,记得一定要加上px单位,否则可能无效 <br/>
6)
2、生成月份
1)逻辑比较简单,直接就是1~12即可 <br/>
// 生成月份
function createMonth() {
var timeSelectTemplate = $("#timeSelectTemplate").html().trim();
var html_month = '';
var start_month = 1;
var max_month = 12;
for (var i = start_month; i <= max_month; i++) {
var dom = $(timeSelectTemplate);
dom.html((i < 10 ? ('0' + i) : i));
html_month += dom.prop('outerHTML');
}
$(".month-div").html(html_month);
}
createMonth();
3、生成具体天数
1)具体是多少天,需要年份和月份来决定 <br/>
2)最小值28天,最大值31天,还有29天(闰年)、以及30天 <br/>
3)获取一个月有多少天,这里有个小技巧 <br/>
function getMonthDay(year, month) {
var days = new Date(year, month + 1, 0).getDate()
return days
}
4)根据获取到的天数,循环生成即可 <br/>
5)设置默认值,1995-01-01,效果如下 <br/>
【移动端移动事件】
1)在PC电脑端,可以通过鼠标时间,mousedown、mousemove、mouseup来实现移动 <br/>
2)在phone移动端,可以通过触碰事件,touchstart、touchmove、touchend <br/>
var div = document.querySelector('div.year-div');
div.addEventListener('touchstart', function (event){
var event = event || window.event;
console.log(event.touches[0]);
});
3)参数说明 <br/>
clientX:触摸目标在视口中的x坐标。
clientY:触摸目标在视口中的y坐标。
identifier:标识触摸的唯一ID。
pageX:触摸目标在页面中的x坐标。
pageY:触摸目标在页面中的y坐标。
screenX:触摸目标在屏幕中的x坐标。
screenY:触摸目标在屏幕中的y坐标。
target:触目的DOM节点目标。
4)这里只需要关注Y轴的值,定义开始触碰的Y值变量以及移动点Y值得差值变量 <br/>
5)当离开触点时,根据40的倍数和总移动Y值计算,让年份选中值,显示在居中位置,会有一个滑动的效果
<br/>
为什么时40的倍数,因为每个年份选项高度都是40px <br/>
animate动画方法不支持对transform样式设置效果,可以在回调函数进行设置
var unit_count = Math.round(moveTotalY / 40);
$(".year-div").animate({}, 300, function () {
$(".year-div").css({ "transform": "translate3d(0," + unit_count * unit + "px,0)" });
});
6)滑动年份和月份时,需要重新计算天数
【主要知识点列表】
编号 | 语言或插件 | 知识点 | 说明 |
---|---|---|---|
1 | jQUery | $(dom).animatie() | 动画方法,元素样式从一个状态到另一个状态的变化 |
2 | js | touchstart | 触碰开始点 |
3 | js | touchmove | 触碰移动点 |
4 | js | touchend | 触碰结束,离开 |
【完整代码】
以下代码仅供参考,对组件感兴趣的小伙伴可以精简代码
<!--时间选择组件-->
<div class="text-no-select" style="width:100%;height:100%;position:fixed;top:0px;left:0px;background:rgba(0,0,0,.3);">
<div style="width:100%;height:235px;background:#fff;position:absolute;bottom:0px;left:0px;">
<div style="width:100%;height:35px;line-height:35px;text-align:center;border-bottom:1px solid #333;">
<span style="float:left;cursor:pointer;padding:0 20px;">取消</span>
<span>选择时间</span>
<span style="float:right;cursor:pointer;padding:0 20px;">确定</span>
</div>
<div style="width:100%;height:200px;display:flex;overflow: hidden;">
<div class="year-div" style="width:100%;height:auto;transform: translate3d(0,0,0);">
</div>
<div class="month-div" style="width:100%;height:auto;transform: translate3d(0,0,0);">
</div>
<div class="day-div" style="width:100%;height:auto;transform: translate3d(0,0,0);">
</div>
</div>
<!--居中焦点线框-->
<div style="width:100%;height:40px;position:absolute;bottom:80px;left:0px;pointer-events: none;border-top:1px solid #ccc;border-bottom:1px solid #ccc;"></div>
<!--遮罩-->
<div style="width:100%;height:200px;position:absolute;bottom:0px;left:0px;pointer-events: none;
background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), color-stop(rgba(255, 255, 255, 0)), to(#ffffff));
background: -webkit-linear-gradient(top, #ffffff, rgba(255, 255, 255, 0), #ffffff);
background: linear-gradient(to bottom, #ffffff, rgba(255, 255, 255, 0), #ffffff);"></div>
</div>
</div>
<!--日期选项模板-->
<script type="text/template" id="timeSelectTemplate">
<div data-value="" style="width:100%;height:40px;line-height:40px;text-align:center;">
<span>2022</span>
</div>
</script>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
// =====全局参数=====
var year_value = 1995;
var month_value = 1;
var day_value = 1;
var moveYearTotalY = 0;
var moveMonthTotalY = 0;
var moveDayTotalY = 0;
var unit = 40;
// 生成年份
function createYear() {
var timeSelectTemplate = $("#timeSelectTemplate").html().trim();
var html_year = '';
var start_year = 1970;
var min_year = new Date().getFullYear();
for (var i = min_year; i >= start_year; i--) {
var dom = $(timeSelectTemplate);
dom.html(i);
dom.attr("data-value", i);
html_year += dom.prop('outerHTML');
}
$(".year-div").html(html_year);
//设置默认值
var unit_count = year_value - min_year;
moveYearTotalY = (unit_count + 2) * unit;
$(".year-div").css({ "transform": "translate3d(0," + moveYearTotalY + "px,0)" });
}
createYear();
// 生成月份
function createMonth() {
var timeSelectTemplate = $("#timeSelectTemplate").html().trim();
var html_month = '';
var start_month = 1;
var max_month = 12;
for (var i = start_month; i <= max_month; i++) {
var dom = $(timeSelectTemplate);
dom.html((i < 10 ? ('0' + i) : i));
dom.attr("data-value", i);
html_month += dom.prop('outerHTML');
}
$(".month-div").html(html_month);
//设置默认值
moveMonthTotalY = 2 * unit;
$(".month-div").css({ "transform": "translate3d(0," + moveMonthTotalY + "px,0)" });
}
createMonth();
// 生成天数
function createDay() {
var timeSelectTemplate = $("#timeSelectTemplate").html().trim();
var html_day = '';
var start_day = 1;
var max_day = getMonthDay(year_value, month_value);
for (var i = start_day; i <= max_day; i++) {
var dom = $(timeSelectTemplate);
dom.html((i < 10 ? ('0' + i) : i));
dom.attr("data-value", i);
html_day += dom.prop('outerHTML');
}
$(".day-div").html(html_day);
//设置默认值
moveDayTotalY = 2 * unit;
$(".day-div").css({ "transform": "translate3d(0," + moveDayTotalY + "px,0)" });
}
createDay();
function getMonthDay(year, month) {
var days = new Date(year, month, 0).getDate()
return days
}
// =====滑动事件=====
// 滑动时间 - 年份
function moveYear() {
var name = '.year-div';
var startY = 0;
var valueY = 0;
var div = document.querySelector(name);
div.addEventListener('touchstart', function (event) {
var event = event || window.event;
var touches = event.touches[0];
startY = touches.clientY;
});
div.addEventListener('touchmove', function (event) {
var event = event || window.event;
var touches = event.touches[0];
valueY = touches.clientY - startY + moveYearTotalY;
$(name).css({ "transform": "translate3d(0," + valueY + "px,0)" });
});
div.addEventListener('touchend', function () {
if (valueY == 0) return;
moveYearTotalY = valueY;
var unit_count = Math.round(moveYearTotalY / unit);
$(name).animate({}, 300, function () {
$(name).css({ "transform": "translate3d(0," + unit_count * unit + "px,0)" });
});
});
}
moveYear();
// 滑动时间 - 月份
function moveMonth() {
var name = '.month-div';
var startY = 0;
var valueY = 0;
var div = document.querySelector(name);
div.addEventListener('touchstart', function (event) {
var event = event || window.event;
var touches = event.touches[0];
startY = touches.clientY;
});
div.addEventListener('touchmove', function (event) {
var event = event || window.event;
var touches = event.touches[0];
valueY = touches.clientY - startY + moveMonthTotalY;
$(name).css({ "transform": "translate3d(0," + valueY + "px,0)" });
});
div.addEventListener('touchend', function (event) {
if (valueY == 0) return;
moveMonthTotalY = valueY;
var unit_count = Math.round(moveMonthTotalY / unit);
$(name).animate({}, 300, function () {
var _y = unit_count * unit;
if (_y > 80) _y = 80;
$(name).css({ "transform": "translate3d(0," + _y + "px,0)" });
});
});
}
moveMonth();
// 滑动时间 - 天数
function moveDay() {
var name = '.day-div';
var startY = 0;
var valueY = 0;
var div = document.querySelector(name);
div.addEventListener('touchstart', function (event) {
var event = event || window.event;
var touches = event.touches[0];
startY = touches.clientY;
});
div.addEventListener('touchmove', function (event) {
var event = event || window.event;
var touches = event.touches[0];
valueY = touches.clientY - startY + moveDayTotalY;
$(name).css({ "transform": "translate3d(0," + valueY + "px,0)" });
});
div.addEventListener('touchend', function (event) {
if (valueY == 0) return;
moveDayTotalY = valueY;
var unit_count = Math.round(moveDayTotalY / unit);
$(name).animate({}, 300, function () {
var _y = unit_count * unit;
if (_y > 80) _y = 80;
$(name).css({ "transform": "translate3d(0," + _y + "px,0)" });
});
});
}
moveDay();
});
</script>