Vue3時(shí)間軸組件問(wèn)題記錄(時(shí)間信息收集組件)
背景
最近公司要求新增一個(gè)大屏頁(yè)面,需要封裝一個(gè)時(shí)間信息收集組件。通過(guò)雙向綁定響應(yīng)式數(shù)據(jù),父組件監(jiān)聽(tīng)子組件對(duì)數(shù)據(jù)的操作。最終將信息作為接口參數(shù),請(qǐng)求相應(yīng)的數(shù)據(jù),渲染至頁(yè)面上。
技術(shù)棧
Vue3(3.2.45)
Element-Plus(2.2.27)
dayjs(^1.11.7)
效果
其中時(shí)間軸是對(duì)Element Plus組件庫(kù)中的Slider滑塊組件的二次封裝,使用樣式穿透自定義樣式,同時(shí)大家可以把onMounted生命周期中的代碼取消注釋,可以做更多的操作。我的另一篇文章也是時(shí)間軸組件的封裝,不過(guò)兩者略有區(qū)別,所以又單獨(dú)記錄一下。
代碼
父組件關(guān)鍵代碼
<!-- 時(shí)間選擇 表單 --> <h1 class="titleH2"> {{ titleTime[0] }} - {{ titleTime[1] }} <br /> </h1> <div class="contentCenter_bottom"> <TimeForm v-model:up="objInfo" v-model:tt="titleTime"></TimeForm> </div> <script setup> // 雙向綁定 obj let objInfo = ref(null); // 雙向綁定 標(biāo)題時(shí)間 let titleTime = ref(null); // 監(jiān)聽(tīng)時(shí)間表單變化 - 針對(duì)左右兩側(cè)的數(shù)據(jù) watch(objInfo, (newVal) => { console.log(newVal, "父組件監(jiān)聽(tīng)到變化"); }); </script>
時(shí)間收集組件代碼
關(guān)鍵變量介紹
這些變量實(shí)際可以對(duì)外暴露出去,也就是讓父組件去定義,讓組件更具靈活性。
- optionsHour :每日小時(shí)節(jié)點(diǎn)配置項(xiàng)(可自行靈活配置)
- optionsDay :每周天數(shù)配置項(xiàng)(可自行靈活配置)
- LastDay :時(shí)間軸根據(jù)當(dāng)前時(shí)間和該變量往前推多少天,之后for循環(huán)會(huì)利用該變量為marks賦值,并求出步進(jìn)值stepValue 。
<template> <div id="TimeForm"> <div class="top"> <div class="topContent"> <div class="topContent_left"> <el-button v-for="(item, index) in optionsHour" :key="index" size="small" :type="indHour == index ? 'primary' : ''" style=" font-family: 'DIGIB'; font-size: 15px; border-radius: 6px 6px 0px 0px; " @click="handleHour(index)" >{{ item }}</el-button > </div> <el-divider direction="vertical" style="height: 80%" /> <div class="topContent_right"> <el-button v-for="(item, index) in optionsDay" :key="index" size="small" :type="indDay == index ? 'primary' : ''" style=" font-family: 'DIGIB'; letter-spacing: 1px; font-size: 15px; border-radius: 6px 6px 0px 0px; padding-left: 7px; padding-right: 7px; " @click="handleDay(index)" >{{ item }}</el-button > </div> </div> </div> <div class="bottom"> <el-slider v-model="value" :marks="marks" :step="stepValue" :show-tooltip="true" :format-tooltip="handleFormatTooltip" /> </div> </div> </template> <script setup> // vue import { ref, reactive, watch, watchEffect, computed, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, defineProps, defineEmits, } from "vue"; // 時(shí)間處理 import dayjs from "dayjs"; // 宏 let props = defineProps(["up", "tt"]); const emits = defineEmits(["update:up", "update:tt"]); // 定義變量 let optionsHour = reactive(["2點(diǎn)", "8點(diǎn)", "14點(diǎn)", "20點(diǎn)"]); let optionsDay = reactive([ "過(guò)去1天", "過(guò)去2天", "過(guò)去3天", "過(guò)去4天", "過(guò)去5天", "過(guò)去6天", "過(guò)去7天", ]); // 高亮 let indHour = ref(0); let indDay = ref(0); // 步長(zhǎng) let stepValue = ref(0); // slider 日期往前推多少天 let LastDay = ref(7); // 當(dāng)前時(shí)間 let NowTime = new Date().getTime(); // slider 值 const value = ref(0); // 標(biāo)記 const marks = reactive({}); // 方法 function GetOneWeek() { // 為marks賦值 for (let i = LastDay.value, j = 0; i >= 0; i--, j++) { let time = new Date(NowTime - i * 24 * 60 * 60 * 1000).getTime(); let t = dayjs(time).format("YYYY-MM-DD"); let num = Number(((100 * j) / LastDay.value).toFixed(1)); // console.log(num); marks[num] = `${t}`; // console.log(i, j, "ij"); } // 步進(jìn)值 stepValue.value = 100 / LastDay.value; } GetOneWeek(); // 函數(shù) // 高亮 function handleHour(val) { indHour.value = val; } function handleDay(val) { indDay.value = val; } // 自定義 提示信息 function handleFormatTooltip(val) { let num = Number(val.toFixed(1)); return marks[num]; } // 監(jiān)聽(tīng) // watch([indHour, indDay, value],([newHour,newDay,newValue],[oldHour,oldDay,oldValue])=>{ // console.log(newHour,newDay,newValue); // emits("update:objInfo", !props.objInfo); // }) watchEffect(() => { let hour, endTime, hourMinuteSecond; let num = Number(value.value.toFixed(1)); switch (indHour.value) { case 0: hourMinuteSecond = 2; break; case 1: hourMinuteSecond = 8; break; case 2: hourMinuteSecond = 14; break; case 3: hourMinuteSecond = 20; break; } switch (indDay.value) { case 0: hour = (indDay.value + 1) * 24; break; case 1: hour = (indDay.value + 1) * 24; break; case 2: hour = (indDay.value + 1) * 24; break; case 3: hour = (indDay.value + 1) * 24; break; case 4: hour = (indDay.value + 1) * 24; break; case 5: hour = (indDay.value + 1) * 24; break; case 6: hour = (indDay.value + 1) * 24; break; } // console.log(marks,value.value); endTime = marks[num]; let obj = { hour: hour, hourMinuteSecond: hourMinuteSecond, endTime: endTime, }; // console.log(marks[0],marks[100]); let timeStart = marks[0].replace(/-/, '年').replace(/-/, '月') + '日'; let timeEnd = marks[100].replace(/-/, '年').replace(/-/, '月') + '日'; console.log(timeStart); let timeObj = [timeStart,timeEnd] emits("update:up", obj); emits("update:tt", timeObj); }); // 生命周期 onBeforeMount(() => {}); onMounted(() => { // 無(wú)需刪除這段注釋 或許日后有用 // document.querySelector(".el-slider__bar").innerHTML = ` // <div // style="width:50px; height:24px;background:#ccc; position: absolute;right: 0px;top: -34px;transform: translateX(50%); display: flex; justify-content: space-between;" // > // <span id='span1'>1</span><span id='span2'>2</span> // </div> // `; // document.querySelector(".bottom").addEventListener("click", (e) => { // if (e.target.id == "span1") { // console.log("實(shí)況"); // } else if (e.target.id == "span2") { // console.log("預(yù)報(bào)"); // } // }); }); </script> <style lang="scss" scoped> // 變量 $timeform-height: 110px; $top-height: 30px; #TimeForm { width: 100%; min-height: $timeform-height; max-height: $timeform-height; box-sizing: border-box; // border: 1px dashed rgba(255, 255, 255, 0.5); // background-color: white; display: flex; flex-direction: column; justify-content: space-between; align-items: center; user-select: none; .top { width: 100%; height: $top-height; padding: 0px 20px; .topContent { width: auto; height: 100%; border-radius: 3px 3px 0px 0px; backdrop-filter: blur(10px); /* 背景模糊效果 */ background-color: rgba(255, 255, 255, 0.5); display: flex; justify-content: flex-start; align-items: end; padding: 0px 10px; .topContent_left { width: 260px; height: 80%; display: flex; justify-content: space-around; align-items: end; } .topContent_right { width: auto; height: 80%; display: flex; justify-content: space-around; align-items: end; flex-wrap: wrap; } } } .bottom { width: 100%; height: calc($timeform-height - $top-height); background-color: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); /* 背景模糊效果 */ display: flex; justify-content: center; align-items: center; padding: 0px 45px; } :deep(.bottom .el-slider__stop) { width: 2px; height: 14px; background-color: #005edc; border-radius: 0px; } :deep(.bottom .el-slider__bar) { background-color: transparent; // position: relative; } :deep(.bottom .el-slider__marks-text) { background-color: #e0eaf8; color: #626f80; padding-left: 2px; padding-right: 2px; } // :deep(.bottom .el-slider__button-wrapper::before){ // position: absolute; // right: 0px; // top: -17px; // transform: translateX(calc(50% - 18px)); // display: inline-block; // content: '123'; // width: 60px; // height: 20px; // background: #005edc; // z-index: 9999999; // } } </style>
所遇問(wèn)題
1.由于marks(取值范圍在閉區(qū)間0-100)的賦值是根據(jù)LastDay 變量計(jì)算出來(lái)的,具體來(lái)說(shuō)是這段代碼:
Number(((100 * j) / LastDay.value).toFixed(1));(最初是沒(méi)有.toFixed(1))
這導(dǎo)致計(jì)算有可能存在很長(zhǎng)的小數(shù),由于小數(shù)的存在,又使得watchEffect當(dāng)中的
let num = Number(value.value.toFixed(1));endTime = marks[num];(最初沒(méi)有.toFixed(1))
有可能匹配不上返回 undefined。
也有嘗試使用Math中的四舍五入或向上/下取整解決,但這又導(dǎo)致滑塊對(duì)應(yīng)不上步進(jìn)值,最終采取了.toFixed(1)解決該問(wèn)題。(.toFixed()返回值是字符串)
2.代碼中的v-model綁定組件必須采用別名方式,否則無(wú)效。
到此這篇關(guān)于Vue3時(shí)間軸組件(時(shí)間信息收集組件)的文章就介紹到這了,更多相關(guān)Vue3時(shí)間軸組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Element Cascader 級(jí)聯(lián)選擇器的使用示例
這篇文章主要介紹了Element Cascader 級(jí)聯(lián)選擇器的使用示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07vue封裝一個(gè)簡(jiǎn)單的div框選時(shí)間的組件的方法
這篇文章主要介紹了vue封裝一個(gè)簡(jiǎn)單的div框選時(shí)間的組件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01詳解如何使用vue實(shí)現(xiàn)頁(yè)面訪問(wèn)攔截
這篇文章主要為大家詳細(xì)介紹了如何使用vue實(shí)現(xiàn)頁(yè)面訪問(wèn)攔截功能,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,需要的可以了解一下2023-08-08