Vue 实现countDown倒计时

时间:2022-10-25 22:04:55

项目中要用到倒计时,用Vue 实现了一个

Vue 实现countDown倒计时

 

  1 <template>
2 <transition name="bkcd">
3 <div class="bkCountDown" v-show="bkCountDownShow">
4 <div class="kbCountDownTitle">
5 <img src="http://static.crecgec.com/Kaipiao/countDownTitle.png">
6 </div>
7 <div id="kbCountDownContent" class="kbCountDownContent" ref="kbCountDownContent">
8 </div>
9 <!--倒计时结束后提示的信息-->
10 <div class="cdEndCon" v-show="cdEndConShow">{{cdEndContent}}</div>
11 </div>
12 </transition>
13 </template>
14
15 <script>
16 import $ from 'jquery'
17
18 export default {
19 props: {
20 // 控制倒计时页面显示、隐藏
21 bkCountDownShow: {
22 type: Boolean,
23 default: true
24 },
25 // 这个参数:为了实现中途倒计时暂停功能
26 // 控制倒计时暂停/开始
27 cdStartOrEnd: {
28 type: Boolean,
29 default: true
30 },
31 // 倒计时的时间,有父组件传递
32 countDownTime: {
33 type: String,
34 default: '2017/11/9 15:03:01'
35 },
36 // 倒计时结束后显示的内容
37 cdEndContent: {
38 type: String,
39 default: '倒计时已经结束'
40 }
41 },
42 data () {
43 return {
44 // 倒计时结束后显示cdEndCon
45 cdEndConShow: false,
46 timestamp: '', // 倒计时的时间戳
47 cdTimer: '', // setTimeOut值
48 timeInterval: '', // 倒计时结束时间与当前时间的之间的间隔
49 timeIntervalVal: '', // 保存时间间隔的参数
50 d: '',
51 h: '',
52 m: '',
53 s: '',
54 days: 24 * 60 * 60,
55 hours: 60 * 60,
56 minutes: 60
57 }
58 },
59 mounted () {
60 this.countdown()
61 },
62 watch: {
63 // 监控cdStartOrEnd值
64 cdStartOrEnd () {
65 if (this.cdStartOrEnd) {
66 this.tick()
67 } else {
68 clearTimeout(this.cdTimer)
69 }
70 }
71 },
72 methods: {
73 countdown () {
74 this.timestamp = new Date(this.countDownTime).getTime()
75 this.init('kbCountDownContent')
76 },
77 // 初始化
78 init (ele) {
79 $.each(['Hours', 'Minutes', 'Seconds'], function (i) {
80 $('<div class="count' + this + '">').html(
81 `<div class = "countPos">\
82 <span class="digit static">0</span>\
83 </div>\
84 <div class="countPos">\
85 <span class="digit static">0</span>\
86 </div>`
87 ).appendTo($('#' + ele))
88 if (this !== 'Seconds') {
89 $('#' + ele).append('<div class="countDiv countDiv' + i + '"></div>')
90 }
91 })
92 this.tick()
93 },
94 tick () {
95 // 每次进入这个方法,就重新计算和当前时间的间隔,然后赋值给timeInterval
96 this.timeInterval = Math.floor((this.timestamp - (new Date())) / 1000)
97 if (this.timeInterval < 0) {
98 this.timeInterval = 0
99 }
100 this.timeIntervalVal = this.timeInterval
101 // Number of days left
102 // 现在是只有时分秒,可以通过调整下面的代码,来确定显示什么
103 // this.d = Math.floor(this.timeInterval / this.days)
104 // this.updateDuo(0, 1, this.d)
105 // this.timeInterval -= this.d * this.days
106 // Number of hours left
107 this.h = Math.floor(this.timeInterval / this.hours)
108 this.updateDuo(0, 1, this.h)
109 this.timeInterval -= this.h * this.hours
110 // Number of minutes timeInterval
111 this.m = Math.floor(this.timeInterval / this.minutes)
112 this.updateDuo(2, 3, this.m)
113 this.timeInterval -= this.m * this.minutes
114 // Number of seconds timeInterval
115 this.s = this.timeInterval
116 this.updateDuo(4, 5, this.s)
117 // timeIntervalVal大于0,就执行setTimeout方法
118 if (this.timeIntervalVal > 0) {
119 this.cdTimer = setTimeout(this.tick, 1000)
120 } else {
121 // 倒计时结束
122 this.cdEndConShow = true
123 // 这块可以添加emit,给父组件传参
124 // 通过emit给父组件传参数来操作bkCountDownShow
125 // bkCountDownShow = false
126 }
127 },
128 updateDuo (minor, major, value) {
129 this.switchDigit($('#kbCountDownContent').find('.countPos').eq(minor), Math.floor(value / 10) % 10)
130 this.switchDigit($('#kbCountDownContent').find('.countPos').eq(major), value % 10)
131 },
132 switchDigit (position, number) {
133 let digit = position.find('.digit')
134 if (digit.is(':animated')) {
135 return false
136 }
137 if (position.data('digit') === number) {
138 return false
139 }
140 position.data('digit', number)
141 var replacement = $('<span>', {
142 'class': 'digit',
143 css: {
144 top: '-170px',
145 opacity: 0
146 },
147 html: number
148 })
149 digit
150 .before(replacement)
151 .removeClass('static')
152 .animate({top: '170px', opacity: 0}, 'slow', function () {
153 digit.remove()
154 })
155 replacement
156 .delay(100)
157 .animate({top: 0, opacity: 1}, 'slow', function () {
158 replacement.addClass('static')
159 })
160 }
161 }
162 }
163 </script>
164
165 <!-- Add "scoped" attribute to limit CSS to this component only -->
166 <style>
167 *{
168 margin:0;
169 padding:0;
170 font-family: 'Microsoft Yahei',Tahoma,'Simsun','宋体' !important;
171 }
172
173 .bkCountDown{
174 width: 100%;
175 height: 980px;
176 background:url('http://static.crecgec.com/Kaipiao/background.png') #b0b0b0;
177 position: absolute;
178 background-size: cover;
179 overflow: hidden;
180 }
181 .kbCountDownTitle{
182 width: 1070px;
183 height: 120px;
184 line-height: 120px;
185 font-size: 120px;
186 margin: 190px auto 0;
187 text-align: center;
188 color: #fff;
189 }
190 .kbCountDownContent{
191 width:1070px;
192 margin:160px auto 0;
193 text-align:center;
194 letter-spacing:-3px;
195 overflow: hidden;
196 }
197 .countPos{
198 display: inline-block;
199 width: 150px;
200 height: 170px;
201 overflow: hidden;
202 position: relative;
203 margin-left: 15px;
204 }
205
206 .digit{
207 position:absolute;
208 display:block;
209 width:150px;
210 height: 170px;
211 line-height: 170px;
212 text-align:center;
213 color:#fff;
214 font-size: 80px;
215 background: url('http://static.crecgec.com/Kaipiao/countDown.png') 0 0 no-repeat;
216 }
217
218 .digit.static{
219 background: url('http://static.crecgec.com/Kaipiao/countDown.png') 0 0 no-repeat;
220 }
221 .countDays,.countHours,.countMinutes,.countSeconds{
222 float: left;
223 font-size: 0;
224 }
225 .countDiv{
226 display:inline-block;
227 width:10px;
228 height:50px;
229 float: left;
230 margin-top: 60px;
231 margin-left: 15px;
232 background: url('http://static.crecgec.com/Kaipiao/countDown1.png') 0 0 no-repeat;
233 }
234 .cdEndCon{
235 width:1070px;
236 margin:20px auto 0;
237 text-align: center;
238 color: #fff;
239 font-size: 20px;
240 }
241 .bkcd-enter-active, .bkcd-leave-active{
242 transition: opacity .5s
243 }
244 .bkcd-enter, .bkcd-leave-to{
245 opacity: 0
246 }
247 </style>