修改element-plus中的日期选择器和日历的样式

2,453 阅读6分钟

el-data-picker日期选择器

我们先看最终实现的效果图

image.png

下面是代码:

<template>
  <div id="box">
    <el-date-picker popper-class="data-style" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="pickerOptions" :inline="true">
      <template #default="{ date }">
        <div class="date-wrapper">
          <div :class="getCustomClass(date)">
            {{ date.getDate() }}
            <span v-if="highlightedDates.includes(formatDate(date))" class="red-dot">已租出</span>
          </div>
        </div>
      </template>
    </el-date-picker>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { ElDatePicker } from 'element-plus'

// const selectedDate = ref('')
const highlightedDates = ['2023-09-16', '2023-10-23', '2023-10-24', '2023-10-27', '2023-10-26', '2023-10-29', '2023-11-01', '2023-12-24', '2023-11-02', '2023-11-03', '2023-11-05', '2023-11-23']

const pickerOptions = {
  disabledDate: (time) => {
    const date = new Date(time)
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
    return highlightedDates.indexOf(`${year}-${month}-${day}`) === -1
  },
}

function formatDate(date) {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  return `${year}-${month}-${day}`
}

function getCustomClass(date) {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const formattedDate = `${year}-${month}-${day}`

  if (highlightedDates.includes(formattedDate)) {
    return 'red-date'
  }

  return ''
}
</script>
<!-- 因为日历组件还没有显示出来,所以我们无法通过深度监听来拿到日历弹层就需要另外写一个style样式表,没有样式隔离 -->
<style lang="scss">
.data-style {
  // border: 1px solid red !important;
  // display: block !important;
  // 动态修改日历弹层的样式(不需要样式渗透)(如果不生效,记得添加 !important)
}
</style>

<style lang="scss" scoped>

.date-wrapper {
  position: relative;
}

.red-date {
  display: inline-block;
  border-radius: 50%;
  width: 20px;
  height: 20px;
  line-height: 20px;
  background-color: red;
  color: white;
  position: relative;
}

.red-dot {
  position: absolute;
  bottom: -18px;
  left: -4px;
  width: 100%;
  font-size: 10px;
  color: red;
  text-align: center;
  white-space: nowrap;
}
</style>

注意:

因为日历组件还没有显示出来,所以我们无法通过深度监听来拿到日历弹层就需要另外写一个style样式表,没有样式隔离

对上面的代码进行解释:

当用户浏览某个日期选择器时,该代码会为其提供一些特殊功能。下面是代码的详细解释:

  1. 首先,我们定义了一个数组变量 highlightedDates,其中包含一些已被选中的日期,这些日期将在日期选择器中以特殊方式标记。用户可以根据这些标记来选择可用日期。

  2. 接下来,我们创建了一个对象变量 pickerOptions,其中包含了一个 disabledDate 函数。这个函数用于禁用未被选中的日期,以确保用户不能选择已被租出的日期。pickerOptions 对象将作为选项传递给日期选择器组件。

  3. disabledDate 函数中,我们先获取了即将被渲染的日期 date。然后,我们使用 highlightedDates 数组来检查该日期是否存在于已被选中的日期中。如果存在,则返回 true,表示该日期被禁用,用户不能选择它。

  4. 最后,我们定义了一个 getCustomClass 函数。这个函数在渲染日期时被调用,用于决定日期的样式类。在本例中,我们根据日期是否在 highlightedDates 数组中来切换样式类。如果日期在数组中,我们将其样式类设置为 red-date,这样它将以特殊的红色样式显示。

为了增强代码的可读性和可维护性,我们还可以添加一些样式表。其中包含了一些定义 red-date 样式的规则,以及一些用于修改日期选择器样式的规则。这些样式表将确保日期选择器和标记样式的正确显示。

综上所述,这段代码利用 Element Plus 库的日期选择器组件,实现了以下功能:

  • 标记已经被选中的日期
  • 禁用已经被选中的日期,确保用户不能选择它们
  • 改变已选中日期的样式,以突出显示这些日期

el-calendar日历

我们先看最终实现的效果图

image.png

下面是代码

<template>
  <div>
    <el-calendar :value="selectedDate" :first-day-of-week="1">
      <template #date-cell="{ data }">
        <div class="day" :class="{ 'is-highlighted': checkIfDateHasReminder(data) }">
          <div class="day-number">{{ data.day.split('-')[2] }}</div>
          <div class="reminder" v-if="checkIfDateHasReminder(data)">已租出</div>
        </div>
      </template>
    </el-calendar>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const selectedDate = ref()
// 下面是我模拟的需要标注的日期,开发过程中可以将这个数据替换请求回来的数据
const highlightedDates = ['2023-09-16', '2023-10-23', '2023-10-24', '2023-10-27', '2023-10-26', '2023-10-29', '2023-11-01', '2023-12-24', '2023-11-02', '2023-11-03', '2023-11-05', '2023-11-23']

// 判断日期是否是我们需要标注的日期
const checkIfDateHasReminder = (data) => {
  if (highlightedDates.includes(data.day)) {
    return true
  }
  return false
}
</script>

<style lang="scss" scoped>
:deep(.el-calendar) {
  width: 648px;
  height: 404px;
}
:deep(.el-calendar-table .el-calendar-day) {
  width: 60px;
  height: 60px;
  margin-left: 12px;
}

:deep(.el-calendar-day) {
  border: none;
}
:deep(.el-calendar__week) {
  border: none;
}
:deep(.el-calendar__date) {
  border: none;
}
:deep(.el-calendar__date:last-child) {
  border: none;
}
.day {
  text-align: center;

  .reminder {
    font-size: 12px;
  }
}

.day-number {
  margin-bottom: 5px;
}

.is-highlighted {
  color: red;
}
</style>

对上面的代码进行解释:

这段代码是一个使用 Vue.js 和 Element Plus 组件库实现的日期选择器组件。以下是对代码的详细解释:

  1. 在组件定义的 template 标签中,创建了一个名为 el-calendar 的 Element Plus el-calendar 组件。该组件绑定了一个响应式变量 selectedDate 以实现日期选中的双向绑定,同时设置了每周的第一天是星期一。
  2. 在组件模板内部,使用了 Element Plus 提供的插槽 date-cell,用来定义一个自定义日期单元格的展示方式。
  3. date-cell 插槽中,通过获取 data 参数来获取日期数据,用于决定是否需要对该日期进行标注。
  4. 使用开发者自定义的方法 checkIfDateHasReminder 对当前日期进行判断。如果该日期的 day 值在highlightedDates数组中存在,则添加 is-highlighted 类名,表示该日期需要被标注。同时判断是否需要显示 “已租出” 提示,如果需要,就在单元格中进行展示。
  5. 在组件中使用了嵌套的 div 元素,用来展示日期和 已租出 提示文字。
  6. 在组件的 script setup 标签中,使用了 Vue 的 ref 函数创建了一个响应式变量 selectedDate,并设置为默认空值。
  7. 创建了一个名为 highlightedDates 的数组,模拟了需要标注的日期数据。
  8. 创建了一个名为 checkIfDateHasReminder 的自定义方法,用来判断当前日期是否需要被标注。
  9. 在样式中使用了名为 :deep 的伪类选择器,用来穿透组件的作用域,设置了组件整体和日期单元格的外观样式。

注意

  1. 这里我们使用了element-plus中提供的插槽来获取到数据#date-cell="{ data }"这个data的结构是这样的。如果想要自定义结构,可以自己选择使用的属性。

image.png

  1. 上面的代码中的highlightedDates是我模拟的数据,在真实开发中,大家可以请求接口,拿回来数据
  2. {{ data.day.split('-')[2] }}这个位置是为了让日历显示日期而不显示年份。