最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Vue3創(chuàng)建一個(gè)簡(jiǎn)單的倒計(jì)時(shí)組件

 更新時(shí)間:2023年11月03日 08:31:52   作者:夢(mèng)塵星月  
這篇文章主要給大家介紹了基于Vue3創(chuàng)建一個(gè)簡(jiǎn)單的倒計(jì)時(shí)組件的代碼示例,文中通過代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下

需要從父級(jí)獲取的數(shù)據(jù)

  • time: 當(dāng)前倒計(jì)時(shí)的剩余時(shí)間,傳秒或毫秒
  • isMilliSecond: 用來判斷當(dāng)前的傳入值是秒還是毫秒值
  • end: 用來傳入具體的終點(diǎn)時(shí)間,傳入秒級(jí)時(shí)間戳或毫秒級(jí)時(shí)間戳
  • format: 用來控制最終的顯示格式,默認(rèn)格式'D天HH時(shí)MM分SS秒'
  • flag: 用來判斷,是否在最高值為0時(shí),不顯示最高值
// countDown.vue
<script setup lang="ts">
const props = defineProps({
    time: {
        type: [Number, String],
        default: 0,
    },
    isMilliSecond: {
        type: Boolean,
        default: false,
    },
    end: {
        type: [Number, String],
        default: 0,
    },
    format: {
        type: String,
        default: () => 'D天HH時(shí)MM分SS秒',
    },
    flag: {
        type: Boolean,
        default: false,
    }
})

</script>

<template>
    <div class="count_down">
        {{ timeStr }}
    </div>
</template>

基礎(chǔ)變量

  • curTime: 存儲(chǔ)當(dāng)前時(shí)間,因?yàn)楫?dāng)瀏覽器退至后臺(tái)時(shí),會(huì)將setTimeout等定時(shí)任務(wù)暫停,通過curTime用以更新倒計(jì)時(shí)
  • days, hours, mins, seconds: 倒計(jì)時(shí)的各個(gè)部分<想著總不能超過一年倒計(jì)時(shí)吧>
  • timer: 存儲(chǔ)定時(shí)器
  • remainingTime: 計(jì)算倒計(jì)時(shí)的秒數(shù)
  • timeStr: 格式化時(shí)間字符串
// countDown.vue
<script setup lang="ts">
import { computed, onMounted, ref, watch, type Ref } from 'vue';

const props = defineProps({
    time: {
        type: [Number, String],
        default: 0,
    },
    isMilliSecond: {
        type: Boolean,
        default: false,
    },
    end: {
        type: [Number, String],
        default: 0,
    },
    format: {
        type: String,
        default: () => 'D天HH時(shí)MM分SS秒',
    },
    flag: {
        type: Boolean,
        default: false,
    }
})

let curTime = 0

const days: Ref<string | number> = ref('0')

const hours: Ref<string | number> = ref('00')

const mins: Ref<string | number> = ref('00')

const seconds: Ref<string | number> = ref('00')

let timer: any = null;

const remainingTime = computed(() => {
    if(props.end) {
        let end = props.isMilliSecond ? +props.end : +props.end * 1000;

        end -= Date.now();
        return Math.round(end / 1000);
    }
    const time = props.isMilliSecond ? Math.round(+props.time / 1000) : Math.round(+props.time)

    return time
})

const timeStr = computed(() => {
    const o: {
        [key: string]: any
    } = {
        'D+': days.value,
        'H+': hours.value,
        'M+': mins.value,
        'S+': seconds.value,
    }

    let str = props.format;

    // 當(dāng)最高值為0時(shí),去除值及其單位,有缺陷,只能去除對(duì)應(yīng)目標(biāo)前的所有字段
    if(days.value == 0 && props.flag) {
        let regexPattern = /.*(?=H)/;

        if(hours.value == 0) {
            regexPattern = /.*(?=M)/;

            if(mins.value == 0) {
                regexPattern = /.*(?=S)/;
            }
        }

        str = str.replace(regexPattern, '');
    }

    for (var k in o) {
        // 括號(hào)的目的是將占位符的模式 k 捕獲到一個(gè)分組中,以便在替換字符串中的占位符時(shí)能夠引用它。
		str = str.replace(new RegExp(`(${k})`, 'g'), function(match, group) {
            let time = group.length === 1 ? o[k] : `00${o[k]}`.slice(-group.length);

            // 如果是天數(shù),不管是什么格式,都把天數(shù)顯示完整,但如果多個(gè)D,會(huì)在小于10之前加0
            if(k == 'D+' && group.length > 1)  {
                time = o[k];
                if(time < 10) {
                    time = `0${time}`
                }
            }

            return time
        });

	}

    return str;
})
</script>

<template>
    <div class="count_down">
        {{ timeStr }}
    </div>
</template>

基礎(chǔ)方法

  • countDown: 進(jìn)入頁面后立即執(zhí)行countDown,并執(zhí)行countdown,從而開始倒計(jì)時(shí)
  • formatTime: 將remainingTime轉(zhuǎn)化成天數(shù),小時(shí),分鐘,秒數(shù)的方法
  • countdown: 獲取時(shí)間后開始倒計(jì)時(shí)的執(zhí)行,
// countDown.vue
<script setup lang="ts">
const countDown = () => {
    curTime = Date.now()
    countdown(remainingTime.value)
}

const formatTime = (time: number) => {
    const secondsInMinute = 60;
    const secondsInHour = 24;

    let t = time;
    let ss = t % secondsInMinute;

    t = (t - ss) / secondsInMinute;

    const mm = t % secondsInMinute;
    t = (t - mm) / secondsInMinute;

    const hh = t % secondsInHour;
    t = (t - hh) / secondsInHour;

    const dd = t % secondsInHour;

    return { dd, hh, mm, ss };
}

const countdown = (time: number) => {
    timer && clearTimeout(timer)

    if(time < 0) {
        return;
    }

    const { dd, hh, mm, ss } = formatTime(time);

    days.value = dd || 0;
    hours.value = hh || 0;
    mins.value = mm || 0;
    seconds.value = ss || 0;

    timer = setTimeout(() => {
        const now = Date.now();
        const diffTime = Math.floor((now - curTime) / 1000)

        const step = diffTime > 1 ? diffTime : 1; // 頁面退到后臺(tái)的時(shí)候不會(huì)計(jì)時(shí),對(duì)比時(shí)間差,大于1s的重置倒計(jì)時(shí)

        curTime = now;

        countdown(time - step);
    }, 1000);
}

onMounted(() => {
    countDown();
})
</script>

為什么不使用setInterval來實(shí)現(xiàn)

  • 間隔不準(zhǔn)確:setInterval 的間隔并不保證準(zhǔn)確,因?yàn)樗皇菍⒒卣{(diào)函數(shù)添加到消息隊(duì)列,實(shí)際執(zhí)行時(shí)間依賴于主線程的負(fù)載和事件循環(huán),可能會(huì)被跳過或累積多次執(zhí)行。
  • 堆積問題: 如果一個(gè)setInterval回調(diào)執(zhí)行的時(shí)間比其間隔短,那么它會(huì)疊加執(zhí)行。這可能會(huì)導(dǎo)致不必要的資源消耗和不符合設(shè)計(jì)預(yù)期的行為。

這些問題通常是由于 JavaScript 的單線程執(zhí)行和事件循環(huán)機(jī)制導(dǎo)致的。在實(shí)際開發(fā)中,為了更準(zhǔn)確地處理定時(shí)任務(wù),通常會(huì)使用 setTimeout 和遞歸或計(jì)算屬性來處理定時(shí)任務(wù)。 雖然 setInterval 有一些局限性,但在某些情況下它仍然可以派上用場(chǎng),特別是對(duì)于一些簡(jiǎn)單的定時(shí)操作。但在需要更精確的定時(shí)和依賴于前后狀態(tài)的場(chǎng)景中,通常會(huì)選擇使用 setTimeout 或其他更高級(jí)的定時(shí)管理方法。

完整代碼

// countDown.vue
<script setup lang="ts">
import { computed, onMounted, ref, watch, type Ref } from 'vue';

const props = defineProps({
    time: {
        type: [Number, String],
        default: 0,
    },
    isMilliSecond: {
        type: Boolean,
        default: false,
    },
    end: {
        type: [Number, String],
        default: 0,
    },
    format: {
        type: String,
        default: () => 'D天HH時(shí)MM分SS秒',
    },
    flag: {
        type: Boolean,
        default: false,
    }
})

let curTime = 0

const days: Ref<string | number> = ref('0')

const hours: Ref<string | number> = ref('00')

const mins: Ref<string | number> = ref('00')

const seconds: Ref<string | number> = ref('00')

let timer: any = null;

const remainingTime = computed(() => {
    if(props.end) {
        let end = props.isMilliSecond ? +props.end : +props.end * 1000;

        end -= Date.now();
        return Math.round(end / 1000);
    }
    const time = props.isMilliSecond ? Math.round(+props.time / 1000) : Math.round(+props.time)

    return time
})

const timeStr = computed(() => {
    const o: {
        [key: string]: any
    } = {
        'D+': days.value,
        'H+': hours.value,
        'M+': mins.value,
        'S+': seconds.value,
    }

    let str = props.format;

    // 如果天數(shù)為0的情況,希望去掉H之前的部分
    if(days.value == 0 && props.flag) {
        let regexPattern = /.*(?=H)/;

        if(hours.value == 0) {
            regexPattern = /.*(?=M)/;

            if(mins.value == 0) {
                regexPattern = /.*(?=S)/;
            }
        }

        str = str.replace(regexPattern, '');
    }

    for (var k in o) {
        // 括號(hào)的目的是將占位符的模式 k 捕獲到一個(gè)分組中,以便在替換字符串中的占位符時(shí)能夠引用它。
		str = str.replace(new RegExp(`(${k})`, 'g'), function(match, group) {
            let time = group.length === 1 ? o[k] : `00${o[k]}`.slice(-group.length);

            if(k == 'D+' && group.length > 1)  {
                time = o[k];
                if(time < 10) {
                    time = `0${time}`
                }
            }

            return time
        });

	}

    return str;
})

const countDown = () => {
    curTime = Date.now()
    countdown(remainingTime.value)
}

const formatTime = (time: number) => {
    const secondsInMinute = 60;
    const secondsInHour = 24;

    let t = time;
    let ss = t % secondsInMinute;

    t = (t - ss) / secondsInMinute;

    const mm = t % secondsInMinute;
    t = (t - mm) / secondsInMinute;

    const hh = t % secondsInHour;
    t = (t - hh) / secondsInHour;

    const dd = t % secondsInHour;

    return { dd, hh, mm, ss };
}

const countdown = (time: number) => {
    timer && clearTimeout(timer)

    if(time < 0) {
        return;
    }

    const { dd, hh, mm, ss } = formatTime(time);

    days.value = dd || 0;
    hours.value = hh || 0;
    mins.value = mm || 0;
    seconds.value = ss || 0;

    timer = setTimeout(() => {
        const now = Date.now();
        const diffTime = Math.floor((now - curTime) / 1000)

        const step = diffTime > 1 ? diffTime : 1; // 頁面退到后臺(tái)的時(shí)候不會(huì)計(jì)時(shí),對(duì)比時(shí)間差,大于1s的重置倒計(jì)時(shí)

        curTime = now;

        countdown(time - step);
    }, 1000);
}

watch(remainingTime, () => {
    countDown()
}, { immediate: true })

onMounted(() => {
    countDown();
})
</script>

<template>
    <div class="count_down">
        {{ timeStr }}
    </div>
</template>
// 父級(jí)調(diào)用
<script setup lang="ts">
import countDown from './components/countDown.vue';

</script>

<template>
	<div id="app">
		<count-down 
            :end="1698980400000"
            :is-milli-second="true"
            :flag="true"
        />
	</div>
</template>

弊端

雖然這樣能夠通過父級(jí)傳入的格式進(jìn)行對(duì)應(yīng)的顯示,但是這樣的同時(shí),無法對(duì)每個(gè)單元的內(nèi)容或者樣式進(jìn)行調(diào)整,也無法根據(jù)父級(jí)來動(dòng)態(tài)顯示不同的樣式 想法: 可以通過插槽的方式,將值傳遞給父級(jí),通過父級(jí)來控制顯示的內(nèi)容

調(diào)整之后的代碼:基本代碼無調(diào)整,通過插槽將值 會(huì)傳給父級(jí)

// countDown.vue
<script setup lang="ts">
import { computed, onMounted, ref, watch, type Ref } from 'vue';

const props = defineProps({
    time: {
        type: [Number, String],
        default: 0,
    },
    isMilliSecond: {
        type: Boolean,
        default: false,
    },
    end: {
        type: [Number, String],
        default: 0,
    },
})

let curTime = 0

const days: Ref<string | number> = ref('0')

const hours: Ref<string | number> = ref('00')

const mins: Ref<string | number> = ref('00')

const seconds: Ref<string | number> = ref('00')

let timer: any = null;

const remainingTime = computed(() => {
    if(props.end) {
        let end = props.isMilliSecond ? +props.end : +props.end * 1000;

        end -= Date.now();
        return Math.round(end / 1000);
    }
    const time = props.isMilliSecond ? Math.round(+props.time / 1000) : Math.round(+props.time)

    return time
})

const countDown = () => {
    curTime = Date.now()
    countdown(remainingTime.value)
}

const formatTime = (time: number) => {
    const secondsInMinute = 60;
    const secondsInHour = 24;

    let t = time;
    let ss = t % secondsInMinute;

    t = (t - ss) / secondsInMinute;

    const mm = t % secondsInMinute;
    t = (t - mm) / secondsInMinute;

    const hh = t % secondsInHour;
    t = (t - hh) / secondsInHour;

    const dd = t % secondsInHour;

    return { dd, hh, mm, ss };
}

const countdown = (time: number) => {
    timer && clearTimeout(timer)

    if(time < 0) {
        return;
    }

    const { dd, hh, mm, ss } = formatTime(time);

    days.value = dd || 0;
    hours.value = hh || 0;
    mins.value = mm || 0;
    seconds.value = ss || 0;

    timer = setTimeout(() => {
        const now = Date.now();
        const diffTime = Math.floor((now - curTime) / 1000)

        const step = diffTime > 1 ? diffTime : 1; // 頁面退到后臺(tái)的時(shí)候不會(huì)計(jì)時(shí),對(duì)比時(shí)間差,大于1s的重置倒計(jì)時(shí)

        curTime = now;

        countdown(time - step);
    }, 1000);
}

watch(remainingTime, () => {
    countDown()
}, { immediate: true })

onMounted(() => {
    countDown();
})
</script>

<template>
    <div class="count_down">
        <slot v-bind="{
            d: days, h: hours, m: mins, s: seconds,
            dd: `00${days}`.slice(-2),
            hh: `00${hours}`.slice(-2),
            mm: `00${mins}`.slice(-2),
            ss: `00${seconds}`.slice(-2),
        }"></slot>
    </div>
</template>
// 父級(jí)調(diào)用
<script setup lang="ts">
import countDown from './components/countDown.vue';

</script>

<template>
	<div id="app">
		<count-down v-slot="timeObj" :end="1698980400000" :is-milli-second="true">
			{{timeObj.d}}天{{timeObj.hh}}小時(shí){{timeObj.mm}}分鐘{{timeObj.ss}}秒
		</count-down>
	</div>
</template>

以上就是基于Vue3創(chuàng)建一個(gè)簡(jiǎn)單的倒計(jì)時(shí)組件的詳細(xì)內(nèi)容,更多關(guān)于Vue3倒計(jì)時(shí)組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue?websocket封裝實(shí)現(xiàn)方法詳解

    Vue?websocket封裝實(shí)現(xiàn)方法詳解

    項(xiàng)目中需要使用websocke,這個(gè)是我自己修修改改好多次之后用得最順手的一版,分享一下。這個(gè)封裝需要搭配vuex使用,因?yàn)槭盏降臄?shù)據(jù)都保存在vuex中了,真的絕絕子好用,解決了我一大堆問題
    2022-09-09
  • 如何查看vue項(xiàng)目的node版本

    如何查看vue項(xiàng)目的node版本

    文章總結(jié):查看Vue項(xiàng)目中使用的Node版本,特別是當(dāng)項(xiàng)目使用Yarn和TypeScript時(shí),可以通過查看yarn.lock文件中的@types/node@version來確定版本
    2025-01-01
  • Vue之文件加載執(zhí)行全流程

    Vue之文件加載執(zhí)行全流程

    這篇文章主要介紹了Vue之文件加載執(zhí)行全流程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 解決VuePress頁面亂碼問題

    解決VuePress頁面亂碼問題

    這篇文章主要介紹了解決VuePress頁面亂碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 詳解Vue取消eslint語法限制

    詳解Vue取消eslint語法限制

    本篇文章給大家分享了Vue取消eslint語法限制的相關(guān)知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以參考學(xué)習(xí)下。
    2018-08-08
  • Vue?h函數(shù)的使用詳解

    Vue?h函數(shù)的使用詳解

    本文主要介紹了Vue?h函數(shù)的使用詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • vue實(shí)現(xiàn)橫向時(shí)間軸

    vue實(shí)現(xiàn)橫向時(shí)間軸

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)橫向時(shí)間軸,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 使用Vue3和ApexCharts實(shí)現(xiàn)交互式3D折線圖

    使用Vue3和ApexCharts實(shí)現(xiàn)交互式3D折線圖

    ApexCharts 是一個(gè)功能強(qiáng)大的 JavaScript 庫,用于創(chuàng)建交互式、可定制的圖表,在 Vue.js 中,它可以通過 vue3-apexcharts 插件輕松集成,本文給大家介紹了使用Vue3和ApexCharts實(shí)現(xiàn)交互式3D折線圖,需要的朋友可以參考下
    2024-06-06
  • Babel自動(dòng)生成Attribute文檔實(shí)現(xiàn)詳解

    Babel自動(dòng)生成Attribute文檔實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了Babel自動(dòng)生成Attribute文檔實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 結(jié)合el-upload組件實(shí)現(xiàn)大文件分片上傳功能

    結(jié)合el-upload組件實(shí)現(xiàn)大文件分片上傳功能

    Element UI的el-upload上傳組件相信各位小伙伴都已經(jīng)非常熟悉,最近接了一個(gè)新需求,要求在el-upload組件基礎(chǔ)上實(shí)現(xiàn)分片上傳功能,即小于等于5M文件正常上傳,大于5M文件切成5M每片上傳,那么這個(gè)功能怎么實(shí)現(xiàn)呢?一起看看吧
    2022-09-09

最新評(píng)論

美姑县| 彰化市| 从江县| 屏山县| 古交市| 岢岚县| 博兴县| 怀远县| 石家庄市| 朝阳市| 晋州市| 安宁市| 长垣县| 奉化市| 东乌| 兴义市| 闽侯县| 海盐县| 克山县| 中宁县| 公安县| 佛教| 奇台县| 西畴县| 四川省| 平阴县| 巴青县| 交城县| 和静县| 望谟县| 和平区| 洪雅县| 于田县| 松原市| 衡山县| 临洮县| 项城市| 溧阳市| 怀集县| 抚顺县| 定南县|