当前位置: 首页 > article >正文

【全栈实战】基于 Vue3 + Wot Design Uni 动手封装组件

😊你好,我是小航,一个正在变秃、变强的文艺倾年。

😊好久没有更新有关前端实战教程了,本文主要讲解【全栈实战】基于 Vue3 + Wot Design Uni 动手封装组件!

😊这个教程你将会学到技术正确的选型、Vue3基础语法实践、父子组件传参、移动端组件封装、组件源码阅读技巧、小程序适配技巧等,一起卷起来吧!

目录

  • 一、前言
    • Wot Design Uni
      • 技术选型
      • UI库选型
        • 开源热度对比
        • 多端支持情况
        • 组件数量
        • ts 支持情况
        • 发展趋势
    • Tyme
      • 语言支持情况
      • 活跃程度
      • 发展趋势
      • 使用教程
  • 二、封装
    • 思路
    • 父组件
    • 子组件
      • 初始化
      • 样式搭建
      • 工具封装
      • 常量定义
      • 逻辑设计
      • 解决微信小程序 Tab 动画异常
    • 效果展示
  • 三、完整代码
    • 代码
    • 下一步建议

一、前言

由于本人近期需要一个支持输入农历、公历的移动端组件,仅需要输入年、月、日、时,输入界面要求可以同时选择四列,且自由切换农历、公历。网上没找到现成的组件,只好自己封装一个了。下面先介绍一下自己的技术选型,本人开发采用的语言是Vue3 + Typescript

Wot Design Uni

在这里插入图片描述

技术选型

Uniapp的上手难度很低,而且Uniapp的语法风格与Vue保持高度一致,可以直接复用已有的Vue项目中的代码和经验。因此我这里使用的开发框架是Uniapp。

UI库选型

对于UI库的选型,我们常常从开源热度、多端支持情况、组件数量、ts支持情况、发展趋势来选择。

开源热度对比

截止到 2024-05-30 发表文章时的数据:

UI 框架uv-uiuview-pluswot-uiTuniaoUI
github stars568362492192
gitee stars55512635-
github forks1.1k15818820
gitee forks75430-

实到这里就一决高下了,github star 数uv-ui(568) > wot-ui(492) > uview-plus(362) > TuniaoUI(192),其中 uv-uiwot-ui 拔得头筹。

在这里插入图片描述

多端支持情况
UI 框架uv-uiuview-pluswot-uiTuniaoUI
h5
app(ios)
app(android)
微信小程序
支付宝小程序
QQ 小程序
百度小程序
头条小程序
组件数量
UI 框架uv-uiuview-pluswot-uiTuniaoUI
总数67677155
基础组件81185
表单组件16172014
数据组件134184
反馈组件810168
布局组件79-8
导航组件8895
其他组件78-5
内容组件---6

组件数:wot(71) > uv-ui(67) = uview-plus(67) > TuniaoUI(55)

ts 支持情况

查看 4 个组件库的源码,可以了解到:

  • uv-uiuView-plus 都是 js 写的,并非 ts,可以通过 ttou/uv-typings 提供类型支持。
  • wotTuniaoUI 都是 ts 写的,编码体验会好很多。

小知识:代码里如何辨别一个库是否有 ts 支持,写代码的时候按 ctrl + i (Mac 里 cmd + i),如果有提示就是有,啥都没有就是没有。

举个例子,编写 <xx-button type="" ...,在 type="" 双引号里面按 ctrl + i,看提示就知道了。

  • wot 有提示
    在这里插入图片描述
  • uv-ui 无提示
    在这里插入图片描述
发展趋势

wot-uiuv-ui皇城PK

在这里插入图片描述
目前 wot-ui 还是比不过 uv-ui 的,但是 wot-ui 有反超的势头。

这里我选择了wot-ui。wot-ui 全称 wot-design-uni,是 wot-design 的 uniapp 版本,文档地址:https://wot-design-uni.netlify.app/

Tyme

Tyme是一个非常强大的日历工具库,可以看作 Lunar 的升级版,拥有更优的设计和扩展性,支持公历和农历、星座、干支、生肖、节气、法定假日等。这有助与我们进行农历和公历之间的转化。

开源地址:https://github.com/6tail/tyme4ts

语言支持情况

看着就很棒,支持了市面了主流的语言。
在这里插入图片描述

活跃程度

近两周刚更新源代码,说明出了问题能解决。我们在采用别人封装好的库时候,一定要多看看仓库活跃程度,如果这个仓库都好久没有更新维护了,不建议使用。

在这里插入图片描述

发展趋势

没毛病,就它了!
在这里插入图片描述

使用教程

// install
npm init -y
npm i typescript -D
npm i ts-node -D
npm i tyme4ts
 
// test.ts
import {SolarDay} from 'tyme4ts';
 
const solar: SolarDay = SolarDay.fromYmd(1986, 5, 29);
 
// 1986年5月29日
console.log(solar.toString());

// 农历丙寅年四月廿一
console.log(solar.getLunarDay().toString());
 
// run
ts-node test.ts

二、封装

思路

在这里插入图片描述
示例数据:

// 公历2024年12月22日13时
birthdayValue: [2024, 12, 22, 13, 1]

用到的组件:

Input、Picker、Popup

父组件

<birthdayPicker
    v-model="state.userInfo.birthdayValue"
    prop="birthdayValue"
    :rules="[
      {
        required: false,
        message: '请输入生辰',
      },
    ]"
 ></birthdayPicker>

// 定义变量
const state = reactive({
  // 用户信息数据
  userInfo: {
    birthdayValue: null,
  },
})

子组件

初始化

Tips:便于调试,推荐onload加入debugger,可以直接看到小程序源代码是否刷新,小程序经常不刷新代码,经常误认为自己的编码问题,也是比较恼火。

onLoad(() => {
  debugger
})

定义组件名称

defineOptions({
  name: 'birthdayPicker',
})

定义接收父组件传值的接口

type bithdayPickerProps = {
  modelValue: number[] // 生日值
  disabled?: boolean // 是否禁用
  prop: string // 表单域 model 字段名,在使用表单校验功能的情况下,该属性是必填的
  rules: FormItemRule[] // 表单校验规则
}
const props = defineProps<bithdayPickerProps>()
const emit = defineEmits(['update:modelValue'])

定义用到的状态变量

const state = reactive({
  displayColumns: [],
  popupShow: false,
  birthdayArr: ['农历', '公历'],
  birthday: [],
  birthdayIndex: 0,
  pickerViewLoaded: false,
})

// 计算Picker展示值
const displayBirthday = computed(() => {
  const birthday = state.birthday
  // 避免空数组调用join函数
  if (isNullBirthdayArray(birthday, 4)) return null
  // 公历2024年12月22日13时
  return (
    state.birthdayArr[state.birthdayIndex] +
    birthday[0] +
    '年' +
    findValueInCoulums(birthday[1], state.displayColumns[1]) +
    findValueInCoulums(birthday[2], state.displayColumns[2]) +
    birthday[3] +
    '时'
  )
})

在这里插入图片描述

这里有个常见的面试考点:

如何在 ref() 与 reactive() 之间做正确选择?
(1)ref() 和 reactive() 用于跟踪其参数的更改。当使用它们初始化变量时,是向 Vue 提供信息:“嘿,每次这些变量发生更改时,请重新构建或重新运行依赖于它们的所有内容”。
(2)ref() 函数可以接受原始类型(最常见的是布尔值、字符串和数字)以及对象作为参数,而 reactive() 函数只能接受对象作为参数。
(3)ref() 有一个 .value 属性,你必须使用 .value 属性获取内容,但是使用 reactive() 的话可以直接访问。
(4)使用 ref() 函数可以替换整个对象实例,但是在使用 reactive() 函数时就不行。
(5)如果你喜欢组件内部状态仅有一个变量,那么 reactive() 就是适合你的正确工具。本人更喜欢使用reactive,看着比较舒服。
在这里插入图片描述

样式搭建

编写组件样式:

<template>
  <wd-popup
    v-model="state.popupShow"
    position="bottom"
    custom-style="border-radius:32rpx;height: 300px;"
    :close-on-click-modal="false"
    @close="closeBirthdayPicker"
    closable
    @after-enter="handleOpened"
  >
    <wd-tabs v-model="state.birthdayIndex" animated swipeable ref="tabsRef" @change="onChangeTab">
      <wd-tab v-for="(item, index) in state.birthdayArr" :key="index" :title="item">
        <wd-picker-view
          :columns="state.displayColumns"
          v-model="state.birthday"
          :column-change="onChangeColumn"
          ref="birthdayPicker"
        />
      </wd-tab>
    </wd-tabs>
  </wd-popup>
  <div @click="openBirthdayPicker">
    <wd-input
      :prop="props.prop"
      :rules="props.rules"
      type="text"
      label="生辰"
      v-model="displayBirthday"
      placeholder="请选择"
      readonly
      required
      placeholder-style="color:#bfbfbf"
    >
      <template #suffix>
        <!--箭头-->
        <wd-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="18px" />
      </template>
    </wd-input>
  </div>
</template>

在这里插入图片描述
基础的打开、关闭

// 打开生日选择器
const openBirthdayPicker = () => {
  if (props.disabled) return
  state.popupShow = true
  const value = props.modelValue
  if (isNullBirthdayArray(value, 5)) {
    state.birthday = [1940, 1, 1, 1]
    state.birthdayIndex = 0
    return
  }
  state.birthday = [value[0], value[1], value[2], value[3]]
  state.birthdayIndex = value[4]
}

// 关闭生日选择器
const closeBirthdayPicker = () => {
  emit('update:modelValue', [...state.birthday, state.birthdayIndex])
  state.popupShow = false
}

工具封装

由于我这里会经常对bithday数组进行判空,判断依据有:是否有空值、长度是否满足,是否是数组等,这里我们封装成一个函数

const isNullBirthdayArray = (birthday: number[], validLength: number = birthday.length) => {
  return (
    !birthday ||
    (isArray(birthday) &&
      (!birthday.length ||
        birthday.length !== validLength ||
        birthday.every((item) => item === null)))
  )
}

Picker值展示时需要根据birthday的值进行与当前columns映射

const findValueInCoulums = (value: number, columns: any[]) => {
  let res = ''
  columns.forEach((item) => {
    if (item.value === value) res = item.label
  })
  return res
}

常量定义

// 定义农历月份和日期的汉字表示
const chineseMonths = [
  '一月',
  '二月',
  '三月',
  '四月',
  '五月',
  '六月',
  '七月',
  '八月',
  '九月',
  '十月',
  '十一月',
  '十二月',
]
const chineseDays = [
  '初一',
  '初二',
  '初三',
  '初四',
  '初五',
  '初六',
  '初七',
  '初八',
  '初九',
  '初十',
  '十一',
  '十二',
  '十三',
  '十四',
  '十五',
  '十六',
  '十七',
  '十八',
  '十九',
  '二十',
  '廿一',
  '廿二',
  '廿三',
  '廿四',
  '廿五',
  '廿六',
  '廿七',
  '廿八',
  '廿九',
  '三十',
]

根据常量来更新展示列信息:

const yearColumns = Array.from({ length: new Date().getFullYear() - 1940 + 1 }, (_, i) => {
  return { label: `${1940 + i}`, value: 1940 + i }
})
const hourColumns = Array.from({ length: 24 }, (_, i) => ({
  label: `${i + 1}`,
  value: i + 1,
}))
const initDays = (len: number, type: 'lunar' | 'gregorian') =>
  Array.from({ length: len }, (_, i) => {
    return {
      label: type === 'lunar' ? `${chineseDays[i]}` : `${i + 1}`,
      value: i + 1,
    }
  })
const updateColumns = (birthday: number[]) => {
  let monthColumns = []
  let dayColumns = []
  const [_year, _month, _day, _hour, birthdayIndex] = birthday
  // 1.农历列
  if (birthdayIndex === 0) {
    const lunarYear: LunarYear = LunarYear.fromYear(_year)
    monthColumns = lunarYear.getMonths().map((month) => ({
      label: month.isLeap()
        ? `${chineseMonths[month.getMonth() - 1]}`
        : chineseMonths[month.getMonth() - 1],
      value: month.getMonthWithLeap(),
    }))
    const lunarMonth: LunarMonth = LunarMonth.fromYm(_year, _month)
    const dayCount: number = lunarMonth.getDayCount()
    dayColumns = initDays(dayCount, 'lunar')
  }
  // 2.公历列
  if (birthdayIndex === 1) {
    monthColumns = Array.from({ length: 12 }, (_, i) => {
      return { label: `${chineseMonths[i]}`, value: i + 1 }
    })
    const solarMonth: SolarMonth = SolarMonth.fromYm(_year, _month)
    const dayCount: number = solarMonth.getDayCount()
    dayColumns = initDays(dayCount, 'gregorian')
  }
  state.displayColumns = [yearColumns, monthColumns, dayColumns, hourColumns]
}

逻辑设计

初始化列

// 1.初始化
onMounted(() => {
  handleShowValueUpdate(props.modelValue)
})

// 2.监听父组件的值变化
watch(
  () => props.modelValue,
  (newValue) => {
    handleShowValueUpdate(newValue)
  },
)

// 3.值变更时更新显示内容
const handleShowValueUpdate = (value: number[]) => {
  // 0.校验
  if (isNullBirthdayArray(value, 5)) {
    // 更新为初始值,状态值保持不变
    updateColumns([1940, 1, 1, 1, 0])
    return
  }
  // 1.获取选中项
  state.birthday = [value[0], value[1], value[2], value[3]]
  state.birthdayIndex = value[4]
  // 2.更新列
  updateColumns(value)
}

// 4.当农历、公历切换时:
const onChangeTab = (index) => {
  state.pickerViewLoaded = true
  const [_year, _month, _day, _hour] = state.birthday
  // 1.农历转公历
  if (index.name === 1) {
    console.log('农历转公历前', index.name, state.birthday)
    const lunarHour = LunarHour.fromYmdHms(_year, _month, _day, _hour, 0, 0)
    const solarTime: SolarTime = lunarHour.getSolarTime()
    state.birthday = [
      solarTime.getYear(),
      solarTime.getMonth(),
      solarTime.getDay(),
      solarTime.getHour(),
    ]
    console.log('农历转公历后', index.name, state.birthday)
  }
  // 2.公历转农历
  if (index.name === 0) {
    console.log('公历转农历前', index.name, state.birthday)
    const solarTime = SolarTime.fromYmdHms(_year, _month, _day, _hour, 0, 0)
    const lunarHour = solarTime.getLunarHour()
    state.birthday = [
      lunarHour.getYear(),
      lunarHour.getMonth(),
      lunarHour.getDay(),
      lunarHour.getHour(),
    ]
    console.log('公历转农历后', index.name, state.birthday)
  }
  // 3.更新Columns列,注意此时state.birthdayIndex还未更新
  updateColumns([...state.birthday, index.name])
}

// 5.更新列
const updateColumns = (birthday: number[]) => {
  let monthColumns = []
  let dayColumns = []
  const [_year, _month, _day, _hour, birthdayIndex] = birthday
  // 1.农历列
  if (birthdayIndex === 0) {
    const lunarYear: LunarYear = LunarYear.fromYear(_year)
    monthColumns = lunarYear.getMonths().map((month) => ({
      label: month.isLeap()
        ? `${chineseMonths[month.getMonth() - 1]}`
        : chineseMonths[month.getMonth() - 1],
      value: month.getMonthWithLeap(),
    }))
    const lunarMonth: LunarMonth = LunarMonth.fromYm(_year, _month)
    const dayCount: number = lunarMonth.getDayCount()
    dayColumns = initDays(dayCount, 'lunar')
  }
  // 2.公历列
  if (birthdayIndex === 1) {
    monthColumns = Array.from({ length: 12 }, (_, i) => {
      return { label: `${chineseMonths[i]}`, value: i + 1 }
    })
    const solarMonth: SolarMonth = SolarMonth.fromYm(_year, _month)
    const dayCount: number = solarMonth.getDayCount()
    dayColumns = initDays(dayCount, 'gregorian')
  }
  state.displayColumns = [yearColumns, monthColumns, dayColumns, hourColumns]
}

当用户滑动列后进行更新picker

const onChangeColumn = (pickerView, value, columnIndex, resolve) => {
  // debugger
  // 1.更新birthday值
  const item = value[columnIndex]
  state.birthday[columnIndex] = Number(item.value)
  // 2.滑动列后重置后面的列
  for (let i = columnIndex + 1; i < 4; i++) {
    state.birthday[i] = 1
  }
  // 3.更新Columns列
  updateColumns([...state.birthday, state.birthdayIndex])
  // 4.更新pickerView
  if (columnIndex === 0) {
    pickerView.setColumnData(1, state.displayColumns[1])
    pickerView.setColumnData(2, state.displayColumns[2])
    pickerView.setColumnData(3, state.displayColumns[3])
  } else if (columnIndex === 1) {
    pickerView.setColumnData(2, state.displayColumns[2])
    pickerView.setColumnData(3, state.displayColumns[3])
  } else if (columnIndex === 2) {
    pickerView.setColumnData(3, state.displayColumns[3])
  }
  // 5.更新pickerView组件
  resolve()
}

这里我进行了后列重置,避免出现后面的日期不存在于当月,造成列Index错误。

在这里插入图片描述

解决微信小程序 Tab 动画异常

// 解决微信小程序Tabs表现异常
const tabsRef = ref<TabsInstance>()
function handleOpened() {
  tabsRef.value?.updateLineStyle(false)
}

在这里插入图片描述

效果展示

选择农历后:

在这里插入图片描述
农历切换到公里后:

在这里插入图片描述
测试闰月:

在这里插入图片描述
测试校验规则

在这里插入图片描述

三、完整代码

代码

<template>
  <wd-popup
    v-model="state.popupShow"
    position="bottom"
    custom-style="border-radius:32rpx;height: 300px;"
    :close-on-click-modal="false"
    @close="closeBirthdayPicker"
    closable
    @after-enter="handleOpened"
  >
    <wd-tabs v-model="state.birthdayIndex" animated swipeable ref="tabsRef" @change="onChangeTab">
      <wd-tab v-for="(item, index) in state.birthdayArr" :key="index" :title="item">
        <wd-picker-view
          :columns="state.displayColumns"
          v-model="state.birthday"
          :column-change="onChangeColumn"
          ref="birthdayPicker"
        />
      </wd-tab>
    </wd-tabs>
  </wd-popup>
  <div @click="openBirthdayPicker">
    <wd-input
      :prop="props.prop"
      :rules="props.rules"
      type="text"
      label="生辰"
      v-model="displayBirthday"
      placeholder="请选择"
      readonly
      required
      placeholder-style="color:#bfbfbf"
    >
      <template #suffix>
        <!--箭头-->
        <wd-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="18px" />
      </template>
    </wd-input>
  </div>
</template>

<script lang="ts" setup>
import { LunarYear, LunarMonth, LunarHour, SolarTime, SolarMonth } from 'tyme4ts'
import { isArray } from 'wot-design-uni/components/common/util'
import { reactive, computed, watch, ref, defineProps, defineEmits, defineOptions } from 'vue'
import { FormItemRule } from 'wot-design-uni/components/wd-form/types'

defineOptions({
  name: 'birthdayPicker',
})

onLoad(() => {
  debugger
})

// 解决微信小程序Tabs表现异常
const tabsRef = ref<TabsInstance>()
function handleOpened() {
  tabsRef.value?.updateLineStyle(false)
}

// 定义农历月份和日期的汉字表示
const chineseMonths = [
  '一月',
  '二月',
  '三月',
  '四月',
  '五月',
  '六月',
  '七月',
  '八月',
  '九月',
  '十月',
  '十一月',
  '十二月',
]
const chineseDays = [
  '初一',
  '初二',
  '初三',
  '初四',
  '初五',
  '初六',
  '初七',
  '初八',
  '初九',
  '初十',
  '十一',
  '十二',
  '十三',
  '十四',
  '十五',
  '十六',
  '十七',
  '十八',
  '十九',
  '二十',
  '廿一',
  '廿二',
  '廿三',
  '廿四',
  '廿五',
  '廿六',
  '廿七',
  '廿八',
  '廿九',
  '三十',
]

// 1.状态管理
const state = reactive({
  displayColumns: [],
  popupShow: false,
  birthdayArr: ['农历', '公历'],
  birthday: [],
  birthdayIndex: 0,
  pickerViewLoaded: false,
})

// 2.定义组件接收值
type bithdayPickerProps = {
  modelValue: number[] // 生日值
  disabled?: boolean // 是否禁用
  prop: string // 表单域 model 字段名,在使用表单校验功能的情况下,该属性是必填的
  rules: FormItemRule[] // 表单校验规则
}
const props = defineProps<bithdayPickerProps>()
const emit = defineEmits(['update:modelValue'])

// 3.计算Picker展示值
const findValueInCoulums = (value: number, columns: any[]) => {
  let res = ''
  columns.forEach((item) => {
    if (item.value === value) res = item.label
  })
  return res
}
const displayBirthday = computed(() => {
  const birthday = state.birthday
  // 避免空数组调用join函数
  if (isNullBirthdayArray(birthday, 4)) return null
  // 公历2024年12月22日13时
  return (
    state.birthdayArr[state.birthdayIndex] +
    birthday[0] +
    '年' +
    findValueInCoulums(birthday[1], state.displayColumns[1]) +
    findValueInCoulums(birthday[2], state.displayColumns[2]) +
    birthday[3] +
    '时'
  )
})
const isNullBirthdayArray = (birthday: number[], validLength: number = birthday.length) => {
  return (
    !birthday ||
    (isArray(birthday) &&
      (!birthday.length ||
        birthday.length !== validLength ||
        birthday.every((item) => item === null)))
  )
}
// 4.初始化
onMounted(() => {
  handleShowValueUpdate(props.modelValue)
})

// 5.监听父组件的值变化
watch(
  () => props.modelValue,
  (newValue) => {
    handleShowValueUpdate(newValue)
  },
)

// 6.值变更时更新显示内容
const handleShowValueUpdate = (value: number[]) => {
  // 0.校验
  if (isNullBirthdayArray(value, 5)) {
    // 更新为初始值,状态值保持不变
    updateColumns([1940, 1, 1, 1, 0])
    return
  }
  // 1.获取选中项
  state.birthday = [value[0], value[1], value[2], value[3]]
  state.birthdayIndex = value[4]
  // 2.更新列
  updateColumns(value)
}

// 7.更新Columns:年份列、月份列、天数列、小时列
const yearColumns = Array.from({ length: new Date().getFullYear() - 1940 + 1 }, (_, i) => {
  return { label: `${1940 + i}`, value: 1940 + i }
})
const hourColumns = Array.from({ length: 24 }, (_, i) => ({
  label: `${i + 1}`,
  value: i + 1,
}))
const initDays = (len: number, type: 'lunar' | 'gregorian') =>
  Array.from({ length: len }, (_, i) => {
    return {
      label: type === 'lunar' ? `${chineseDays[i]}` : `${i + 1}`,
      value: i + 1,
    }
  })

const updateColumns = (birthday: number[]) => {
  let monthColumns = []
  let dayColumns = []
  const [_year, _month, _day, _hour, birthdayIndex] = birthday
  // 1.农历列
  if (birthdayIndex === 0) {
    const lunarYear: LunarYear = LunarYear.fromYear(_year)
    monthColumns = lunarYear.getMonths().map((month) => ({
      label: month.isLeap()
        ? `${chineseMonths[month.getMonth() - 1]}`
        : chineseMonths[month.getMonth() - 1],
      value: month.getMonthWithLeap(),
    }))
    const lunarMonth: LunarMonth = LunarMonth.fromYm(_year, _month)
    const dayCount: number = lunarMonth.getDayCount()
    dayColumns = initDays(dayCount, 'lunar')
  }
  // 2.公历列
  if (birthdayIndex === 1) {
    monthColumns = Array.from({ length: 12 }, (_, i) => {
      return { label: `${chineseMonths[i]}`, value: i + 1 }
    })
    const solarMonth: SolarMonth = SolarMonth.fromYm(_year, _month)
    const dayCount: number = solarMonth.getDayCount()
    dayColumns = initDays(dayCount, 'gregorian')
  }
  state.displayColumns = [yearColumns, monthColumns, dayColumns, hourColumns]
}

// 8.当用户滑动列后触发
const onChangeColumn = (pickerView, value, columnIndex, resolve) => {
  // debugger
  // 1.更新birthday值
  const item = value[columnIndex]
  state.birthday[columnIndex] = Number(item.value)
  // 2.滑动列后重置后面的列
  for (let i = columnIndex + 1; i < 4; i++) {
    state.birthday[i] = 1
  }
  // 3.更新Columns列
  updateColumns([...state.birthday, state.birthdayIndex])
  // 4.更新pickerView
  if (columnIndex === 0) {
    pickerView.setColumnData(1, state.displayColumns[1])
    pickerView.setColumnData(2, state.displayColumns[2])
    pickerView.setColumnData(3, state.displayColumns[3])
  } else if (columnIndex === 1) {
    pickerView.setColumnData(2, state.displayColumns[2])
    pickerView.setColumnData(3, state.displayColumns[3])
  } else if (columnIndex === 2) {
    pickerView.setColumnData(3, state.displayColumns[3])
  }
  // 5.更新pickerView组件
  resolve()
}

// 9.当农历、公历切换时:
const onChangeTab = (index) => {
  state.pickerViewLoaded = true
  const [_year, _month, _day, _hour] = state.birthday
  // 1.农历转公历
  if (index.name === 1) {
    console.log('农历转公历前', index.name, state.birthday)
    const lunarHour = LunarHour.fromYmdHms(_year, _month, _day, _hour, 0, 0)
    const solarTime: SolarTime = lunarHour.getSolarTime()
    state.birthday = [
      solarTime.getYear(),
      solarTime.getMonth(),
      solarTime.getDay(),
      solarTime.getHour(),
    ]
    console.log('农历转公历后', index.name, state.birthday)
  }
  // 2.公历转农历
  if (index.name === 0) {
    console.log('公历转农历前', index.name, state.birthday)
    const solarTime = SolarTime.fromYmdHms(_year, _month, _day, _hour, 0, 0)
    const lunarHour = solarTime.getLunarHour()
    state.birthday = [
      lunarHour.getYear(),
      lunarHour.getMonth(),
      lunarHour.getDay(),
      lunarHour.getHour(),
    ]
    console.log('公历转农历后', index.name, state.birthday)
  }
  // 3.更新Columns列,注意此时state.birthdayIndex还未更新
  updateColumns([...state.birthday, index.name])
}

// 打开生日选择器
const openBirthdayPicker = () => {
  if (props.disabled) return
  state.popupShow = true
  const value = props.modelValue
  if (isNullBirthdayArray(value, 5)) {
    state.birthday = [1940, 1, 1, 1]
    state.birthdayIndex = 0
    return
  }
  state.birthday = [value[0], value[1], value[2], value[3]]
  state.birthdayIndex = value[4]
}

// 关闭生日选择器
const closeBirthdayPicker = () => {
  emit('update:modelValue', [...state.birthday, state.birthdayIndex])
  state.popupShow = false
}
</script>

<style lang="scss" scoped></style>

下一步建议

近期本人时间有限,暂不做改进,大佬们可以拿去做完善。

  1. 缺少 取消和确认 的操作。
  2. 组件不够通用,需要暴漏常用的函数和变量。
📌 [ 笔者 ]   文艺倾年
📃 [ 更新 ]   2024.12.22
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

在这里插入图片描述


http://www.kler.cn/a/450245.html

相关文章:

  • ROS1入门教程6:复杂行为处理
  • 模型优化之知识蒸馏
  • cudnn版本gpu架构
  • 【ArcGIS Pro微课1000例】0064:栅格目录、栅格数据集、镶嵌数据集
  • Android 代码模式的理解
  • Redis分布式锁释放锁是否必须用lua脚本?
  • 低代码可视化-uniapp进销存销售表单-代码生成器
  • LeetCode 2605 从两个数字数组里生成最小数字
  • Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
  • Echarts的高级使用,动画,交互api
  • Vue3:uv-upload图片上传
  • LeetCode:101. 对称二叉树
  • Vue3 组件 view-shadcn-ui 2024.5.3 发布
  • 如何利用Java爬虫按关键字搜索苏宁易购商品
  • 精准提升:从94.5%到99.4%——目标检测调优全纪录
  • 搭建Docker Harbor仓库
  • Qt5 cmake引用private头文件
  • scrapy 融合selenium
  • web的五个Observer API
  • 过滤掉list中两个连续的元素
  • C# 文件系统I/O操作--什么是I/O
  • day14-补充静态网卡配置
  • git 提交代码无法连接:Failed to connect to github.com port 443 after 21060 ms
  • 数据结构:双向循坏链表
  • 一文搞懂MYSQL、SQL、SQLServer、SQLyog的区别和联系
  • 英语四六级备考必备:2015-2024年历年真题+解析全汇总