基於vue3.0+TypeScript的簡易日曆

前言

第一次用vue3的api和ts寫,還在摸索中,有地方寫的不規範的,可交流,共同進步html

項目介紹,功能很簡單

  1. 顯示全部時間日期
  2. 上一年上個月,下個月下一年

預覽地址

arhebin.gitee.io/vue-calenda…vue

寫完後的感覺和收穫

  1. ts很香,但我用的不熟練;我平時會看看vue-next的源碼,既能學新api還能學ts,一箭雙鵰呢;固然其餘優質代碼也能夠
  2. vue3.0新的api很強大;例如就是reative, ref, watcher, watchEffect...,選擇太多了,給開發者的組合方式也就多了,如今最缺的應該是最佳實踐了。
  3. 最大感覺就是以前基於組件的分離,如今還能夠基於數據或者方法層面上的抽離,例如我試着寫了一個useComputedDayuseReducerDate,有點意思

怎麼寫日曆

個人思路是:

  1. 須要一個輸入的日期,默認是當前日期;這個值能夠是傳入的props,也能夠是state組件自身的狀態,(看你喜歡)
  2. 須要知道基於當前日期的年份
  3. 須要知道基於當前日期的月份
  4. 須要知道基於當前日期的幾號
  5. 須要知道基於當前日期的當月最大天數
  6. 須要知道基於當前日期的上一個月最大天數
  7. 須要知道基於當前日期的當月一號是星期幾

這些值都是基於當前日期的,因此你們會想到能夠用一個computed來關聯起來,反正我這麼想了,😄git

有了這些值作什麼能?

  1. 我先畫一個7*6的大方塊,默認索引是0-41
  2. 我知道當前日期一號是星期幾,就能和上面的索引關聯起來,在日後填日子,填到何時,就是當月最大天數的量,剩下的就是下一個月的1號仍是到索引結束,
  3. 同理頭部,當前日期一號是星期幾,以前的能夠根據上一月最大天數與索引關聯起來,填上去

舉個例子🌰github

  1. 今天是2020/4/28;星期2;4月1號是星期三;最大天數是30天;上一個月的最大天數是31天;索引是index
  2. 4月份的全部日子1-30怎麼填入裏格子中呢?當index - 3 >= 0就往小格子裏填入index - 3 + 1;直到(30 + 3 - 1) < index時,😯;剩餘頭尾
  3. 尾部觸發條件就是(30 + 3 - 1) < index,填入index - (30 + 3 - 1)
  4. 剩下就是頭部了,只要填入31 - (3 - index - 1)

代碼以下api

<p class="item" v-for="(el, index) in maxDays" :key="index">
  <span :class="['day', el.isActive ? 'isactive' : '']"
    v-if="(index - state.currentMonthFirstDay) >= 0 && (state.currentMonthMaxDays + state.currentMonthFirstDay - 1) >= index">
    {{index - state.currentMonthFirstDay + 1}}
  </span>
  <span class="day rest " v-else-if="(state.currentMonthMaxDays + state.currentMonthFirstDay - 1) < index">{{index - (state.currentMonthMaxDays + state.currentMonthFirstDay - 1)}}</span>
  <span class="day rest" v-else>{{state.preMonthMaxDays - (state.currentMonthFirstDay - index - 1)}}</span>
</p>
複製代碼

剩下的就是上一年上個月,下一年下個月

個人思路是寫一個dispatch,靠action的type去控制,只要改變固然輸入日期就好了。由於依賴已經關聯了;(可能一開始會寫個最簡單一個方法,if-else的判斷)數組

這些都不是重點啦,你們都有本身的思路。可是重點是包括我在內想知道是怎麼基於新api寫功能

剩下就是怎麼寫了

盲寫,先實現功能再說

<template>
    //html結構
</template>
<script>
    step() {
        const nowDay = new Date().toLocaleDateString().split('/').map(Number)
        const dayStr = ref<number[]>(nowDay) //這邊寫成數組,以前是字符串,但寫字符串有個問題就是年月日改變一個就會觸發因此依賴;數組能夠單純改變一個
        //接來利用computed
        //造成依賴
        const date = computed(() => new Date(str.value.join('/')))
        //年
        const currentYear = computed(() => date.value.getFullYear())
        //剩餘的值例如currentMonthMaxDays,preMonthMaxDays,currentMonthFirstDay
        ...
        //handleChange改變日期的方法
        const handleChange = () => {
            if () {
                //上一年
            }
            else if() {
                //上個月
            } else if() {
                //下個月
            } else if () {
                //下一年
            }
        }
    }
</script>

複製代碼

當你寫完,你會感受🐸,好長啊。就我我的而言,不怎麼喜歡在組件的入口把代碼的篇幅搞得很長。bash

怎麼優化呢?

如今基於vue3.0,我的感受數據,方法也能抽離,除了️組件抽離(只是我我的的想法,能夠交流)函數

  1. 第一個想法💡是:能不能把基於輸入日期的值拿出來溜溜呢? 對於那寫當前年份,當前月份等,數據能夠抽離成到一個文件中,取個好聽的名字叫作useComputedDay
export const useComputedDay = (str: Ref<number[]>) => {
    //注入了依賴
    const date = computed(() => new Date(str.value.join('/')))
    //年
    const currentYear = computed(() => date.value.getFullYear())
    //月
    const currentMonth = computed(() => date.value.getMonth() + 1)
    //日
    const currentDate = computed(() => date.value.getDate())
    //星期
    const currentDay = computed(() => date.value.getDay())
    //當月最大天數
    const currentMonthMaxDays = computed(() => getMonthMaxDays(currentYear.value, currentMonth.value))
    //當月星期幾
    const currentMonthFirstDay = computed(() => computedFirstDay(currentYear.value, currentMonth.value))
    //上一個月最大天數
    // const preMonthMaxDays = computed(() => new Date(currentYear.value, currentMonth.value - 1, 0).getDate())
    const preMonthMaxDays = computed(() => getMonthMaxDays(currentYear.value, currentMonth.value - 1))
    return {
      date,
      currentYear,
      currentMonth,
      currentDate,
      currentDay,
      currentMonthMaxDays,
      preMonthMaxDays,
      currentMonthFirstDay
    } 
}
複製代碼

怎麼用呢?佈局

const nowDay = new Date().toLocaleDateString().split('/').map(Number)
    const dayStr = ref<number[]>(nowDay) //這邊寫成數組,以前是字符串,但寫字符串有個問題就是年月日改變一個就會觸發因此依賴;數組能夠單純改變一個
    const dispatch = useReducerDate(dayStr)
    const {
      date,
      currentYear,
      currentMonth,
      currentDate,
      currentDay,
      currentMonthMaxDays,
      preMonthMaxDays,
      currentMonthFirstDay
    } = useComputedDay(dayStr);
複製代碼

這樣的話只要dayStr改變了全部的都會改變學習

  1. 第二個想法💡是:能不能把控制上下年月的方法也搞到外面去呢?,例如整個dispatchdispatch怎麼寫呢?能夠抽離出來寫成相似reducer那樣
export const useReducerDate = (state: Ref<number[]>) => {
    return function (action: action) {
        switch(action.type) {
            case 'preYear': {
                const _var = state.value.map(Number)
                _var[0] = _var[0] - 1;
                state.value = _var
                break;
            }
            case 'preMonth': {
                cutMonth(state);
                break;
            } 
            case 'nextYear': {
                const _var = state.value.map(Number)
                _var[0] = _var[0] + 1;
                state.value = _var
                break;
            }
            case 'nextMonth': {
                addMonth(state);
                break;
            } 
            default: {
                state.value = new Date().toLocaleDateString().split('/').map(Number)
            }
                
        }
    }
}
複製代碼

怎麼用呢?

<div class="textheader">
    <i class="iconfont textItem" @click="dispatch({type: 'preYear'})">&#xe714;</i>
    <i class="iconfont textItem" @click="dispatch({type: 'preMonth'})">&#xe667;</i>
    <p class="textItem">
      {{state.currentYear}} 年 {{state.currentMonth}} 月 {{state.currentDate}} 日
    </p>
    <i class="iconfont textItem " @click="dispatch({type: 'nextMonth'})">&#xe610;</i>
    <i class="iconfont textItem" @click="dispatch({type: 'nextYear'})">&#xe713;</i>
</div>
const dispatch = useReducerDate(dayStr)
複製代碼

很簡單吧,香不香。

  1. 第三個想法💡(剛加的)這個useReducerDate還能在提取一下寫個相似 useReducer,寫個可複用的函數
export const useReducer = (state: Ref<any>, reducer: (state: Ref<any>, action: action) => any) => {
    return function dispatch(val: action) {
        reducer(state, val)
    }
}
複製代碼
  1. 主要功能就完成了

源碼

github.com/coolpail/vu…

總結

  1. 主要體會並非日曆怎麼實現,而是在vue3.0的背景下,如何更好的基於新的api去實現功能,佈局本身的目錄結構;api太多了,玩法組合太多了
  2. 期待你們的寫法和想法💡,對交流學習共同進步
相關文章
相關標籤/搜索