每月2个小小项目——JS+CSS3实现动态时钟

此博客介绍了如何使用HTML、CSS和JavaScript实现一个动态时钟,将时间显示为数字滚动效果。通过设置元素的布局、样式和透明度,使数字逐位滚动展示当前时间。涉及知识点包括DOM操作、定时器、CSS过渡效果和透明度控制。

目录

 

项目实现图片GIF

项目思想

详细版(带大量解释)

HTML代码

CSS代码

JS代码

完整版(代码简洁,在原型链上编写,不带解释)

HTML代码:

CSS代码:

JS代码:


项目实现图片GIF

 

项目思想

首先将数字分为6列加2个引号,完成想像图中的排列(每一列设置inline-block属性,然后设置顶部对齐),然后我们再将2个引号垂直居中,并通过setInterval()方法获得实时的时间,把更新的时间处理成字符串,例如16:29:05,我们处理为162905然后依次取出每一位,把他和图片中对应的那一列中的数字进行对应,即把那一列中对应的数字居中对齐就行了。

详细版(带大量解释)

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link rel="stylesheet" href="dynamicClock.css">
	<script src="https://www.jq22.com/jquery/jquery-3.3.1.js"></script>
</head>
<body>
	<div class="wrapper">
		<div class="column">
			<div>0</div>
			<div>1</div>
			<div>2</div>
		</div>
		<div class="column ten"></div>
		<div class="colon">:</div>
		<div class="column six"></div>
		<div class="column ten"></div>
		<div class="colon">:</div>
		<div class="column six"></div>
		<div class="column ten"></div>
	</div>
	<script src="dynamicClock.js"></script>
</body>
</html>

CSS代码

*{
	margin: 0;
	padding: 0;
}
.wrapper{
/*	border: 5px solid pink;*/
	text-align: center;
}
.column,
.colon{
	display: inline-block;
	vertical-align: top;
	/*基于顶部对齐,不设置的话默认每列是底部对齐,然后向上把容器撑开,而底部的位置我们在居中的时候是不好计算的,所以我们这里设置向上对齐;*/
	font-size: 80px;
	line-height: 80px;
}
.colon{
	transform: translateY(calc(50vh - 40px));
	/*
	1.设置居中,用其他方法会脱离文档流,这样的话会和数字重叠
	2.1vh代表你现在屏幕高度的1%,同理1vw代表你现在屏幕宽度的1%
	3.clac()可以把计算完的像素值返回,这里注意-40px不能连写,-号和30px之间要有空格,不然会翻译为负号而不是减号,而2个数字无法计算。
	4.transform:none|transform-functions,常用的函数有translate()、scale()、rotate()、skew()等,我们这里用的translateY相当于在Y轴方平移
	*/
}
.opacity0{
	opacity: 1;
}
.opacity1{
	opacity: 0.5;
}
.opacity2{
	opacity: 0.4;
}
.opacity3{
	opacity: 0.25;
}
.opacity4{
	opacity: 0.1;
}
.opacity5{
	opacity: 0;
}
.wrapper{
	overflow: hidden;
	width: 100%;
}
.column{
	transition: all 300ms ease-in;
	/*设置过度的内容、总时长以及过度的方法;*/
}

JS代码

//透明度的等级数列,在setOpacityClass函数中使用,用于设置不同类别的透明度。
var  opacityName = ['opacity0','opacity1','opacity2','opacity3','opacity4','opacity4','opacity4','opacity4','opacity4','opacity5']
// 创建0-9或0-5加入每一列中
function joinTime(){
	for (var i = 0; i < 10; i++) {
		var number = '<div>' + i + '</div>';
		$('.ten').append(number);
		// $(选择器1).append(字符串),相当于把字符串添加到选择器1的每个doom节点
		// $(选择器1).append(选择器2),相当于把选择器2中的所有doom节点剪切后加入选择器1中的每个doom节点中
		// $(选择器1).append(function(index,html){}),相当于把函数中返回的数据加入选择器1的每个doom节点中,选择器1中有几个doom节点就会执行几次,
		// 每次对应一个index和html,index对应选择1中正在添加的doom节点的序号,是从0开始的,而html是该doom节点下所有的内容,是字符串的形式
	}
	for (var i = 0; i < 6; i++) {
		var number = '<div>' + i + '</div>';
		$('.six').append(number);
	}
}
joinTime();
//每隔一段时间得到最新的时间,并更新到网页中
setInterval(function(){
	// setInterval(code,milliseconds,arg1,arg2...args),code代表js中的代码或函数,代码的话用字符串的形式传递,注意有双重引号需要用单引号括双引号,或反的,milliseconds代表毫秒数,
	//args代表传输的参数,可以写多个,会传入code中函数中,例如code写成function(a,b,c,d....){}则a,b,c...会依次与arg1,arg2,arg3...结合,也可以使用arguments查看使用。
	//每过多少毫秒调用code中的内容,注意code中直接写F()而不加引号,会立即执行,且只执行1次,因为他要当做js中的代码需要加引号,要当做函数需要去掉()号。
	var time = new Date();
	var hours = time.getHours(),
		seconds = time.getSeconds(),
		minutes = time.getMinutes();
	// console.log(hours+':'+minutes+':'+seconds);
	var standardTime = timeString(hours, seconds ,minutes ,true)//更改为false为12小时。
	// console.log(standardTime);
	achieveTime(standardTime, $('.column'));//传document.getElementsByClassName('column')也行。
},200);
//将hours,seconds,minutes传入,有些的可能需要添加0,得到符合规范的字符串我们设置2种返回结果,1种是24小时制,1种是12小时制。
function timeString(hours, seconds, minutes,is24Hours){
	// 方法1
	// if(is24Hours){
	// 	//返回24小时制的时间,处理hours,minutes,seconds如果小于10我们在前面加个‘0’
	// 	if(hours < 10){
	// 		hours = '0' + hours; 
	// 	}else{
	// 		hours += '';
	// 	}
	// 	if (minutes < 10) {
	// 		minutes = '0' + minutes;
	// 	}else{
	// 		minutes += '';
	// 	}
	// 	if (seconds < 10) {
	// 		seconds = '0' + seconds;
	// 	}else{
	// 		seconds += '';
	// 	}
	// }else{
	// 	//返回12小时制的,将hours%12,后再判断小于10即可,这里就不写了,可以把方法1注释了,直接用方法2.
	// }
	// var timeS = hours + minutes + seconds;
	//方法2
	timeS = [is24Hours ? hours : hours % 12 || 12,minutes,seconds].reduce(function(p, n){
		return p + ('0' + n).slice(-2);
	});
	// arr.reduce(function(total, currentValue, index, array){return},initialValue) 该函数叫累加器,
	// 函数根据执行arr.length次,第一次total的值为initialValue,currentValue,index对应arr[0]和0,而array始终对应arr不变,然后return的值返回第二次的total中,
	// 再执行一遍函数以此类推,最后把return的值返回给total的值后,再将total返回,这也是为什么当arr.length=1时,
	// 我们写入initialValue的值后返回结果为undefined,所以我们使用时注意一定要定义return的值,如果没有定义的话每次会将undefined返回total。
	// 参数中只有total和current是必须定义的,然后在不写initialValue时,该函数的total值默认为arr[0]的,index、currentValue的值都会从第二个数开始,即index为1。
	// 还有1种特殊情况,即arr.length=1时,如果不定义initialValue的值,那么该函数直接返回arr[0],不会运行function内的代码。

	// String/Array.slice(start,end) 
	// 该函数将数组或字符串的[start]——[end-1]位返回成一个数组或字符串,参数可以填负数,加上length转换为正数后计算,可以不写end,表示从[strat]选到尾,还可以都不写,
	// 会将内容完全返回,注意返回的是浅拷贝,即如果数组的内容包含引用,他复制的是引用。最后该函数是不改变原数组和字符串的
	// timeS = timeS.length == 6 ? timeS : '0' + timeS;
	return timeS.length == 6 ? timeS : '0' + timeS
	// p初始为数组第一位,n为数组的第二位,加完后的值再赋予p,n为数组的第三位。最后返回累加成果。如果小时为0,可能出现5位数的情况。
}
function achieveTime(standardTime, elem){
	// Array.from(object,mapFunction(value,index){return},thisValue)方法用于通过拥有length属性的对象或可迭代的对象来返回一个数组,常用于类数组转化为数组。
	// object是要转换为数组的对象是必填的,其他可以不填,mapFunction是object数组中每个数需要执行的函数,执行object.length次,每次value代表当前的值即object[index],
	// index代表当前的索引号,每次的最后会将return语句中的值返回给自身即object[index],thisValue代表的是mapFunction运行过程中的this指向,默认为window。
	Array.from(elem).forEach(function(ele,index){
		//array.forEach(function(currentValue, index, arr),thisValue);数组中每个元素都执行一遍function。
		//其中只有currentValue为必选,函数共执行array.length次,每次currentValue=array[index],index从0到length-1,arr===Array,thisValue同Array.from中的一样,无论是否有return都无返回值。
		var offset = standardTime[index] * 80;
		$(ele).css({
			'transform' : 'translateY(calc(50vh - ' + offset + 'px - 40px))'
		});
		// 相当于把每一列的0都居中对齐了,然后把每一列对应的时间取出来,乘以数字的高度,向下平移即得到了当前的时间,注意字符串拼接时,可以先写式子再用字符串符号分割开来,不然特容易出错。
		setOpacityClass(ele, standardTime[index]);
	});
}
//给1列中的数字设置不同的类名来对应透明度。
function setOpacityClass(ele, n){
	Array.from(ele.children).forEach(function(ele2, index2){
		// 方法1
		//注意.children是document上的方法,.attr()是jquer上的方法
		// if(n > index2){
		// 	$(ele2).attr('class',opacityName[n - index2]);
		// }else{
		// 	$(ele2).attr('class',opacityName[index2 - n]);
		// }
		//方法2
		//判断index2和n之间是否距离为index。
		$(ele2).attr('class',opacityName.find(function(ele, i){
		return index2-i === (+n) || index2 + i === (+n);
		//注意我们的n不能直接比较,需要转换为数字类型
		}));
		//array.find(function(currentValue, index, arr),thisValue),对每个array数组中的值执行一遍function,返回array[index]的值,参数作用都和array.Each中的相同
		
	});
}

_____________________________________________________________________________________________________________________

完整版(代码简洁,在原型链上编写,不带解释)

HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="demo.css">
	<script src="https://www.jq22.com/jquery/jquery-3.3.1.js"></script>
	<title>Document</title>
</head>
<body>
	<div class="wrapper">
			<div class="column">
				<div>0</div>
				<div>1</div>
				<div>2</div>
			</div>
			<div class="column ten" ></div>
			<div class="coln">:</div>
			<div class="column six"></div>
			<div class="column ten"></div>
			<div class="coln">:</div>
			<div class="column six"></div>
			<div class="column ten"></div>
	</div>
	<script src="demo.js"></script>
</body>
</html>

CSS代码:

*{
	margin: 0;
	padding: 0;
}
body{
	background-color: #0e141b;
	overflow: hidden;
}
.wrapper{
	width: 100%;
	text-align: center;
}
.wrapper .column,
.wrapper .coln{
	display: inline-block;
	color: rgba(224,230,235,0.89);
	vertical-align: top;
	font-size: 86px;
	line-height: 86px;
	font-weight: 300;
}
.coln{
	transform: translateY(calc(50vh - 43px));
}
.column{
	transition: all 300ms ease-in;
}
.visible{
	opacity: 1;
}
.close{
	opacity: 0.35;
}
.far{
	opacity: 0.15;
}
.distance{
	opacity: 0.1;
}

JS代码:

function Index(dom,use24Hours){
	this.column = Array.from(dom);
	this.createDom();
	this.start();
	this.use24Hours = use24Hours;
	this.classList = ['visible','close','far','far','distance','distance'];
}
Index.prototype.start = function(){
	var self = this;
	setInterval(function(){
		var c = self.getClock();
		console.log(c);
		self.column.forEach(function(ele,index){
			var n = + c[index];
			var offset = n * 86;
			$(ele).css({
				'transform':'translateY(calc(50vh - '+ offset + 'px - 43px))'
			});
			Array.from(ele.children).forEach(function(ele2, index2){
				var className = self.getClass(n,index2);
				$(ele2).attr('class',className);
			})
		})
	},200);
};
Index.prototype.getClass = function(n, i){
	var className = this.classList.find(function(ele, index){
		return i-index === n || i + index === n;
	});
	return className || '';
};
Index.prototype.getClock = function(){
	var d = new Date();
	m = [this.use24Hours ? d.getHours() : d.getHours() % 12 || 12,d.getMinutes(),d.getSeconds()].reduce(function(p, n){
		return p + ('0' + n).slice(-2);
	});
	return m.length == 6 ? m : '0'+m;
};
Index.prototype.createDom = function createDom(){
	for(var i = 0; i < 6; i++){
		var oDiv='<div>' + i + '</div>';
		$('.six').append(oDiv);
	}
	for(var i = 0; i < 10; i++){
		var iDiv = '<div>' + i + '</div>';
		$('.ten').append(iDiv);
	}
};
new Index($('.column'),true);

 

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值