I am utilizing the following script from CodePen
// Create Countdown
var Countdown = {
// Backbone-like structure
$el: $('.countdown'),
// Params
countdown_interval: null,
total_seconds : 0,
// Initialize the countdown
init: function() {
// DOM
this.$ = {
hours : this.$el.find('.bloc-time.hours .figure'),
minutes: this.$el.find('.bloc-time.min .figure'),
seconds: this.$el.find('.bloc-time.sec .figure')
};
// Init countdown values
this.values = {
hours : this.$.hours.parent().attr('data-init-value'),
minutes: this.$.minutes.parent().attr('data-init-value'),
seconds: this.$.seconds.parent().attr('data-init-value'),
};
// Initialize total seconds
this.total_seconds = this.values.hours * 60 * 60 + (this.values.minutes * 60) + this.values.seconds;
// Animate countdown to the end
this.count();
},
count: function() {
var that = this,
$hour_1 = this.$.hours.eq(0),
$hour_2 = this.$.hours.eq(1),
$min_1 = this.$.minutes.eq(0),
$min_2 = this.$.minutes.eq(1),
$sec_1 = this.$.seconds.eq(0),
$sec_2 = this.$.seconds.eq(1);
this.countdown_interval = setInterval(function() {
if(that.total_seconds > 0) {
--that.values.seconds;
if(that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if(that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.total_seconds;
}
else {
clearInterval(that.countdown_interval);
}
}, 1000);
},
animateFigure: function($el, value) {
var that = this,
$top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX : '-180deg',
transformPerspective: 300,
ease : Quart.easeOut,
onComplete : function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, { rotationX: 0 });
}
});
TweenMax.to($back_top, 0.8, {
rotationX : 0,
transformPerspective: 300,
ease : Quart.easeOut,
clearProps : 'all'
});
},
checkHour: function(value, $el_1, $el_2) {
var val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if(value >= 10) {
// Animate only if the figure has changed
if(fig_1_value !== val_1) this.animateFigure($el_1, val_1);
if(fig_2_value !== val_2) this.animateFigure($el_2, val_2);
}
else {
// If we are under 10, replace first figure with 0
if(fig_1_value !== '0') this.animateFigure($el_1, 0);
if(fig_2_value !== val_1) this.animateFigure($el_2, val_1);
}
}
};
// Let's go !
Countdown.init();
我一直在努力寻找如何修改它以支持每页多个倒数计时器的方法。
到目前为止,我的方法是尝试添加一个数字计数器,以使每个“倒数”元素都具有唯一的类,然后修改脚本以在每个元素上运行,但这没有用,我认为不会。
我不确定其他方法,但是希望能得到一些帮助。
答案 0 :(得分:6)
通过将其转换为函数,只需一点重构即可创建该对象的新实例。
例如,如果您克隆<div class="countdown"/>
HTML,并在JS中调用:
new Countdown($($('.countdown')[0])).init();
new Countdown($($('.countdown')[1])).init();
或者,您也可以使用以下方法初始化页面上的所有.countdowns
:
$('.countdown').each((_, el) => (new Countdown($(el)).init()));
您将拥有两个独特的倒计时实例。
// Create Countdown
function Countdown(node) {
this.$el = node;
this.countdown_interval = null;
this.total_seconds = 0;
this.init = function() {
// DOM
this.$ = {
hours: this.$el.find('.bloc-time.hours .figure'),
minutes: this.$el.find('.bloc-time.min .figure'),
seconds: this.$el.find('.bloc-time.sec .figure')
};
// Init countdown values
this.values = {
hours: this.$.hours.parent().attr('data-init-value'),
minutes: this.$.minutes.parent().attr('data-init-value'),
seconds: this.$.seconds.parent().attr('data-init-value'),
};
// Initialize total seconds
this.total_seconds = (this.values.hours * 60 * 60) +
(this.values.minutes * 60) +
this.values.seconds;
// Animate countdown to the end
this.count();
};
this.count = function() {
let that = this,
$hour_1 = this.$.hours.eq(0),
$hour_2 = this.$.hours.eq(1),
$min_1 = this.$.minutes.eq(0),
$min_2 = this.$.minutes.eq(1),
$sec_1 = this.$.seconds.eq(0),
$sec_2 = this.$.seconds.eq(1);
this.countdown_interval = setInterval(function() {
if (that.total_seconds > 0) {
--that.values.seconds;
if (that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if (that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.total_seconds;
} else {
clearInterval(that.countdown_interval);
}
}, 1000);
};
this.animateFigure = function($el, value) {
let that = this,
$top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX: '-180deg',
transformPerspective: 300,
ease: Quart.easeOut,
onComplete: function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, {
rotationX: 0
});
}
});
TweenMax.to($back_top, 0.8, {
rotationX: 0,
transformPerspective: 300,
ease: Quart.easeOut,
clearProps: 'all'
});
};
this.checkHour = function(value, $el_1, $el_2) {
let val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if (value >= 10) {
// Animate only if the figure has changed
if (fig_1_value !== val_1) this.animateFigure($el_1, val_1);
if (fig_2_value !== val_2) this.animateFigure($el_2, val_2);
} else {
// If we are under 10, replace first figure with 0
if (fig_1_value !== '0') this.animateFigure($el_1, 0);
if (fig_2_value !== val_1) this.animateFigure($el_2, val_1);
}
}
}
// Let's go !
new Countdown($($('.countdown')[0])).init();
new Countdown($($('.countdown')[1])).init();
// Alternatively you could also initialize all countdowns on page with:
// $('.countdown').each((i, el) => (new Countdown($(el)).init()));
body {
background-color: #f2f1ed;
}
.wrap {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
margin: auto;
height: 310px;
}
a {
text-decoration: none;
color: #1a1a1a;
}
h1 {
margin-bottom: 60px;
text-align: center;
font: 300 2.25em "Lato";
text-transform: uppercase;
}
h1 strong {
font-weight: 400;
color: #ea4c4c;
}
h2 {
margin-bottom: 80px;
text-align: center;
font: 300 0.7em "Lato";
text-transform: uppercase;
}
h2 strong {
font-weight: 400;
}
.countdown {
width: 720px;
margin: 4px 0;
display: inline-block;
}
.countdown .bloc-time {
float: left;
margin-right: 45px;
text-align: center;
}
.countdown .bloc-time:last-child {
margin-right: 0;
}
.countdown .count-title {
display: block;
margin-bottom: 15px;
font: normal 0.94em "Lato";
color: #1a1a1a;
text-transform: uppercase;
}
.countdown .figure {
position: relative;
float: left;
height: 110px;
width: 100px;
margin-right: 10px;
background-color: #fff;
border-radius: 8px;
-moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
-webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}
.countdown .figure:last-child {
margin-right: 0;
}
.countdown .figure>span {
position: absolute;
left: 0;
right: 0;
margin: auto;
font: normal 5.94em/107px "Lato";
font-weight: 700;
color: #de4848;
}
.countdown .figure .top:after,
.countdown .figure .bottom-back:after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.countdown .figure .top {
z-index: 3;
background-color: #f7f7f7;
transform-origin: 50% 100%;
-webkit-transform-origin: 50% 100%;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
-moz-transform: perspective(200px);
-ms-transform: perspective(200px);
-webkit-transform: perspective(200px);
transform: perspective(200px);
}
.countdown .figure .bottom {
z-index: 1;
}
.countdown .figure .bottom:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 50%;
background-color: rgba(0, 0, 0, 0.02);
}
.countdown .figure .bottom-back {
z-index: 2;
top: 0;
height: 50%;
overflow: hidden;
background-color: #f7f7f7;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
}
.countdown .figure .bottom-back span {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.countdown .figure .top,
.countdown .figure .top-back {
height: 50%;
overflow: hidden;
-moz-backface-visibility: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.countdown .figure .top-back {
z-index: 4;
bottom: 0;
background-color: #fff;
-webkit-transform-origin: 50% 0;
transform-origin: 50% 0;
-moz-transform: perspective(200px) rotateX(180deg);
-ms-transform: perspective(200px) rotateX(180deg);
-webkit-transform: perspective(200px) rotateX(180deg);
transform: perspective(200px) rotateX(180deg);
-moz-border-radius-bottomleft: 10px;
-webkit-border-bottom-left-radius: 10px;
border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.countdown .figure .top-back span {
position: absolute;
top: -100%;
left: 0;
right: 0;
margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap">
<h1>Draft <strong>Countdown</strong></h1>
<!-- Countdown #1 -->
<div class="countdown">
<div class="bloc-time hours" data-init-value="24">
<span class="count-title">Hours</span>
<div class="figure hours hours-1">
<span class="top">2</span>
<span class="top-back">
<span>2</span>
</span>
<span class="bottom">2</span>
<span class="bottom-back">
<span>2</span>
</span>
</div>
<div class="figure hours hours-2">
<span class="top">4</span>
<span class="top-back">
<span>4</span>
</span>
<span class="bottom">4</span>
<span class="bottom-back">
<span>4</span>
</span>
</div>
</div>
<div class="bloc-time min" data-init-value="0">
<span class="count-title">Minutes</span>
<div class="figure min min-1">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
<div class="figure min min-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
<div class="bloc-time sec" data-init-value="0">
<span class="count-title">Seconds</span>
<div class="figure sec sec-1">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
<div class="figure sec sec-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
</div>
<div class="countdown">
<div class="bloc-time hours" data-init-value="4">
<span class="count-title">Hours</span>
<div class="figure hours hours-1">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
<div class="figure hours hours-2">
<span class="top">4</span>
<span class="top-back">
<span>4</span>
</span>
<span class="bottom">4</span>
<span class="bottom-back">
<span>4</span>
</span>
</div>
</div>
<div class="bloc-time min" data-init-value="30">
<span class="count-title">Minutes</span>
<div class="figure min min-1">
<span class="top">3</span>
<span class="top-back">
<span>3</span>
</span>
<span class="bottom">3</span>
<span class="bottom-back">
<span>3</span>
</span>
</div>
<div class="figure min min-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
<div class="bloc-time sec" data-init-value="30">
<span class="count-title">Seconds</span>
<div class="figure sec sec-1">
<span class="top">3</span>
<span class="top-back">
<span>3</span>
</span>
<span class="bottom">3</span>
<span class="bottom-back">
<span>3</span>
</span>
</div>
<div class="figure sec sec-2">
<span class="top">0</span>
<span class="top-back">
<span>0</span>
</span>
<span class="bottom">0</span>
<span class="bottom-back">
<span>0</span>
</span>
</div>
</div>
</div>
</div>
Here's a link to the updated codepen。
希望这会有所帮助,
答案 1 :(得分:3)
作为jQuery插件,它可以采用这种方式(您可以进一步对其进行自定义):
// Create Countdown Plugin
$.fn.fancyCountdown = function() {
return this.each(function() {
var that=this;
var $el=$(this);
that.values = {
titleHours: 'Hours',
titleMinutes: 'Minutes',
titleSeconds: 'Seconds'
};
if( $el.data('settings') ) {
that.values = $el.data('settings');
} else {
that.values = $.extend( {}, that.values, $el.data() );
};
var explodeTime = that.values.time.split(':');
that.values.hours = explodeTime[0]*1;
that.values.minutes = explodeTime[1]*1;
that.values.seconds = explodeTime[2]*1;
that.values.hours1 = explodeTime[0][0];
that.values.hours2 = explodeTime[0][1];
that.values.minutes1 = explodeTime[1][0];
that.values.minutes2 = explodeTime[1][1];
that.values.seconds1 = explodeTime[2][0];
that.values.seconds2 = explodeTime[2][1];
that.values.totalSeconds = that.values.hours*60*60 + that.values.minutes*60 + that.values.seconds;
that.values.template = '\
<span class="top">#</span>\
<span class="top-back">\
<span>#</span>\
</span>\
<span class="bottom">#</span>\
<span class="bottom-back">\
<span>#</span>\
</span>\
';
that.countdownInterval = null;
if( !$el.hasClass('countdown-engaged') ) {
$el.addClass('countdown-engaged');
// Initialize the countdown
that.init=function() {
// DOM
that.createDom();
that.$ = {
hours: $el.find('.bloc-time.hours .figure'),
minutes: $el.find('.bloc-time.min .figure'),
seconds: $el.find('.bloc-time.sec .figure')
};
// Animate countdown to the end
that.count();
};
that.createDom = function() {
var html = '\
<div class="bloc-time hours">\
<span class="count-title">' + that.values.titleHours + '</span>\
<div class="figure hours hours-1">\
' + that.values.template.replace(/#/g, that.values.hours1) + '\
</div>\
<div class="figure hours hours-2">\
' + that.values.template.replace(/#/g, that.values.hours2) + '\
</div>\
</div>\
<div class="bloc-time min">\
<span class="count-title">' + that.values.titleMinutes + '</span>\
<div class="figure min min-1">\
' + that.values.template.replace(/#/g, that.values.minutes1) + '\
</div>\
<div class="figure min min-2">\
' + that.values.template.replace(/#/g, that.values.minutes2) + '\
</div>\
</div>\
<div class="bloc-time sec">\
<span class="count-title">' + that.values.titleSeconds + '</span>\
<div class="figure sec sec-1">\
' + that.values.template.replace(/#/g, that.values.seconds1) + '\
</div>\
<div class="figure sec sec-2">\
' + that.values.template.replace(/#/g, that.values.seconds2) + '\
</div>\
</div>\
';
$el.html(html);
};
that.count = function() {
var $hour_1 = that.$.hours.eq(0),
$hour_2 = that.$.hours.eq(1),
$min_1 = that.$.minutes.eq(0),
$min_2 = that.$.minutes.eq(1),
$sec_1 = that.$.seconds.eq(0),
$sec_2 = that.$.seconds.eq(1);
that.countdownInterval = setInterval(function() {
if (that.values.totalSeconds > 0) {
--that.values.seconds;
if (that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if (that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.values.totalSeconds;
} else {
clearInterval(that.countdownInterval);
};
}, 1000);
};
that.animateFigure = function($el, value) {
var $top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX: '-180deg',
transformPerspective: 300,
ease: Quart.easeOut,
onComplete: function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, {
rotationX: 0
});
}
});
TweenMax.to($back_top, 0.8, {
rotationX: 0,
transformPerspective: 300,
ease: Quart.easeOut,
clearProps: 'all'
});
};
that.checkHour=function(value, $el_1, $el_2) {
var val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if (value >= 10) {
// Animate only if the figure has changed
if (fig_1_value !== val_1) that.animateFigure($el_1, val_1);
if (fig_2_value !== val_2) that.animateFigure($el_2, val_2);
} else {
// If we are under 10, replace first figure with 0
if (fig_1_value !== '0') that.animateFigure($el_1, 0);
if (fig_2_value !== val_1) that.animateFigure($el_2, val_1);
}
};
};
that.init();
});
};
$('.countdown').fancyCountdown();
body {
background-color: #f2f1ed;
}
.wrap {
margin: 0 auto;
height: 310px;
}
a {
text-decoration: none;
color: #1a1a1a;
}
h1 {
margin-bottom: 60px;
text-align: center;
font: 300 2.25em "Lato";
text-transform: uppercase;
}
h1 strong {
font-weight: 400;
color: #ea4c4c;
}
h2 {
margin-bottom: 80px;
text-align: center;
font: 300 0.7em "Lato";
text-transform: uppercase;
}
h2 strong {
font-weight: 400;
}
.countdown {
width: 720px;
margin: 0 auto;
}
.countdown .bloc-time {
float: left;
margin-right: 45px;
text-align: center;
}
.countdown .bloc-time:last-child {
margin-right: 0;
}
.countdown .count-title {
display: block;
margin-bottom: 15px;
font: normal 0.94em "Lato";
color: #1a1a1a;
text-transform: uppercase;
}
.countdown .figure {
position: relative;
float: left;
height: 110px;
width: 100px;
margin-right: 10px;
background-color: #fff;
border-radius: 8px;
-moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
-webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}
.countdown .figure:last-child {
margin-right: 0;
}
.countdown .figure>span {
position: absolute;
left: 0;
right: 0;
margin: auto;
font: normal 5.94em/107px "Lato";
font-weight: 700;
color: #de4848;
}
.countdown .figure .top:after,
.countdown .figure .bottom-back:after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.countdown .figure .top {
z-index: 3;
background-color: #f7f7f7;
transform-origin: 50% 100%;
-webkit-transform-origin: 50% 100%;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
-moz-transform: perspective(200px);
-ms-transform: perspective(200px);
-webkit-transform: perspective(200px);
transform: perspective(200px);
}
.countdown .figure .bottom {
z-index: 1;
}
.countdown .figure .bottom:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 50%;
background-color: rgba(0, 0, 0, 0.02);
}
.countdown .figure .bottom-back {
z-index: 2;
top: 0;
height: 50%;
overflow: hidden;
background-color: #f7f7f7;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
}
.countdown .figure .bottom-back span {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.countdown .figure .top,
.countdown .figure .top-back {
height: 50%;
overflow: hidden;
-moz-backface-visibility: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.countdown .figure .top-back {
z-index: 4;
bottom: 0;
background-color: #fff;
-webkit-transform-origin: 50% 0;
transform-origin: 50% 0;
-moz-transform: perspective(200px) rotateX(180deg);
-ms-transform: perspective(200px) rotateX(180deg);
-webkit-transform: perspective(200px) rotateX(180deg);
transform: perspective(200px) rotateX(180deg);
-moz-border-radius-bottomleft: 10px;
-webkit-border-bottom-left-radius: 10px;
border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.countdown .figure .top-back span {
position: absolute;
top: -100%;
left: 0;
right: 0;
margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap">
<h1>Draft <strong>Countdown</strong></h1>
<div class="countdown" data-time="22:30:00"></div>
</div>
<div class="wrap">
<h1>Second <strong>Countdown</strong></h1>
<div class="countdown" data-settings='{"time": "01:22:50", "titleHours": "Sati", "titleMinutes": "Minuti", "titleSeconds": "Sekunde"}'></div>
</div>
也在JSFiddle上。
答案 2 :(得分:2)
我只在外观上保留了CSS(进行了一些修改),然后将所有代码完全重写为“纯” Javascript(没有jQuery),并保留了GSAP / TweenMax库。
您可以通过填写表示标题和持续时间等的数组来放置任意数量的countDown。
只有一个setInterval处理不同的countDown,它将在最后一个活动的countDown处停止。
之所以选择此解决方案,是因为同时使用多个setInterval似乎与此不成比例,并且不必要地使OS过载。
为了获得更高的准确性,所有的countDowns都是基于系统时钟(而不是setInterval的调用周期,因为它们是“自然地”移位的,因此与任何时间测量都不兼容)。
此脚本可以执行两种类型的countDown:
-固定时间(例如鸡蛋6分钟)
-在日期(或时间)结束时(例如:生日,约会...)
此脚本的另一个好处是,它可以按需生成对页面上的countDown显示有用的html元素集,并允许选择具有所需单位数量的显示
const myCountDowns= [ { title: 'timer <strong>24h</strong>'
, type : 'Hours'
, timer: '24h'
}
, { title: 'Tea cup <strong>2\' 45"</strong>'
, type : 'Minutes'
, timer: '2m 45s'
}
, { title: 'until the new year <strong>2020</strong>'
, type : 'Days'
, date : '01 01 2020' // local Month Day Year
}
]
CountDown.BuildsAndRun( myCountDowns )
// ->type : 'Days' or 'Hours' or 'Minutes' or 'seconds'
// set "timer" for time duration otherwise set a "date" value
// timer string format is _number_UNIT where UNIT = 'd','h','m','s' for Days, Hours, Minutes, Seconds
// ex : '3d 25m 6s' = 3 days 0 hours 25 minutes, 6 seconds (days = 0, 0 is defauls for all units)
// ex : '6s 3d 25m' = the same, there is no order
// date format is JS Date format see new Date( _STRING_ )
完整代码(在下面的代码段中)
(function( CountDown )
{
// Private vars
const domEndBody = document.body.querySelector('script') || document.body // for countDowns insert place
, eWrapp = document.createElement('div')
, eTitle = document.createElement('h1')
, eCountDown = document.createElement('div')
, eTimeBlock = document.createElement('div')
, eCountTitle = document.createElement('span')
, eFigure = document.createElement('div')
, counters = [] // list of CountDowns
, one_Sec = 1000
, one_Min = one_Sec * 60
, one_Hour = one_Min * 60
, one_Day = one_Hour * 24
, padZ =(val,sz) => ('0'.repeat(sz)+val.toString(10)).slice(-sz) // return string with leading zeros
, Interface = [ { xL:8, Title:'Days', Fig:3 } // titles & counts of figures
, { xL:5, Title:'Hours', Fig:2 }
, { xL:3, Title:'Minutes', Fig:2 }
, { xL:0, Title:'Seconds', Fig:2 }
]
, animOpt = { rotationX: 0, transformPerspective: 300, ease: Quart.easeOut, clearProps: 'all' }
var activeCounters = 0
// finalize countDown elements
eWrapp.className = 'wrap'
eTitle.innerHTML = 'F<strong>D</strong>' // 'Draft <strong>Countdown</strong>'
eCountDown.className = 'countdown'
eTimeBlock.className = 'bloc-time'
eCountTitle.className = 'count-title'
eFigure.className = 'figure'
eFigure.innerHTML = '<span class="top" > </span>'
+ ' <span class="top-back" > <span> </span> </span>'
+ ' <span class="bottom" > </span>'
+ ' <span class="bottom-back"> <span> </span> </span>'
//Public Method ........................................................................
CountDown.BuildsAndRun = function( TimerArray )
{
for (let TimerParms of TimerArray)
{ CountDown_Build ( TimerParms ) }
setTimeout(() => { CountDown_Run() }, 300); // the Timeout is just for start spectacle
}
// Private Methods......................................................................
CountDown_Build = function( parms )
{
let len = parms.type==='Hours'?6:parms.type==='Minutes'?4:parms.type==='seconds'?2:9
, ctD = { lg : len // countDown number of figure (digits)
, face : ' '.repeat(len) // actuel face of countDown
, fig : [] // array of firures (DOM elements)
, ref : counters.length // ID of this countDown
, time : null // time to add to compute taget time for CountDown
, target : null // target Timie value
, activ : true // to check if count down is activ or not ( finished )
}
// generate all Figures of CountDown
for(let i=len;i--;) { // from len to 0 (just my fav ninja)
ctD.fig.push( eFigure.cloneNode(true) )
}
// CountDown DOM making
let xWrapp = eWrapp.cloneNode(true)
, xTitle = eTitle.cloneNode(true)
, xCountDown = eCountDown.cloneNode(true)
, noFig = 0 // ref on the first ctD.fig list (of figures)
xTitle.innerHTML = parms.title
xWrapp.style.width = len===9?'1105px':len===6?'740px':len===4?'485px':'230px'
//xCountDown.style.width = len===9?'1090px':len===6?'730px':len===4?'470px':'230px'
xWrapp.appendChild(xTitle)
xWrapp.appendChild(xCountDown)
// making of bloc-time elements
for(eBlk of Interface)
{
if(len>eBlk.xL)
{
let xTimeBlock = eTimeBlock.cloneNode(true)
, xCountTitle = eCountTitle.cloneNode(true)
xCountTitle.textContent = eBlk.Title
xTimeBlock.appendChild(xCountTitle)
for(let f=eBlk.Fig;f--;) // (fav ninja again)
{ xTimeBlock.appendChild(ctD.fig[noFig++]) } // move figures inside
xCountDown.appendChild(xTimeBlock)
}
}
document.body.insertBefore(xWrapp, domEndBody) // insert CountDowm on page
// set count down initial values
if (parms.timer) // in case of timer...
{
let TimeInfos = get_DHMS(parms.timer, len )
ctD.time = TimeInfos.add
counters.push( ctD )
activeCounters++
updateInterface( ctD.ref, TimeInfos.dis ) // show first figure faces
}
else if (parms.date) // in case of CountDown until date
{
ctD.target = new Date(parms.date);
counters.push( ctD )
if (showFaceOnNow( ctD.ref ))
{ activeCounters++ }
}
}
CountDown_Run = function()
{
for (let elm of counters)
{
if (elm.time)
{ elm.target = new Date().getTime() + elm.time }
}
let timerInterval = setInterval(_=>
{
counters.forEach((elm,ref)=>
{
if ( elm.activ )
{
if (!showFaceOnNow( ref ))
{ activeCounters-- }
}
if ( activeCounters<=0 )
{ clearInterval(timerInterval) }
})
}
, one_Sec )
}
showFaceOnNow = function(ref)
{
let now = new Date().getTime()
, tim = counters[ref].target - now
, face = '0'.repeat( counters[ref].lg )
if (tim >= 0)
{
face = padZ(Math.floor(tim / one_Day), 3)
face += padZ((Math.floor((tim % one_Day ) / one_Hour)), 2)
face += padZ((Math.floor((tim % one_Hour) / one_Min )), 2)
face += padZ((Math.floor((tim % one_Min ) / one_Sec )), 2)
face = padZ( face, counters[ref].lg )
}
else
{
counters[ref].activ = false
}
updateInterface ( ref, face)
return counters[ref].activ
}
updateInterface = function(ref, newVal)
{
for(let p = counters[ref].lg ; p--;) // update faces figures backward
{
if (counters[ref].face.charAt(p) !== newVal.charAt(p))
{
animateFigure( counters[ref].fig[p], newVal.charAt(p) )
}
}
counters[ref].face = newVal
}
get_DHMS = function (timer_val, lg)
{
let vDelay = { d:0, h:0, m:0, s:0 }
, vNum = '0'
, ret = { add: 0, dis: ''}
for (const c of timer_val)
{
if (/[0-9]/.test(c) ) vNum += c
if (/[dhms]/.test(c) )
{
vDelay[c] = parseInt(vNum)
vNum = '0'
}
}
ret.add = (vDelay.d*one_Day)+(vDelay.h*one_Hour)+(vDelay.m*one_Min)+(vDelay.s*one_Sec)
ret.dis = (padZ(vDelay.d,3)+padZ(vDelay.h,2)+padZ(vDelay.m,2)+padZ(vDelay.s,2)).slice(-lg)
return ret
}
animateFigure = function (domElm, newChar)
{
let eTop = domElm.querySelector('.top')
, eBottom = domElm.querySelector('.bottom')
, eBack_top = domElm.querySelector('.top-back')
// Before we begin, change the back value and the back bottom value
eBack_top.querySelector('span').textContent = newChar
domElm.querySelector('.bottom-back span').textContent = newChar
TweenMax.to(eTop, 0.8, // Then animate
{ rotationX : '-180deg'
, transformPerspective: 300
, ease : Quart.easeOut
, onComplete : function()
{
eTop.textContent = newChar
eBottom.textContent = newChar
TweenMax.set(eTop, { rotationX: 0 })
}
})
TweenMax.to(eBack_top, 0.8, animOpt)
}
}( window.CountDown = window.CountDown || {}));
/********************************************************************************************/
const myCountDowns= [ { title: 'timer <strong>24h</strong>'
, type : 'Hours'
, timer: '24h'
}
, { title: 'Tea cup <strong>2\' 45"</strong>'
, type : 'Minutes'
, timer: '2m 45s'
}
, { title: 'until the new year <strong>2020</strong>'
, type : 'Days'
, date : '01 01 2020' // local Month Day Year
}
]
CountDown.BuildsAndRun( myCountDowns )
// ->type : 'Days' or 'Hours' or 'Minutes' or 'seconds'
// set "timer" for time duration otherwise set a "date" value
// timer string format is _number_UNIT where UNIT = 'd','h','m','s' for Days, Hours, Minutes, Seconds
// ex : '3d 25m 6s' = 3 days 0 hours 25 minutes, 6 seconds (days = 0, 0 is defauls for all units)
// ex : '6s 3d 25m' = the same, there is no order
// date format is JS Date format see new Date( _STRING_ )
body {
background-color: #f2f1ed;
margin: 0;
}
.wrap {
margin: 2em auto;
height: 270px;
width: 1500px; /* be re-calculate on JS */
border-radius: 1em;
padding: 10px 5px 0 5px;
box-shadow: 0px 0px 1px 1px rgba(170, 170, 170, 0.64);
}
a {
text-decoration: none;
color: #1a1a1a;
}
h1 {
margin-bottom: 30px;
text-align: center;
font: 300 2.25em "Lato";
text-transform: uppercase;
}
h1 strong {
font-weight: 400;
color: #ea4c4c;
}
h2 {
margin-bottom: 80px;
text-align: center;
font: 300 0.7em "Lato";
text-transform: uppercase;
}
h2 strong {
font-weight: 400;
}
.countdown {
/* width: 100%; or be re-calculate on JS */
margin: 0 auto;
padding: 0 10px 10px 10px;
}
.countdown .bloc-time {
float: left;
margin-right: 45px;
text-align: center;
}
.countdown .bloc-time:last-child {
margin-right: 0;
}
.countdown .count-title {
display: block;
margin-bottom: 15px;
font: normal 0.94em "Lato";
color: #1a1a1a;
text-transform: uppercase;
}
.countdown .figure {
position: relative;
float: left;
height: 110px;
width: 100px;
margin-right: 10px;
background-color: #fff;
border-radius: 8px;
-moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
-webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}
.countdown .figure:last-child {
margin-right: 0;
}
.countdown .figure > span {
position: absolute;
left: 0;
right: 0;
margin: auto;
font: normal 5.94em/107px "Lato";
font-weight: 700;
color: #de4848;
}
.countdown .figure .top:after, .countdown .figure .bottom-back:after {
content: "";
position: absolute;
z-index: -1;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.countdown .figure .top {
z-index: 3;
background-color: #f7f7f7;
transform-origin: 50% 100%;
-webkit-transform-origin: 50% 100%;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
-moz-transform: perspective(200px);
-ms-transform: perspective(200px);
-webkit-transform: perspective(200px);
transform: perspective(200px);
}
.countdown .figure .bottom {
z-index: 1;
}
.countdown .figure .bottom:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 50%;
background-color: rgba(0, 0, 0, 0.02);
}
.countdown .figure .bottom-back {
z-index: 2;
top: 0;
height: 50%;
overflow: hidden;
background-color: #f7f7f7;
-moz-border-radius-topleft: 10px;
-webkit-border-top-left-radius: 10px;
border-top-left-radius: 10px;
-moz-border-radius-topright: 10px;
-webkit-border-top-right-radius: 10px;
border-top-right-radius: 10px;
}
.countdown .figure .bottom-back span {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.countdown .figure .top, .countdown .figure .top-back {
height: 50%;
overflow: hidden;
-moz-backface-visibility: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.countdown .figure .top-back {
z-index: 4;
bottom: 0;
background-color: #fff;
-webkit-transform-origin: 50% 0;
transform-origin: 50% 0;
-moz-transform: perspective(200px) rotateX(180deg);
-ms-transform: perspective(200px) rotateX(180deg);
-webkit-transform: perspective(200px) rotateX(180deg);
transform: perspective(200px) rotateX(180deg);
-moz-border-radius-bottomleft: 10px;
-webkit-border-bottom-left-radius: 10px;
border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.countdown .figure .top-back span {
position: absolute;
top: -100%;
left: 0;
right: 0;
margin: auto;
}
<link href='https://fonts.googleapis.com/css?family=Lato:300,400,700' rel='stylesheet' type='text/css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<!-- no more HTML code -->
答案 3 :(得分:1)
// Create Countdown
var Countdown = {
// Backbone-like structure
$el: $('.countdown'),
// Params
countdown_interval: null,
total_seconds : 0,
// Initialize the countdown
init: function() {
// DOM
this.$ = {
hours : this.$el.find('.bloc-time.hours .figure'),
minutes: this.$el.find('.bloc-time.min .figure'),
seconds: this.$el.find('.bloc-time.sec .figure')
};
// Init countdown values
this.values = {
hours : this.$.hours.parent().attr('data-init-value'),
minutes: this.$.minutes.parent().attr('data-init-value'),
seconds: this.$.seconds.parent().attr('data-init-value'),
};
// Initialize total seconds
this.total_seconds = this.values.hours * 60 * 60 + (this.values.minutes * 60) + this.values.seconds;
// Animate countdown to the end
this.count();
},
count: function() {
var that = this,
$hour_1 = this.$.hours.eq(0),
$hour_2 = this.$.hours.eq(1),
$min_1 = this.$.minutes.eq(0),
$min_2 = this.$.minutes.eq(1),
$sec_1 = this.$.seconds.eq(0),
$sec_2 = this.$.seconds.eq(1);
this.countdown_interval = setInterval(function() {
if(that.total_seconds > 0) {
--that.values.seconds;
if(that.values.minutes >= 0 && that.values.seconds < 0) {
that.values.seconds = 59;
--that.values.minutes;
}
if(that.values.hours >= 0 && that.values.minutes < 0) {
that.values.minutes = 59;
--that.values.hours;
}
// Update DOM values
// Hours
that.checkHour(that.values.hours, $hour_1, $hour_2);
// Minutes
that.checkHour(that.values.minutes, $min_1, $min_2);
// Seconds
that.checkHour(that.values.seconds, $sec_1, $sec_2);
--that.total_seconds;
}
else {
clearInterval(that.countdown_interval);
}
}, 1000);
},
animateFigure: function($el, value) {
var that = this,
$top = $el.find('.top'),
$bottom = $el.find('.bottom'),
$back_top = $el.find('.top-back'),
$back_bottom = $el.find('.bottom-back');
// Before we begin, change the back value
$back_top.find('span').html(value);
// Also change the back bottom value
$back_bottom.find('span').html(value);
// Then animate
TweenMax.to($top, 0.8, {
rotationX : '-180deg',
transformPerspective: 300,
ease : Quart.easeOut,
onComplete : function() {
$top.html(value);
$bottom.html(value);
TweenMax.set($top, { rotationX: 0 });
}
});
TweenMax.to($back_top, 0.8, {
rotationX : 0,
transformPerspective: 300,
ease : Quart.easeOut,
clearProps : 'all'
});
},
checkHour: function(value, $el_1, $el_2) {
var val_1 = value.toString().charAt(0),
val_2 = value.toString().charAt(1),
fig_1_value = $el_1.find('.top').html(),
fig_2_value = $el_2.find('.top').html();
if(value >= 10) {
// Animate only if the figure has changed
if(fig_1_value !== val_1) this.animateFigure($el_1, val_1);
if(fig_2_value !== val_2) this.animateFigure($el_2, val_2);
}
else {
// If we are under 10, replace first figure with 0
if(fig_1_value !== '0') this.animateFigure($el_1, 0);
if(fig_2_value !== val_1) this.animateFigure($el_2, val_1);
}
}
};
function initializeCountdown ( $element ){
let uniqueCountdown = $.extend( {}, Countdown );
uniqueCountdown.$el = $element;
uniqueCountdown.init();
}
$('.countdown').each( function(){
initializeCountdown( $(this) );
});
我已更改了最后一个函数及其后续调用的逻辑。该方法复制Countdown
,为每个对象提供唯一的this
。然后,它在初始化之前设置与之对应的$el
。然后,我们为每个倒数元素调用此方法,由于this
是唯一的,因此每个倒数将彼此独立地操作,并允许倒数具有不同的开始时间。