first commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
:: BASE_DOC ::
|
||||
|
||||
## API
|
||||
|
||||
### Calendar Props
|
||||
|
||||
name | type | default | description | required
|
||||
-- | -- | -- | -- | --
|
||||
custom-style | Object | - | CSS(Cascading Style Sheets) | N
|
||||
allow-same-day | Boolean | false | \- | N
|
||||
auto-close | Boolean | true | \- | N
|
||||
confirm-btn | String / Object | '' | [see more ts definition](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts) | N
|
||||
first-day-of-week | Number | 0 | \- | N
|
||||
format | Function | - | Typescript: `CalendarFormatType ` `type CalendarFormatType = (day: TDate) => TDate` `type TDateType = 'selected' \| 'disabled' \| 'start' \| 'start-end' \|'centre' \| 'end' \| ''` `interface TDate { date: Date; day: number; type: TDateType; className?: string; prefix?: string; suffix?: string;}`。[see more ts definition](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts) | N
|
||||
locale-text | Object | - | Typescript: `CalendarLocaleText` `interface CalendarLocaleText {title?: string; weekdays?: string[]; monthTitle?: string; months?: string[]; confirm?: string;}`。[see more ts definition](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts) | N
|
||||
max-date | Number | - | \- | N
|
||||
min-date | Number | - | \- | N
|
||||
readonly | Boolean | - | \- | N
|
||||
switch-mode | String | none | options: none/month/year-month | N
|
||||
title | String | - | \- | N
|
||||
type | String | single | options: single/multiple/range | N
|
||||
use-popup | Boolean | true | \- | N
|
||||
using-custom-navbar | Boolean | false | \- | N
|
||||
value | Number / Array | - | `v-model:value` is supported。Typescript: `number \| number[]` | N
|
||||
default-value | Number / Array | - | uncontrolled property。Typescript: `number \| number[]` | N
|
||||
visible | Boolean | false | \- | N
|
||||
|
||||
### Calendar Events
|
||||
|
||||
name | params | description
|
||||
-- | -- | --
|
||||
change | `(context: { value: number \| number[] })` | \-
|
||||
close | `(context: { trigger: CalendarTrigger })` | [see more ts definition](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts)。<br/>`type CalendarTrigger = 'close-btn' \| 'confirm-btn' \| 'overlay' \| 'auto-close'`<br/>
|
||||
confirm | `(context: { value: number \| number[] })` | \-
|
||||
panel-change | `(context: { year: number, month: number })` | \-
|
||||
scroll | `(context: {scrollLeft: number, scrollTop: number, scrollHeight: number, scrollWidth: number, deltaX: number, deltaY: number})` | triggered when scrolling
|
||||
select | `(context: { value: number \| number[] })` | \-
|
||||
|
||||
### Calendar Slots
|
||||
|
||||
name | Description
|
||||
-- | --
|
||||
confirm-btn | \-
|
||||
title | \-
|
||||
|
||||
### CSS Variables
|
||||
|
||||
The component provides the following CSS variables, which can be used to customize styles.
|
||||
Name | Default Value | Description
|
||||
-- | -- | --
|
||||
--td-calendar-active-color | @brand-color | -
|
||||
--td-calendar-bg-color | @bg-color-container | -
|
||||
--td-calendar-days-color | @text-color-secondary | -
|
||||
--td-calendar-item-centre-color | @brand-color-light | -
|
||||
--td-calendar-item-disabled-color | @text-color-disabled | -
|
||||
--td-calendar-item-suffix-color | @text-color-placeholder | -
|
||||
--td-calendar-radius | 24rpx | -
|
||||
--td-calendar-selected-border-radius | @radius-default | -
|
||||
--td-calendar-selected-color | @text-color-anti | -
|
||||
--td-calendar-switch-mode-icon-color | @text-color-secondary | -
|
||||
--td-calendar-switch-mode-icon-disabled-color | @text-color-disabled | -
|
||||
--td-calendar-title-color | @text-color-primary | -
|
||||
--td-calendar-title-font | @font-title-large | -
|
||||
113
uni_modules/tdesign-uniapp/components/calendar/README.md
Normal file
113
uni_modules/tdesign-uniapp/components/calendar/README.md
Normal file
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: Calendar 日历
|
||||
description: 按照日历形式展示数据或日期的容器。
|
||||
spline: form
|
||||
isComponent: true
|
||||
---
|
||||
|
||||
|
||||
## 引入
|
||||
|
||||
可在 `main.ts` 或在需要使用的页面或组件中引入。
|
||||
|
||||
```js
|
||||
import TCalendar from '@tdesign/uniapp/calendar/calendar.vue';
|
||||
```
|
||||
|
||||
### 组件类型
|
||||
|
||||
#### 单个选择日历
|
||||
|
||||
{{ base }}
|
||||
|
||||
#### 多个选择日历
|
||||
|
||||
{{ multiple }}
|
||||
|
||||
#### 带单行/双行描述的日历
|
||||
|
||||
{{ custom-text }}
|
||||
|
||||
#### 带翻页功能的日历
|
||||
|
||||
{{ switch-mode }}
|
||||
|
||||
#### 可选择区间日期的日历
|
||||
|
||||
{{ range }}
|
||||
|
||||
### 组件样式
|
||||
|
||||
#### 国际化
|
||||
|
||||
{{ local-text }}
|
||||
|
||||
#### 含不可选的日历
|
||||
|
||||
{{ custom-range }}
|
||||
|
||||
#### 不使用 Popup
|
||||
|
||||
{{ without-popup }}
|
||||
|
||||
## API
|
||||
|
||||
### Calendar Props
|
||||
|
||||
名称 | 类型 | 默认值 | 描述 | 必传
|
||||
-- | -- | -- | -- | --
|
||||
custom-style | Object | - | 自定义样式 | N
|
||||
allow-same-day | Boolean | false | 是否允许区间选择日历的起止时间相同,仅当 `type='range'` 时有效 | N
|
||||
auto-close | Boolean | true | 自动关闭;在点击关闭按钮、确认按钮、遮罩层时自动关闭,不需要手动设置 visible | N
|
||||
confirm-btn | String / Object | '' | 确认按钮。值为 null 则不显示确认按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性。[详细类型定义](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts) | N
|
||||
first-day-of-week | Number | 0 | 第一天从星期几开始,默认 0 = 周日 | N
|
||||
format | Function | - | 用于格式化日期的函数。TS 类型:`CalendarFormatType ` `type CalendarFormatType = (day: TDate) => TDate` `type TDateType = 'selected' \| 'disabled' \| 'start' \| 'start-end' \|'centre' \| 'end' \| ''` `interface TDate { date: Date; day: number; type: TDateType; className?: string; prefix?: string; suffix?: string;}`。[详细类型定义](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts) | N
|
||||
locale-text | Object | - | 国际化文案。TS 类型:`CalendarLocaleText` `interface CalendarLocaleText {title?: string; weekdays?: string[]; monthTitle?: string; months?: string[]; confirm?: string;}`。[详细类型定义](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts) | N
|
||||
max-date | Number | - | 最大可选的日期,不传则默认半年后 | N
|
||||
min-date | Number | - | 最小可选的日期,不传则默认今天 | N
|
||||
readonly | Boolean | - | 是否只读,只读状态下不能选择日期 | N
|
||||
switch-mode | String | none | 切换模式。 `none` 表示平铺展示所有月份; `month` 表示支持按月切换, `year-month` 表示既按年切换,也支持按月切换。可选项:none/month/year-month | N
|
||||
title | String | - | 标题,不传默认为“请选择日期” | N
|
||||
type | String | single | 日历的选择类型,single = 单选;multiple = 多选; range = 区间选择。可选项:single/multiple/range | N
|
||||
use-popup | Boolean | true | 是否使用弹出层包裹日历 | N
|
||||
using-custom-navbar | Boolean | false | 是否使用了自定义导航栏 | N
|
||||
value | Number / Array | - | 当前选择的日期,不传则选用 minDate 属性值或今天,优先级:minDate > today。当 type = multiple 或 range 时传入数组。支持语法糖 `v-model:value`。TS 类型:`number \| number[]` | N
|
||||
default-value | Number / Array | - | 当前选择的日期,不传则选用 minDate 属性值或今天,优先级:minDate > today。当 type = multiple 或 range 时传入数组。非受控属性。TS 类型:`number \| number[]` | N
|
||||
visible | Boolean | false | 是否显示日历;`usePopup` 为 true 时有效 | N
|
||||
|
||||
### Calendar Events
|
||||
|
||||
名称 | 参数 | 描述
|
||||
-- | -- | --
|
||||
change | `(context: { value: number \| number[] })` | 不显示 confirm-btn 时,完成选择时触发(暂不支持 type = multiple)
|
||||
close | `(context: { trigger: CalendarTrigger })` | 关闭按钮时触发。[详细类型定义](https://github.com/tencent/tdesign-miniprogram/blob/develop/packages/uniapp-components/calendar/type.ts)。<br/>`type CalendarTrigger = 'close-btn' \| 'confirm-btn' \| 'overlay' \| 'auto-close'`<br/>
|
||||
confirm | `(context: { value: number \| number[] })` | 点击确认按钮时触发
|
||||
panel-change | `(context: { year: number, month: number })` | 切换月或年时触发(switch-mode 不为 none 时有效)
|
||||
scroll | `(context: {scrollLeft: number, scrollTop: number, scrollHeight: number, scrollWidth: number, deltaX: number, deltaY: number})` | 滚动时触发
|
||||
select | `(context: { value: number \| number[] })` | 点击日期时触发
|
||||
|
||||
### Calendar Slots
|
||||
|
||||
名称 | 描述
|
||||
-- | --
|
||||
confirm-btn | 确认按钮
|
||||
title | 标题
|
||||
|
||||
### CSS Variables
|
||||
|
||||
组件提供了下列 CSS 变量,可用于自定义样式。
|
||||
名称 | 默认值 | 描述
|
||||
-- | -- | --
|
||||
--td-calendar-active-color | @brand-color | -
|
||||
--td-calendar-bg-color | @bg-color-container | -
|
||||
--td-calendar-days-color | @text-color-secondary | -
|
||||
--td-calendar-item-centre-color | @brand-color-light | -
|
||||
--td-calendar-item-disabled-color | @text-color-disabled | -
|
||||
--td-calendar-item-suffix-color | @text-color-placeholder | -
|
||||
--td-calendar-radius | 24rpx | -
|
||||
--td-calendar-selected-border-radius | @radius-default | -
|
||||
--td-calendar-selected-color | @text-color-anti | -
|
||||
--td-calendar-switch-mode-icon-color | @text-color-secondary | -
|
||||
--td-calendar-switch-mode-icon-disabled-color | @text-color-disabled | -
|
||||
--td-calendar-title-color | @text-color-primary | -
|
||||
--td-calendar-title-font | @font-title-large | -
|
||||
@@ -0,0 +1,42 @@
|
||||
export default {
|
||||
tClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
classPrefix: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
switchMode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
preYearBtnDisable: {
|
||||
type: Boolean,
|
||||
},
|
||||
prevMonthBtnDisable: {
|
||||
type: Boolean,
|
||||
},
|
||||
nextYearBtnDisable: {
|
||||
type: Boolean,
|
||||
},
|
||||
nextMonthBtnDisable: {
|
||||
type: Boolean,
|
||||
},
|
||||
tId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// realLocalText: {
|
||||
// type: Object,
|
||||
// default: () => ({}),
|
||||
// },
|
||||
// currentMonth: {
|
||||
// type: Array,
|
||||
// default: () => ([]),
|
||||
// },
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<view
|
||||
:id="tId"
|
||||
:class="' ' + tClass + ' ' + classPrefix + ' '+(switchMode !== 'none' ? classPrefix + '__with-action' : '')"
|
||||
>
|
||||
<view
|
||||
v-if="switchMode !== 'none'"
|
||||
:class="classPrefix + '__action'"
|
||||
>
|
||||
<view
|
||||
v-if="switchMode === 'year-month'"
|
||||
:class="utils.cls(classPrefix + '__icon', [['disabled', preYearBtnDisable]])"
|
||||
:data-disabled="preYearBtnDisable"
|
||||
data-type="pre-year"
|
||||
@click="handleSwitchModeChange"
|
||||
>
|
||||
<t-icon name="chevron-left-double" />
|
||||
</view>
|
||||
<view
|
||||
:class="utils.cls(classPrefix + '__icon', [['disabled', prevMonthBtnDisable]])"
|
||||
:data-disabled="prevMonthBtnDisable"
|
||||
data-type="pre-month"
|
||||
@click="handleSwitchModeChange"
|
||||
>
|
||||
<t-icon name="chevron-left" />
|
||||
</view>
|
||||
</view>
|
||||
<view :class="classPrefix + '__title'">
|
||||
{{ title }}
|
||||
</view>
|
||||
<view
|
||||
v-if="switchMode !== 'none'"
|
||||
:class="classPrefix + '__action'"
|
||||
>
|
||||
<view
|
||||
:class="utils.cls(classPrefix + '__icon', [['disabled', nextMonthBtnDisable]])"
|
||||
:data-disabled="nextMonthBtnDisable"
|
||||
data-type="next-month"
|
||||
@click="handleSwitchModeChange"
|
||||
>
|
||||
<t-icon name="chevron-right" />
|
||||
</view>
|
||||
<view
|
||||
v-if="switchMode === 'year-month'"
|
||||
:class="utils.cls(classPrefix + '__icon', [['disabled', nextYearBtnDisable]])"
|
||||
:data-disabled="nextYearBtnDisable"
|
||||
data-type="next-year"
|
||||
@click="handleSwitchModeChange"
|
||||
>
|
||||
<t-icon name="chevron-right-double" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import TIcon from '../icon/icon.vue';
|
||||
import utils from '../common/utils.wxs';
|
||||
import props from './calendar-header.props';
|
||||
import { getMonthTitle } from './computed';
|
||||
|
||||
export default {
|
||||
name: 'TCalendarHeader',
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
components: {
|
||||
TIcon,
|
||||
},
|
||||
props: {
|
||||
...props,
|
||||
},
|
||||
emits: [
|
||||
'handleSwitchModeChange',
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
utils,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleSwitchModeChange(...args) {
|
||||
this.$emit('handleSwitchModeChange', ...args);
|
||||
},
|
||||
getMonthTitle,
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import './calendar.css';
|
||||
</style>
|
||||
205
uni_modules/tdesign-uniapp/components/calendar/calendar.css
Normal file
205
uni_modules/tdesign-uniapp/components/calendar/calendar.css
Normal file
@@ -0,0 +1,205 @@
|
||||
.t-calendar {
|
||||
width: inherit;
|
||||
position: relative;
|
||||
z-index: 9999;
|
||||
background: var(--td-calendar-bg-color, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.t-calendar--popup {
|
||||
border-top-left-radius: var(--td-calendar-radius, 24rpx);
|
||||
border-top-right-radius: var(--td-calendar-radius, 24rpx);
|
||||
}
|
||||
.t-calendar__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font: var(--td-calendar-title-font, var(--td-font-title-large, 600 36rpx / 52rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular)));
|
||||
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
|
||||
padding: var(--td-spacer-2, 32rpx);
|
||||
}
|
||||
.t-calendar__title:focus {
|
||||
outline: 0;
|
||||
}
|
||||
.t-calendar__close-btn {
|
||||
position: absolute;
|
||||
top: var(--td-spacer-2, 32rpx);
|
||||
right: var(--td-spacer-2, 32rpx);
|
||||
margin: calc(-1 * var(--td-spacer-1, 24rpx));
|
||||
padding: var(--td-spacer-1, 24rpx);
|
||||
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
|
||||
}
|
||||
.t-calendar__days {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
grid-column-gap: 8rpx;
|
||||
padding: 0 32rpx;
|
||||
text-align: center;
|
||||
line-height: 92rpx;
|
||||
}
|
||||
.t-calendar__days-item {
|
||||
height: 92rpx;
|
||||
font-size: 28rpx;
|
||||
color: var(--td-calendar-days-color, var(--td-text-color-secondary, var(--td-font-gray-2, rgba(0, 0, 0, 0.6))));
|
||||
}
|
||||
.t-calendar__content {
|
||||
min-height: 400rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.t-calendar__month {
|
||||
font: var(--td-font-title-small, 600 28rpx / 44rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular));
|
||||
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
|
||||
padding: 32rpx 0 0;
|
||||
}
|
||||
.t-calendar__months {
|
||||
height: 712rpx;
|
||||
padding: 0 32rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.t-calendar__months::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.t-calendar__dates {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
grid-column-gap: 8rpx;
|
||||
}
|
||||
.t-calendar__dates-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font: var(--td-font-title-medium, 600 32rpx / 48rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular));
|
||||
border-radius: var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx));
|
||||
height: 120rpx;
|
||||
margin-top: 16rpx;
|
||||
color: var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.t-calendar__dates-item-prefix,
|
||||
.t-calendar__dates-item-suffix {
|
||||
position: absolute;
|
||||
font: var(--td-font-body-extraSmall, 20rpx / 32rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular));
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.t-calendar__dates-item-prefix {
|
||||
top: 8rpx;
|
||||
}
|
||||
.t-calendar__dates-item-suffix {
|
||||
bottom: 8rpx;
|
||||
color: var(--td-calendar-item-suffix-color, var(--td-text-color-placeholder, var(--td-font-gray-3, rgba(0, 0, 0, 0.4))));
|
||||
}
|
||||
.t-calendar__dates-item-suffix--selected,
|
||||
.t-calendar__dates-item-suffix--start,
|
||||
.t-calendar__dates-item-suffix--end {
|
||||
color: var(--td-calendar-selected-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
|
||||
}
|
||||
.t-calendar__dates-item-suffix--disabled {
|
||||
color: var(--td-calendar-item-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
|
||||
}
|
||||
.t-calendar__dates-item--selected,
|
||||
.t-calendar__dates-item--start-end,
|
||||
.t-calendar__dates-item--start,
|
||||
.t-calendar__dates-item--end {
|
||||
background: var(--td-calendar-active-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
|
||||
color: var(--td-calendar-selected-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
|
||||
border-radius: var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx));
|
||||
}
|
||||
.t-calendar__dates-item--start {
|
||||
border-radius: var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx)) 0 0 var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx));
|
||||
}
|
||||
.t-calendar__dates-item--end {
|
||||
border-radius: 0 var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx)) var(--td-calendar-selected-border-radius, var(--td-radius-default, 12rpx)) 0;
|
||||
}
|
||||
.t-calendar__dates-item--start + .t-calendar__dates-item--end::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 8rpx;
|
||||
height: 100%;
|
||||
background: var(--td-calendar-active-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
|
||||
}
|
||||
.t-calendar__dates-item--start + .t-calendar__dates-item--end:before {
|
||||
left: -8rpx;
|
||||
}
|
||||
.t-calendar__dates-item--centre {
|
||||
border-radius: 0;
|
||||
background-color: var(--td-calendar-item-centre-color, var(--td-brand-color-light, var(--td-primary-color-1, #f2f3ff)));
|
||||
}
|
||||
.t-calendar__dates-item--centre::before,
|
||||
.t-calendar__dates-item--centre::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 8rpx;
|
||||
height: 100%;
|
||||
background-color: var(--td-calendar-item-centre-color, var(--td-brand-color-light, var(--td-primary-color-1, #f2f3ff)));
|
||||
}
|
||||
.t-calendar__dates-item--centre:before {
|
||||
left: -8rpx;
|
||||
}
|
||||
.t-calendar__dates-item--centre:after {
|
||||
right: -8rpx;
|
||||
}
|
||||
.t-calendar__dates-item--disabled {
|
||||
color: var(--td-calendar-item-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
|
||||
cursor: default;
|
||||
}
|
||||
.t-calendar__footer {
|
||||
padding: 32rpx;
|
||||
}
|
||||
.t-calendar-switch-mode--none > .t-calendar__months {
|
||||
height: 60vh;
|
||||
}
|
||||
.t-calendar-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.t-calendar-header__with-action {
|
||||
padding: 0rpx 32rpx 16rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
.t-calendar-header__with-action::after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: unset;
|
||||
bottom: 0;
|
||||
left: unset;
|
||||
right: unset;
|
||||
background-color: var(--td-border-color, var(--td-gray-color-3, #e7e7e7));
|
||||
}
|
||||
.t-calendar-header__with-action::after {
|
||||
height: 1px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
.t-calendar-header__with-action .t-calendar-header__title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font: var(--td-font-title-small, 600 28rpx / 44rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular));
|
||||
}
|
||||
.t-calendar-header__action {
|
||||
display: flex;
|
||||
font-size: 40rpx;
|
||||
color: var(--td-calendar-switch-mode-icon-color, var(--td-text-color-secondary, var(--td-font-gray-2, rgba(0, 0, 0, 0.6))));
|
||||
}
|
||||
.t-calendar-header__icon {
|
||||
padding: 16rpx;
|
||||
}
|
||||
.t-calendar-header__icon--disabled {
|
||||
color: var(--td-calendar-switch-mode-icon-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
|
||||
}
|
||||
.t-calendar-header__title {
|
||||
text-align: left;
|
||||
}
|
||||
454
uni_modules/tdesign-uniapp/components/calendar/calendar.vue
Normal file
454
uni_modules/tdesign-uniapp/components/calendar/calendar.vue
Normal file
@@ -0,0 +1,454 @@
|
||||
<template>
|
||||
<view>
|
||||
<t-popup
|
||||
v-if="usePopup"
|
||||
:visible="visible"
|
||||
:using-custom-navbar="usingCustomNavbar"
|
||||
:custom-navbar-height="customNavbarHeight"
|
||||
placement="bottom"
|
||||
@visible-change="onVisibleChange"
|
||||
>
|
||||
<CalendarTemplate
|
||||
:class-prefix="classPrefix"
|
||||
:use-popup="usePopup"
|
||||
:switch-mode="switchMode"
|
||||
:t-class="tClass"
|
||||
:custom-style="tools._style([customStyle])"
|
||||
:title="title"
|
||||
:real-local-text="realLocalText"
|
||||
:months="months"
|
||||
:current-month="currentMonth"
|
||||
:action-buttons="actionButtons"
|
||||
:days="days"
|
||||
:scroll-into-view="scrollIntoView"
|
||||
:first-day-of-week="firstDayOfWeek"
|
||||
:inner-confirm-btn="innerConfirmBtn"
|
||||
@scroll="onScroll"
|
||||
@close="handleClose"
|
||||
@select="handleSelect"
|
||||
@clickButton="onTplButtonTap"
|
||||
@handleSwitchModeChange="handleSwitchModeChange"
|
||||
>
|
||||
<template #confirm-btn>
|
||||
<slot name="confirm-btn" />
|
||||
</template>
|
||||
<template #title>
|
||||
<slot name="title" />
|
||||
</template>
|
||||
</CalendarTemplate>
|
||||
</t-popup>
|
||||
<block v-else>
|
||||
<CalendarTemplate
|
||||
:class-prefix="classPrefix"
|
||||
:use-popup="usePopup"
|
||||
:switch-mode="switchMode"
|
||||
:t-class="tClass"
|
||||
:custom-style="tools._style([customStyle])"
|
||||
:title="title"
|
||||
:real-local-text="realLocalText"
|
||||
:months="months"
|
||||
:current-month="currentMonth"
|
||||
:action-buttons="actionButtons"
|
||||
:days="days"
|
||||
:scroll-into-view="scrollIntoView"
|
||||
:first-day-of-week="firstDayOfWeek"
|
||||
:inner-confirm-btn="innerConfirmBtn"
|
||||
@scroll="onScroll"
|
||||
@close="handleClose"
|
||||
@select="handleSelect"
|
||||
@clickButton="onTplButtonTap"
|
||||
@handleSwitchModeChange="handleSwitchModeChange"
|
||||
>
|
||||
<template #confirm-btn>
|
||||
<slot name="confirm-btn" />
|
||||
</template>
|
||||
<template #title>
|
||||
<slot name="title" />
|
||||
</template>
|
||||
</CalendarTemplate>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import TPopup from '../popup/popup';
|
||||
import TButton from '../button/button';
|
||||
import TIcon from '../icon/icon';
|
||||
import CalendarTemplate from './template.vue';
|
||||
|
||||
import { uniComponent } from '../common/src/index';
|
||||
import { prefix } from '../common/config';
|
||||
import { coalesce } from '../common/utils';
|
||||
|
||||
import props from './props';
|
||||
import TCalendar from '../common/shared/calendar/index';
|
||||
import useCustomNavbar from '../mixins/using-custom-navbar';
|
||||
import { getPrevMonth, getPrevYear, getNextMonth, getNextYear } from './utils';
|
||||
import tools from '../common/utils.wxs';
|
||||
import {
|
||||
getMonthTitle,
|
||||
getDateLabel,
|
||||
isDateSelected,
|
||||
} from './computed.js';
|
||||
|
||||
|
||||
const name = `${prefix}-calendar`;
|
||||
|
||||
|
||||
const defaultLocaleText = {
|
||||
title: '请选择日期',
|
||||
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
monthTitle: '{year} 年 {month}',
|
||||
months: ['1 月', '2 月', '3 月', '4 月', '5 月', '6 月', '7 月', '8 月', '9 月', '10 月', '11 月', '12 月'],
|
||||
confirm: '确认',
|
||||
};
|
||||
|
||||
export default uniComponent({
|
||||
name,
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
controlledProps: [
|
||||
{
|
||||
key: 'value',
|
||||
event: 'confirm',
|
||||
},
|
||||
{
|
||||
key: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
],
|
||||
externalClasses: [
|
||||
`${prefix}-class`,
|
||||
],
|
||||
mixins: [useCustomNavbar],
|
||||
components: {
|
||||
TPopup,
|
||||
TButton,
|
||||
TIcon,
|
||||
CalendarTemplate,
|
||||
},
|
||||
props: {
|
||||
...props,
|
||||
},
|
||||
emits: [
|
||||
'update:visible',
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
prefix,
|
||||
classPrefix: name,
|
||||
months: [],
|
||||
scrollIntoView: '',
|
||||
innerConfirmBtn: {},
|
||||
realLocalText: {},
|
||||
currentMonth: {},
|
||||
actionButtons: {
|
||||
preYearBtnDisable: false,
|
||||
prevMonthBtnDisable: false,
|
||||
nextMonthBtnDisable: false,
|
||||
nextYearBtnDisable: false,
|
||||
},
|
||||
tools,
|
||||
|
||||
dataVisible: this.visible,
|
||||
dataValue: coalesce(this.value, this.defaultValue),
|
||||
days: [],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
type: {
|
||||
handler(v) {
|
||||
this.base.type = v;
|
||||
},
|
||||
},
|
||||
|
||||
allowSameDay(v) {
|
||||
this.base.allowSameDay = v;
|
||||
},
|
||||
|
||||
confirmBtn: {
|
||||
handler(v) {
|
||||
if (typeof v === 'string') {
|
||||
this.innerConfirmBtn = v === 'slot' ? 'slot' : { content: v };
|
||||
} else if (typeof v === 'object') {
|
||||
this.innerConfirmBtn = v;
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
|
||||
firstDayOfWeek: 'onWatchMinMaxDate',
|
||||
minDate: 'onWatchMinMaxDate',
|
||||
maxDate: 'onWatchMinMaxDate',
|
||||
|
||||
value: {
|
||||
handler(v) {
|
||||
this.dataValue = v;
|
||||
},
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
|
||||
visible: {
|
||||
handler(v) {
|
||||
this.dataVisible = v;
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
|
||||
dataValue: {
|
||||
handler(v) {
|
||||
this.base.value = v;
|
||||
this.calcMonths();
|
||||
this.updateCurrentMonth(Array.isArray(v) ? v[0] : v);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
|
||||
dataVisible: {
|
||||
handler(v) {
|
||||
if (v) {
|
||||
this.onScrollIntoView();
|
||||
this.base.value = this.dataValue;
|
||||
this.calcMonths();
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
format: {
|
||||
handler(v) {
|
||||
const { usePopup, dataVisible: visible } = this;
|
||||
|
||||
if (this.base) {
|
||||
this.base.format = v;
|
||||
}
|
||||
|
||||
if (!usePopup || visible) {
|
||||
this.calcMonths();
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const values = Object.keys(props).reduce((acc, key) => ({
|
||||
...acc,
|
||||
[key]: this[key],
|
||||
}));
|
||||
this.base = new TCalendar(values);
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const realLocalText = { ...defaultLocaleText, ...this.localeText };
|
||||
this.initialValue();
|
||||
this.onWatchMinMaxDate();
|
||||
this.days = this.base.getDays(realLocalText.weekdays);
|
||||
this.realLocalText = realLocalText;
|
||||
|
||||
this.calcMonths();
|
||||
this.updateCurrentMonth();
|
||||
|
||||
if (!this.usePopup) {
|
||||
this.onScrollIntoView();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMonthTitle,
|
||||
getDateLabel,
|
||||
isDateSelected,
|
||||
initialValue() {
|
||||
const { dataValue: value, type, minDate } = this;
|
||||
|
||||
if (!value) {
|
||||
const today = new Date();
|
||||
const now = minDate || new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime(); // 获取 0 点的时间戳
|
||||
const initialValue = type === 'single' ? now : [now];
|
||||
|
||||
if (type === 'range') {
|
||||
initialValue[1] = now + 24 * 3600 * 1000; // 第二天
|
||||
}
|
||||
|
||||
this.dataValue = initialValue;
|
||||
this.base.value = initialValue;
|
||||
}
|
||||
},
|
||||
|
||||
onScrollIntoView() {
|
||||
const { dataValue: value } = this;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
const date = new Date(Array.isArray(value) ? value[0] : value);
|
||||
|
||||
if (date) {
|
||||
this.scrollIntoView = `year_${date.getFullYear()}_month_${date.getMonth()}`;
|
||||
}
|
||||
},
|
||||
|
||||
getCurrentYearAndMonth(v) {
|
||||
const date = new Date(v);
|
||||
return { year: date.getFullYear(), month: date.getMonth() };
|
||||
},
|
||||
|
||||
updateActionButton(value) {
|
||||
const _min = this.getCurrentYearAndMonth(this.base.minDate);
|
||||
const _max = this.getCurrentYearAndMonth(this.base.maxDate);
|
||||
const _value = this.getCurrentYearAndMonth(value);
|
||||
|
||||
const _minTimestamp = new Date(_min.year, _min.month, 1).getTime();
|
||||
const _maxTimestamp = new Date(_max.year, _max.month, 1).getTime();
|
||||
const _dateValue = new Date(_value.year, _value.month, 1);
|
||||
|
||||
const _prevYearTimestamp = getPrevYear(_dateValue).getTime();
|
||||
const _prevMonthTimestamp = getPrevMonth(_dateValue).getTime();
|
||||
const _nextMonthTimestamp = getNextMonth(_dateValue).getTime();
|
||||
const _nextYearTimestamp = getNextYear(_dateValue).getTime();
|
||||
|
||||
const preYearBtnDisable = _prevYearTimestamp < _minTimestamp || _prevMonthTimestamp < _minTimestamp;
|
||||
const prevMonthBtnDisable = _prevMonthTimestamp < _minTimestamp;
|
||||
const nextYearBtnDisable = _nextMonthTimestamp > _maxTimestamp || _nextYearTimestamp > _maxTimestamp;
|
||||
const nextMonthBtnDisable = _nextMonthTimestamp > _maxTimestamp;
|
||||
|
||||
this.actionButtons = {
|
||||
preYearBtnDisable,
|
||||
prevMonthBtnDisable,
|
||||
nextYearBtnDisable,
|
||||
nextMonthBtnDisable,
|
||||
};
|
||||
},
|
||||
|
||||
updateCurrentMonth(newValue) {
|
||||
if (this.switchMode === 'none') return;
|
||||
this.calcCurrentMonth(newValue);
|
||||
},
|
||||
|
||||
calcCurrentMonth(newValue) {
|
||||
const date = newValue || this.getCurrentDate();
|
||||
const { year, month } = this.getCurrentYearAndMonth(date);
|
||||
const currentMonth = this.months.filter(item => item.year === year && item.month === month);
|
||||
|
||||
this.updateActionButton(date);
|
||||
|
||||
this.currentMonth = currentMonth.length > 0 ? currentMonth : [this.months[0]];
|
||||
},
|
||||
|
||||
calcMonths() {
|
||||
if (!this.base) return;
|
||||
|
||||
const months = this.base.getMonths();
|
||||
|
||||
this.months = months;
|
||||
},
|
||||
|
||||
close(trigger) {
|
||||
if (this.autoClose) {
|
||||
this.$emit('update:visible', false);
|
||||
this.dataVisible = false;
|
||||
}
|
||||
this.$emit('close', { trigger });
|
||||
},
|
||||
|
||||
onVisibleChange() {
|
||||
this.close('overlay');
|
||||
},
|
||||
|
||||
handleClose() {
|
||||
this.close('close-btn');
|
||||
},
|
||||
|
||||
handleSelect(e) {
|
||||
const { readonly } = this;
|
||||
const { date, year, month } = e.currentTarget.dataset;
|
||||
|
||||
if (date.type === 'disabled' || readonly) return;
|
||||
|
||||
const rawValue = this.base.select({ cellType: date.type, year, month, date: date.day });
|
||||
|
||||
const value = this.toTime(rawValue);
|
||||
|
||||
this.calcMonths();
|
||||
this.updateCurrentMonth();
|
||||
|
||||
if (this.confirmBtn == null) {
|
||||
// 不显示确认按钮,则选择完即关闭 popup
|
||||
if (this.type === 'single' || rawValue.length === 2) {
|
||||
this.dataVisible = false;
|
||||
this._trigger('change', { value }); // 受控
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit('select', { value });
|
||||
},
|
||||
|
||||
onTplButtonTap() {
|
||||
const rawValue = this.base.getTrimValue();
|
||||
const value = this.toTime(rawValue);
|
||||
|
||||
this.close('confirm-btn');
|
||||
this._trigger('confirm', { value });
|
||||
},
|
||||
|
||||
toTime(val) {
|
||||
if (!val) return null;
|
||||
if (Array.isArray(val)) {
|
||||
return val.map(item => item.getTime());
|
||||
}
|
||||
return val.getTime();
|
||||
},
|
||||
|
||||
onScroll(e) {
|
||||
this.$emit('scroll', e.detail);
|
||||
},
|
||||
|
||||
getCurrentDate() {
|
||||
let time = Array.isArray(this.base.value) ? this.base.value[0] : this.base.value;
|
||||
|
||||
if (this.currentMonth.length > 0) {
|
||||
const year = this.currentMonth[0]?.year;
|
||||
const month = this.currentMonth[0]?.month;
|
||||
time = new Date(year, month, 1).getTime();
|
||||
}
|
||||
|
||||
return time;
|
||||
},
|
||||
|
||||
handleSwitchModeChange(e) {
|
||||
const { type, disabled } = e.currentTarget.dataset;
|
||||
if (disabled) return;
|
||||
|
||||
const date = this.getCurrentDate();
|
||||
|
||||
const funcMap = {
|
||||
'pre-year': () => getPrevYear(date),
|
||||
'pre-month': () => getPrevMonth(date),
|
||||
'next-month': () => getNextMonth(date),
|
||||
'next-year': () => getNextYear(date),
|
||||
};
|
||||
const newValue = funcMap[type]();
|
||||
if (!newValue) return;
|
||||
|
||||
const { year, month } = this.getCurrentYearAndMonth(newValue);
|
||||
this.$emit('panel-change', { year, month: month + 1 });
|
||||
|
||||
this.calcCurrentMonth(newValue);
|
||||
},
|
||||
|
||||
onWatchMinMaxDate() {
|
||||
const { firstDayOfWeek, minDate, maxDate } = this;
|
||||
firstDayOfWeek && (this.base.firstDayOfWeek = firstDayOfWeek);
|
||||
minDate && (this.base.minDate = minDate);
|
||||
maxDate && (this.base.maxDate = maxDate);
|
||||
this.calcMonths();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
@import './calendar.css';
|
||||
</style>
|
||||
<style scoped>
|
||||
.t-calendar-switch-mode--none > .t-calendar__months {
|
||||
/* support mp-alipay */
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
42
uni_modules/tdesign-uniapp/components/calendar/computed.js
Normal file
42
uni_modules/tdesign-uniapp/components/calendar/computed.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import { getRegExp } from '../common/runtime/wxs-polyfill';
|
||||
|
||||
|
||||
export function isDateSelected(dateItem) {
|
||||
return ['start', 'end', 'selected', 'centre'].indexOf(dateItem.type) >= 0;
|
||||
}
|
||||
|
||||
export function getMonthTitle(year, month, pattern = '') {
|
||||
// prettier-ignore
|
||||
const REGEXP = getRegExp('\\{year\\}|\\{month\\}', 'g');
|
||||
|
||||
return pattern.replace(REGEXP, (match) => {
|
||||
const replacements = {
|
||||
'{year}': year,
|
||||
'{month}': month < 10 ? `0${month}` : month,
|
||||
};
|
||||
return replacements[match] || match;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function getDateLabel(monthItem, dateItem) {
|
||||
const weekdayText = ['日', '一', '二', '三', '四', '五', '六'];
|
||||
const weekday = (monthItem.weekdayOfFirstDay + dateItem.day - 1) % 7;
|
||||
let label = `${monthItem.month + 1}月${dateItem.day}日, 星期${weekdayText[weekday]}`;
|
||||
if (dateItem.type === 'start') {
|
||||
label = `开始日期:${label}`;
|
||||
}
|
||||
if (dateItem.type === 'end') {
|
||||
label = `结束日期:${label}`;
|
||||
}
|
||||
if (isDateSelected(dateItem)) {
|
||||
label = `已选中, ${label}`;
|
||||
}
|
||||
if (dateItem.prefix) {
|
||||
label += `, ${dateItem.prefix}`;
|
||||
}
|
||||
if (dateItem.suffix) {
|
||||
label += `, ${dateItem.suffix}`;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
113
uni_modules/tdesign-uniapp/components/calendar/props.ts
Normal file
113
uni_modules/tdesign-uniapp/components/calendar/props.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
|
||||
* */
|
||||
|
||||
import type { TdCalendarProps } from './type';
|
||||
export default {
|
||||
/** 是否允许区间选择日历的起止时间相同,仅当 `type='range'` 时有效 */
|
||||
allowSameDay: Boolean,
|
||||
/** 自动关闭;在点击关闭按钮、确认按钮、遮罩层时自动关闭,不需要手动设置 visible */
|
||||
autoClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/** 确认按钮。值为 null 则不显示确认按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性 */
|
||||
confirmBtn: {
|
||||
type: [String, Object],
|
||||
default: '' as TdCalendarProps['confirmBtn'],
|
||||
},
|
||||
/** 第一天从星期几开始,默认 0 = 周日 */
|
||||
firstDayOfWeek: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
/** 用于格式化日期的函数 */
|
||||
format: {
|
||||
type: Function,
|
||||
},
|
||||
/** 国际化文案 */
|
||||
localeText: {
|
||||
type: Object,
|
||||
},
|
||||
/** 最大可选的日期,不传则默认半年后 */
|
||||
maxDate: {
|
||||
type: Number,
|
||||
},
|
||||
/** 最小可选的日期,不传则默认今天 */
|
||||
minDate: {
|
||||
type: Number,
|
||||
},
|
||||
/** 是否只读,只读状态下不能选择日期 */
|
||||
readonly: Boolean,
|
||||
/** 切换模式。 `none` 表示平铺展示所有月份; `month` 表示支持按月切换, `year-month` 表示既按年切换,也支持按月切换 */
|
||||
switchMode: {
|
||||
type: String,
|
||||
default: 'none' as TdCalendarProps['switchMode'],
|
||||
validator(val: TdCalendarProps['switchMode']): boolean {
|
||||
if (!val) return true;
|
||||
return ['none', 'month', 'year-month'].includes(val);
|
||||
},
|
||||
},
|
||||
/** 标题,不传默认为“请选择日期” */
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
/** 日历的选择类型,single = 单选;multiple = 多选; range = 区间选择 */
|
||||
type: {
|
||||
type: String,
|
||||
default: 'single' as TdCalendarProps['type'],
|
||||
validator(val: TdCalendarProps['type']): boolean {
|
||||
if (!val) return true;
|
||||
return ['single', 'multiple', 'range'].includes(val);
|
||||
},
|
||||
},
|
||||
/** 是否使用弹出层包裹日历 */
|
||||
usePopup: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/** 是否使用了自定义导航栏 */
|
||||
usingCustomNavbar: Boolean,
|
||||
/** 当前选择的日期,不传则选用 minDate 属性值或今天,优先级:minDate > today。当 type = multiple 或 range 时传入数组 */
|
||||
value: {
|
||||
type: [Number, Array],
|
||||
},
|
||||
/** 当前选择的日期,不传则选用 minDate 属性值或今天,优先级:minDate > today。当 type = multiple 或 range 时传入数组,非受控属性 */
|
||||
defaultValue: {
|
||||
type: [Number, Array],
|
||||
},
|
||||
/** 是否显示日历;`usePopup` 为 true 时有效 */
|
||||
visible: Boolean,
|
||||
/** 不显示 confirm-btn 时,完成选择时触发(暂不支持 type = multiple) */
|
||||
onChange: {
|
||||
type: Function,
|
||||
default: () => ({}),
|
||||
},
|
||||
/** 关闭按钮时触发 */
|
||||
onClose: {
|
||||
type: Function,
|
||||
default: () => ({}),
|
||||
},
|
||||
/** 点击确认按钮时触发 */
|
||||
onConfirm: {
|
||||
type: Function,
|
||||
default: () => ({}),
|
||||
},
|
||||
/** 切换月或年时触发(switch-mode 不为 none 时有效) */
|
||||
onPanelChange: {
|
||||
type: Function,
|
||||
default: () => ({}),
|
||||
},
|
||||
/** 滚动时触发 */
|
||||
onScroll: {
|
||||
type: Function,
|
||||
default: () => ({}),
|
||||
},
|
||||
/** 点击日期时触发 */
|
||||
onSelect: {
|
||||
type: Function,
|
||||
default: () => ({}),
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
export default {
|
||||
classPrefix: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
usePopup: {
|
||||
type: Boolean,
|
||||
},
|
||||
switchMode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
tClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
customStyle: {
|
||||
type: [String, Object],
|
||||
default: '',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
realLocalText: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
months: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
currentMonth: {
|
||||
type: [Array, Object],
|
||||
default: () => ([]),
|
||||
},
|
||||
actionButtons: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
days: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
scrollIntoView: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
firstDayOfWeek: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
innerConfirmBtn: {
|
||||
type: [Object, String],
|
||||
default: '',
|
||||
},
|
||||
};
|
||||
261
uni_modules/tdesign-uniapp/components/calendar/template.vue
Normal file
261
uni_modules/tdesign-uniapp/components/calendar/template.vue
Normal file
@@ -0,0 +1,261 @@
|
||||
<template>
|
||||
<view
|
||||
:class="utils.cls(classPrefix, [['popup', usePopup]]) + ' ' + classPrefix + '-switch-mode--' + switchMode + ' ' + tClass"
|
||||
:style="customStyle"
|
||||
>
|
||||
<view
|
||||
:class="classPrefix + '__title'"
|
||||
tabindex="0"
|
||||
>
|
||||
<slot name="title" />
|
||||
<text v-if="title || realLocalText.title">
|
||||
{{ title || realLocalText.title }}
|
||||
</text>
|
||||
</view>
|
||||
<t-icon
|
||||
v-if="usePopup"
|
||||
name="close"
|
||||
:t-class="classPrefix + '__close-btn'"
|
||||
size="48rpx"
|
||||
aria-role="button"
|
||||
aria-label="关闭"
|
||||
:custom-style="closeBtnCustomStyle"
|
||||
@click="handleClose"
|
||||
/>
|
||||
<block
|
||||
v-if="switchMode !== 'none'"
|
||||
name="calendar-header"
|
||||
>
|
||||
<calendar-header
|
||||
:class-prefix="classPrefix + '-header'"
|
||||
:switch-mode="switchMode"
|
||||
:title="getMonthTitle(
|
||||
currentMonth[0] && currentMonth[0].year,
|
||||
realLocalText.months && currentMonth[0] && realLocalText.months[currentMonth[0].month],
|
||||
realLocalText.monthTitle
|
||||
)"
|
||||
:pre-year-btn-disable="actionButtons.preYearBtnDisable"
|
||||
:prev-month-btn-disable="actionButtons.prevMonthBtnDisable"
|
||||
:next-year-btn-disable="actionButtons.nextYearBtnDisable"
|
||||
:next-month-btn-disable="actionButtons.nextMonthBtnDisable"
|
||||
@handleSwitchModeChange="handleSwitchModeChange"
|
||||
/>
|
||||
</block>
|
||||
<view
|
||||
aria-hidden
|
||||
:class="classPrefix + '__days'"
|
||||
>
|
||||
<view
|
||||
v-for="(item, index) in days"
|
||||
:key="index"
|
||||
:class="classPrefix + '__days-item'"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view
|
||||
:class="classPrefix + '__months'"
|
||||
:scroll-into-view="scrollIntoView"
|
||||
scroll-y
|
||||
enhanced
|
||||
:show-scrollbar="false"
|
||||
@scroll="onScroll"
|
||||
>
|
||||
<block
|
||||
v-for="(item, index) in switchMode === 'none' ? months : currentMonth"
|
||||
:key="index"
|
||||
>
|
||||
<block
|
||||
v-if="switchMode === 'none'"
|
||||
name="calendar-header"
|
||||
>
|
||||
<calendar-header
|
||||
:t-class="classPrefix + '__month'"
|
||||
:class-prefix="classPrefix + '-header'"
|
||||
:switch-mode="switchMode"
|
||||
:t-id="'year_' + item.year + '_month_' + item.month"
|
||||
:title="getMonthTitle(item.year, realLocalText.months && realLocalText.months[item.month], realLocalText.monthTitle)"
|
||||
:pre-year-btn-disable="actionButtons.preYearBtnDisable"
|
||||
:prev-month-btn-disable="actionButtons.prevMonthBtnDisable"
|
||||
:next-year-btn-disable="actionButtons.nextYearBtnDisable"
|
||||
:next-month-btn-disable="actionButtons.nextMonthBtnDisable"
|
||||
@handleSwitchModeChange="handleSwitchModeChange"
|
||||
/>
|
||||
</block>
|
||||
|
||||
<view :class="classPrefix + '__dates'">
|
||||
<view
|
||||
v-for="(item, index1) in (item.weekdayOfFirstDay - firstDayOfWeek + 7) % 7"
|
||||
:key="index1"
|
||||
/>
|
||||
<block
|
||||
v-for="(dateItem, dateIndex) in item.months"
|
||||
:key="dateIndex"
|
||||
>
|
||||
<view
|
||||
:class="classPrefix + '__dates-item ' + dateItem.className + ' ' + classPrefix + '__dates-item--' + dateItem.type"
|
||||
:data-year="item.year"
|
||||
:data-month="item.month"
|
||||
:data-date="dateItem"
|
||||
aria-role="button"
|
||||
:aria-label="getDateLabel(item, dateItem)"
|
||||
:aria-disabled="dateItem.type === 'disabled'"
|
||||
@click="handleSelect"
|
||||
>
|
||||
<view
|
||||
v-if="dateItem.prefix"
|
||||
:class="classPrefix + '__dates-item-prefix'"
|
||||
>
|
||||
{{ dateItem.prefix }}
|
||||
</view>
|
||||
{{ dateItem.day }}
|
||||
<view
|
||||
v-if="dateItem.suffix"
|
||||
:class="classPrefix + '__dates-item-suffix ' + classPrefix + '__dates-item-suffix--' + dateItem.type"
|
||||
>
|
||||
{{ dateItem.suffix }}
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view
|
||||
v-if="innerConfirmBtn != null && usePopup"
|
||||
:class="classPrefix + '__footer'"
|
||||
>
|
||||
<slot
|
||||
v-if="innerConfirmBtn === 'slot'"
|
||||
name="confirm-btn"
|
||||
/>
|
||||
<block v-else-if="innerConfirmBtn">
|
||||
<t-button
|
||||
:t-id="innerConfirmBtn.tId"
|
||||
:custom-style="innerConfirmBtn.style"
|
||||
:block="coalesce(innerConfirmBtn.block, true)"
|
||||
:t-class="coalesce(coalesce(innerConfirmBtn.tClass, prefix + '-class-action'))"
|
||||
:class="prefix + '-calendar__confirm-btn'"
|
||||
:disabled="innerConfirmBtn.disabled"
|
||||
:data-type="'action'"
|
||||
:data-extra="innerConfirmBtn.dataExtra"
|
||||
:custom-dataset="innerConfirmBtn.customDataset"
|
||||
:content="innerConfirmBtn.content || realLocalText.confirm"
|
||||
:icon="innerConfirmBtn.icon"
|
||||
:loading="innerConfirmBtn.loading"
|
||||
:loading-props="innerConfirmBtn.loadingProps"
|
||||
:theme="coalesce(innerConfirmBtn.theme, 'primary')"
|
||||
:ghost="innerConfirmBtn.ghost"
|
||||
:shape="innerConfirmBtn.shape"
|
||||
:size="innerConfirmBtn.size"
|
||||
:variant="innerConfirmBtn.variant"
|
||||
:open-type="innerConfirmBtn.openType"
|
||||
:hover-class="innerConfirmBtn.hoverClass"
|
||||
:hover-stop-propagation="innerConfirmBtn.hoverStopPropagation"
|
||||
:hover-start-time="innerConfirmBtn.hoverStartTime"
|
||||
:hover-stay-time="innerConfirmBtn.hoverStayTime"
|
||||
:lang="innerConfirmBtn.lang"
|
||||
:session-from="innerConfirmBtn.sessionFrom"
|
||||
:send-message-title="innerConfirmBtn.sendMessageTitle"
|
||||
:send-message-path="innerConfirmBtn.sendMessagePath"
|
||||
:send-message-img="innerConfirmBtn.sendMessageImg"
|
||||
:app-parameter="innerConfirmBtn.appParameter"
|
||||
:show-message-card="innerConfirmBtn.showMessageCard"
|
||||
:aria-label="innerConfirmBtn.ariaLabel"
|
||||
@click="onTplButtonTap"
|
||||
@getuserinfo="onTplButtonTap"
|
||||
@contact="onTplButtonTap"
|
||||
@getphonenumber="onTplButtonTap"
|
||||
@error="onTplButtonTap"
|
||||
@opensetting="onTplButtonTap"
|
||||
@launchapp="onTplButtonTap"
|
||||
@agreeprivacyauthorization="onTplButtonTap"
|
||||
>
|
||||
<slot v-if="innerConfirmBtn.useDefaultSlot" />
|
||||
</t-button>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import TIcon from '../icon/icon.vue';
|
||||
import TButton from '../button/button.vue';
|
||||
import utils from '../common/utils.wxs';
|
||||
import {
|
||||
getDateLabel,
|
||||
getMonthTitle,
|
||||
} from './computed.js';
|
||||
import CalendarHeader from './calendar-header.vue';
|
||||
import { prefix } from '../common/config';
|
||||
import { coalesce } from '../common/utils';
|
||||
import props from './template.props';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'TCalendarContent',
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
components: {
|
||||
CalendarHeader,
|
||||
TIcon,
|
||||
TButton,
|
||||
},
|
||||
props: {
|
||||
...props,
|
||||
},
|
||||
emits: [
|
||||
'clickButton',
|
||||
'close',
|
||||
'scroll',
|
||||
'select',
|
||||
'handleSwitchModeChange',
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
prefix,
|
||||
utils,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
closeBtnCustomStyle() {
|
||||
return utils._style({
|
||||
position: 'absolute',
|
||||
top: '16px',
|
||||
right: '16px',
|
||||
margin: '-12px',
|
||||
padding: '12px',
|
||||
color: 'var(--td-calendar-title-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, .9))))',
|
||||
});
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
coalesce,
|
||||
getDateLabel,
|
||||
getMonthTitle,
|
||||
onTplButtonTap() {
|
||||
this.$emit('clickButton');
|
||||
},
|
||||
handleSelect(...args) {
|
||||
this.$emit('select', ...args);
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
onScroll(...args) {
|
||||
this.$emit('scroll', ...args);
|
||||
},
|
||||
handleSwitchModeChange(...args) {
|
||||
this.$emit('handleSwitchModeChange', ...args);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
@import './calendar.css';
|
||||
</style>
|
||||
141
uni_modules/tdesign-uniapp/components/calendar/type.ts
Normal file
141
uni_modules/tdesign-uniapp/components/calendar/type.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
|
||||
* */
|
||||
|
||||
import type { TdButtonProps as ButtonProps } from '../button/type';
|
||||
|
||||
export interface TdCalendarProps {
|
||||
/**
|
||||
* 是否允许区间选择日历的起止时间相同,仅当 `type='range'` 时有效
|
||||
* @default false
|
||||
*/
|
||||
allowSameDay?: boolean;
|
||||
/**
|
||||
* 自动关闭;在点击关闭按钮、确认按钮、遮罩层时自动关闭,不需要手动设置 visible
|
||||
* @default true
|
||||
*/
|
||||
autoClose?: boolean;
|
||||
/**
|
||||
* 确认按钮。值为 null 则不显示确认按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性
|
||||
* @default ''
|
||||
*/
|
||||
confirmBtn?: string | ButtonProps | null;
|
||||
/**
|
||||
* 第一天从星期几开始,默认 0 = 周日
|
||||
* @default 0
|
||||
*/
|
||||
firstDayOfWeek?: number;
|
||||
/**
|
||||
* 用于格式化日期的函数
|
||||
*/
|
||||
format?: CalendarFormatType;
|
||||
/**
|
||||
* 国际化文案
|
||||
*/
|
||||
localeText?: CalendarLocaleText;
|
||||
/**
|
||||
* 最大可选的日期,不传则默认半年后
|
||||
*/
|
||||
maxDate?: number;
|
||||
/**
|
||||
* 最小可选的日期,不传则默认今天
|
||||
*/
|
||||
minDate?: number;
|
||||
/**
|
||||
* 是否只读,只读状态下不能选择日期
|
||||
*/
|
||||
readonly?: boolean;
|
||||
/**
|
||||
* 切换模式。 `none` 表示平铺展示所有月份; `month` 表示支持按月切换, `year-month` 表示既按年切换,也支持按月切换
|
||||
* @default none
|
||||
*/
|
||||
switchMode?: 'none' | 'month' | 'year-month';
|
||||
/**
|
||||
* 标题,不传默认为“请选择日期”
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* 日历的选择类型,single = 单选;multiple = 多选; range = 区间选择
|
||||
* @default single
|
||||
*/
|
||||
type?: 'single' | 'multiple' | 'range';
|
||||
/**
|
||||
* 是否使用弹出层包裹日历
|
||||
* @default true
|
||||
*/
|
||||
usePopup?: boolean;
|
||||
/**
|
||||
* 是否使用了自定义导航栏
|
||||
* @default false
|
||||
*/
|
||||
usingCustomNavbar?: boolean;
|
||||
/**
|
||||
* 当前选择的日期,不传则选用 minDate 属性值或今天,优先级:minDate > today。当 type = multiple 或 range 时传入数组
|
||||
*/
|
||||
value?: number | number[];
|
||||
/**
|
||||
* 当前选择的日期,不传则选用 minDate 属性值或今天,优先级:minDate > today。当 type = multiple 或 range 时传入数组,非受控属性
|
||||
*/
|
||||
defaultValue?: number | number[];
|
||||
/**
|
||||
* 是否显示日历;`usePopup` 为 true 时有效
|
||||
* @default false
|
||||
*/
|
||||
visible?: boolean;
|
||||
/**
|
||||
* 不显示 confirm-btn 时,完成选择时触发(暂不支持 type = multiple)
|
||||
*/
|
||||
onChange?: (context: { value: number | number[] }) => void;
|
||||
/**
|
||||
* 关闭按钮时触发
|
||||
*/
|
||||
onClose?: (context: { trigger: CalendarTrigger }) => void;
|
||||
/**
|
||||
* 点击确认按钮时触发
|
||||
*/
|
||||
onConfirm?: (context: { value: number | number[] }) => void;
|
||||
/**
|
||||
* 切换月或年时触发(switch-mode 不为 none 时有效)
|
||||
*/
|
||||
onPanelChange?: (context: { year: number; month: number }) => void;
|
||||
/**
|
||||
* 滚动时触发
|
||||
*/
|
||||
onScroll?: (context: {
|
||||
scrollLeft: number;
|
||||
scrollTop: number;
|
||||
scrollHeight: number;
|
||||
scrollWidth: number;
|
||||
deltaX: number;
|
||||
deltaY: number;
|
||||
}) => void;
|
||||
/**
|
||||
* 点击日期时触发
|
||||
*/
|
||||
onSelect?: (context: { value: number | number[] }) => void;
|
||||
}
|
||||
|
||||
export type CalendarFormatType = (day: TDate) => TDate;
|
||||
|
||||
export type TDateType = 'selected' | 'disabled' | 'start' | 'start-end' | 'centre' | 'end' | '';
|
||||
|
||||
export interface TDate {
|
||||
date: Date;
|
||||
day: number;
|
||||
type: TDateType;
|
||||
className?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
}
|
||||
|
||||
export interface CalendarLocaleText {
|
||||
title?: string;
|
||||
weekdays?: string[];
|
||||
monthTitle?: string;
|
||||
months?: string[];
|
||||
confirm?: string;
|
||||
}
|
||||
|
||||
export type CalendarTrigger = 'close-btn' | 'confirm-btn' | 'overlay' | 'auto-close';
|
||||
16
uni_modules/tdesign-uniapp/components/calendar/utils.js
Normal file
16
uni_modules/tdesign-uniapp/components/calendar/utils.js
Normal file
@@ -0,0 +1,16 @@
|
||||
export function getMonthByOffset(date, offset) {
|
||||
const _date = new Date(date);
|
||||
_date.setMonth(_date.getMonth() + offset);
|
||||
return _date;
|
||||
}
|
||||
|
||||
export function getYearByOffset(date, offset) {
|
||||
const _date = new Date(date);
|
||||
_date.setFullYear(_date.getFullYear() + offset);
|
||||
return _date;
|
||||
}
|
||||
|
||||
export const getPrevMonth = date => getMonthByOffset(date, -1);
|
||||
export const getNextMonth = date => getMonthByOffset(date, 1);
|
||||
export const getPrevYear = date => getYearByOffset(date, -1);
|
||||
export const getNextYear = date => getYearByOffset(date, 1);
|
||||
Reference in New Issue
Block a user