From 687d36d548c5fc3671d45d07af754f457bb87cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Wed, 17 Aug 2022 18:11:28 +0800 Subject: [PATCH] feat:create date picker dom --- src/editor/assets/css/date/datePicker.css | 208 ++++++++++++++++++ .../core/draw/particle/date/DateParticle.ts | 55 ++++- .../core/draw/particle/date/DatePicker.ts | 123 ++++++++++- 3 files changed, 373 insertions(+), 13 deletions(-) diff --git a/src/editor/assets/css/date/datePicker.css b/src/editor/assets/css/date/datePicker.css index 1917dac..ffdad15 100644 --- a/src/editor/assets/css/date/datePicker.css +++ b/src/editor/assets/css/date/datePicker.css @@ -1,7 +1,215 @@ .date-container { display: none; + width: 300px; + overflow: hidden; + left: 0; + right: 0; + position: absolute; + color: #606266; + background: #ffffff; + border-radius: 4px; + padding: 10px; + user-select: none; + border: 1px solid #e4e7ed; + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); } .date-container.active { display: block; +} + +.date-wrap { + display: none; +} + +.date-wrap.active { + display: block; +} + +.date-title { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + color: #606266; + font-size: 16px; +} + +.date-title>span { + display: inline-block; +} + +.date-title>span:not(.date-title__now) { + font-family: cursive; + cursor: pointer; +} + +.date-title>span:not(.date-title__now):hover { + color: #5175F4; +} + +.date-title .date-title__pre-year { + width: 15%; +} + +.date-title .date-title__pre-month { + width: 15%; +} + +.date-title .date-title__now { + width: 40%; +} + +.date-title .date-title__next-year { + width: 15%; +} + +.date-title .date-title__next-month { + width: 15%; +} + +.date-week { + width: 100%; + display: flex; + justify-content: center; + margin-top: 15px; + padding-bottom: 5px; + border-bottom: 1px solid #e4e7ed; +} + +.date-week>span { + list-style: none; + width: calc(100%/7); + text-align: center; + color: #606266; + font-size: 14px; +} + +.date-day { + width: 100%; + display: flex; + flex-wrap: wrap; + align-items: center; + margin-top: 5px; +} + +.date-day>div { + width: calc(100%/7); + height: 40px; + text-align: center; + color: #606266; + font-size: 14px; + cursor: pointer; + line-height: 40px; + border-radius: 4px; +} + +.date-day>div:hover { + color: #5175F4; + opacity: .8; +} + +.date-day>div.active { + color: #5175F4; + font-weight: 700; +} + +.date-day>div.disable { + color: #c0c4cc; +} + +.date-day>div.select { + color: #fff; + background-color: #5175F4; +} + +.time-wrap { + display: none; + padding: 10px; + height: 286px; +} + +.time-wrap ::-webkit-scrollbar { + width: 0; +} + +.time-wrap.active { + display: flex; +} + +.time-wrap li { + list-style: none; +} + +.time-wrap>li { + width: 33.3%; + height: 100%; + text-align: center; +} + +.time-wrap>li>span { + transform: translateY(-5px); + display: inline-block; +} + +.time-wrap>li>ol { + height: calc(100% - 20px); + overflow-y: auto; + border: 1px solid #e2e2e2; +} + +.time-wrap>li:first-child>ol { + border-right: 0; +} + +.time-wrap>li:last-child>ol { + border-left: 0; +} + +.time-wrap>li>ol>li { + line-height: 30px; +} + +.date-menu { + width: 100%; + height: 28px; + display: flex; + justify-content: flex-end; + align-items: center; + padding-top: 10px; + position: relative; + border-top: 1px solid #e4e7ed; +} + +.date-menu button { + display: inline-block; + line-height: 1; + white-space: nowrap; + cursor: pointer; + background: #fff; + border: 1px solid #dcdfe6; + color: #606266; + appearance: none; + text-align: center; + box-sizing: border-box; + outline: none; + margin: 0; + transition: .1s; + font-weight: 500; + user-select: none; + padding: 7px 15px; + font-size: 12px; + border-radius: 3px; + margin-left: 10px; +} + +.date-menu button.date-menu__time { + border: 1px solid transparent; + position: absolute; + left: 0; + margin-left: 0; +} + +.date-menu button.date-menu__time:hover { + color: #5175F4; } \ No newline at end of file diff --git a/src/editor/core/draw/particle/date/DateParticle.ts b/src/editor/core/draw/particle/date/DateParticle.ts index dadec21..c62270e 100644 --- a/src/editor/core/draw/particle/date/DateParticle.ts +++ b/src/editor/core/draw/particle/date/DateParticle.ts @@ -1,26 +1,75 @@ +import { ElementType } from '../../../../dataset/enum/Element' import { IElement, IElementPosition } from '../../../../interface/Element' import { IRowElement } from '../../../../interface/Row' +import { RangeManager } from '../../../range/RangeManager' import { Draw } from '../../Draw' import { DatePicker } from './DatePicker' export class DateParticle { + private draw: Draw + private range: RangeManager private datePicker: DatePicker constructor(draw: Draw) { + this.draw = draw + this.range = draw.getRange() this.datePicker = new DatePicker({ mountDom: draw.getContainer() }) } + public getDateElementList(): IElement[] { + let leftIndex = -1 + let rightIndex = -1 + const { startIndex, endIndex } = this.range.getRange() + if (!~startIndex && !~endIndex) return [] + const elementList = this.draw.getElementList() + const startElement = elementList[startIndex] + if (startElement.type !== ElementType.DATE) return [] + // 向左查找 + let preIndex = startIndex + while (preIndex > 0) { + const preElement = elementList[preIndex] + if (preElement.dateId !== startElement.dateId) { + leftIndex = preIndex + break + } + preIndex-- + } + // 向右查找 + let nextIndex = startIndex + 1 + while (nextIndex < elementList.length) { + const nextElement = elementList[nextIndex] + if (nextElement.dateId !== startElement.dateId) { + rightIndex = nextIndex - 1 + break + } + nextIndex++ + } + // 控件在最后 + if (nextIndex === elementList.length) { + rightIndex = nextIndex - 1 + } + if (!~leftIndex || !~rightIndex) return [] + return elementList.slice(leftIndex + 1, rightIndex + 1) + } + public clearDatePicker() { this.datePicker.dispose() } public renderDatePicker(element: IElement, position: IElementPosition) { - console.log('element: ', element) - console.log('position: ', position) - this.datePicker.render() + const height = this.draw.getHeight() + const pageGap = this.draw.getPageGap() + const startTop = this.draw.getPageNo() * (height + pageGap) + const value = this.getDateElementList().map(el => el.value).join('') + this.datePicker.render({ + value, + element, + position, + startTop + }) } public render(ctx: CanvasRenderingContext2D, element: IRowElement, x: number, y: number) { diff --git a/src/editor/core/draw/particle/date/DatePicker.ts b/src/editor/core/draw/particle/date/DatePicker.ts index dad1b60..09a2683 100644 --- a/src/editor/core/draw/particle/date/DatePicker.ts +++ b/src/editor/core/draw/particle/date/DatePicker.ts @@ -1,9 +1,13 @@ +import { IElement, IElementPosition } from '../../../../interface/Element' + export interface IDatePickerOption { mountDom?: HTMLElement } interface IDatePickerDom { container: HTMLDivElement; + dateWrap: HTMLDivElement; + timeWrap: HTMLUListElement; title: { preYear: HTMLSpanElement; preMonth: HTMLSpanElement; @@ -12,6 +16,11 @@ interface IDatePickerDom { nextYear: HTMLSpanElement; }; day: HTMLDivElement; + time: { + hour: HTMLOListElement; + minute: HTMLOListElement; + second: HTMLOListElement; + }; menu: { time: HTMLButtonElement; now: HTMLButtonElement; @@ -19,11 +28,20 @@ interface IDatePickerDom { }; } +interface IRenderOption { + value: string; + element: IElement; + position: IElementPosition; + startTop: number; +} + export class DatePicker { private options: IDatePickerOption private now: Date private dom: IDatePickerDom + private renderOptions: IRenderOption | null + private isDatePicker: boolean constructor(options: IDatePickerOption = {}) { this.options = { @@ -32,6 +50,8 @@ export class DatePicker { } this.now = new Date() this.dom = this._createDom() + this.renderOptions = null + this.isDatePicker = true this._bindEvent() } @@ -39,6 +59,8 @@ export class DatePicker { const datePickerContainer = document.createElement('div') datePickerContainer.classList.add('date-container') // title-切换年月、年月显示 + const dateWrap = document.createElement('div') + dateWrap.classList.add('date-wrap') const datePickerTitle = document.createElement('div') datePickerTitle.classList.add('date-title') const preYearTitle = document.createElement('span') @@ -72,12 +94,47 @@ export class DatePicker { // day-天数显示 const datePickerDay = document.createElement('div') datePickerDay.classList.add('date-day') + // 日期内容构建 + dateWrap.append(datePickerTitle) + dateWrap.append(datePickerWeek) + dateWrap.append(datePickerDay) + // time-时间选择 + const timeWrap = document.createElement('ul') + timeWrap.classList.add('time-wrap') + let hourTime: HTMLOListElement + let minuteTime: HTMLOListElement + let secondTime: HTMLOListElement + const timeList = ['时', '分', '秒'] + timeList.forEach((t, i) => { + const li = document.createElement('li') + const timeText = document.createElement('span') + timeText.innerText = t + li.append(timeText) + const ol = document.createElement('ol') + const isHour = i === 0 + const isMinute = i === 1 + const endIndex = isHour ? 24 : 60 + for (let i = 0; i < endIndex; i++) { + const time = document.createElement('li') + time.innerText = `${String(i).padStart(2, '0')}` + ol.append(time) + } + if (isHour) { + hourTime = ol + } else if (isMinute) { + minuteTime = ol + } else { + secondTime = ol + } + li.append(ol) + timeWrap.append(li) + }) // menu-选择时间、现在、确定 const datePickerMenu = document.createElement('div') datePickerMenu.classList.add('date-menu') const timeMenu = document.createElement('button') timeMenu.classList.add('date-menu__time') - timeMenu.innerText = '时间' + timeMenu.innerText = '时间选择' const nowMenu = document.createElement('button') nowMenu.classList.add('date-menu__now') nowMenu.innerText = '此刻' @@ -88,13 +145,14 @@ export class DatePicker { datePickerMenu.append(nowMenu) datePickerMenu.append(submitMenu) // 构建 - datePickerContainer.append(datePickerTitle) - datePickerContainer.append(datePickerWeek) - datePickerContainer.append(datePickerDay) + datePickerContainer.append(dateWrap) + datePickerContainer.append(timeWrap) datePickerContainer.append(datePickerMenu) this.options.mountDom!.append(datePickerContainer) return { container: datePickerContainer, + dateWrap, + timeWrap, title: { preYear: preYearTitle, preMonth: preMonthTitle, @@ -103,6 +161,11 @@ export class DatePicker { nextYear: nextYearTitle }, day: datePickerDay, + time: { + hour: hourTime!, + minute: minuteTime!, + second: secondTime! + }, menu: { time: timeMenu, now: nowMenu, @@ -124,6 +187,10 @@ export class DatePicker { this.dom.title.nextYear.onclick = () => { this._nextYear() } + this.dom.menu.time.onclick = () => { + this.isDatePicker = !this.isDatePicker + this._toggleDateTimePicker() + } this.dom.menu.now.onclick = () => { this._now() } @@ -132,15 +199,32 @@ export class DatePicker { } } + private _setPosition() { + if (!this.renderOptions) return + const { + position: { + coordinate: { + leftTop: [left, top] + }, + lineHeight + }, + startTop + } = this.renderOptions + // 位置 + this.dom.container.style.left = `${left}px` + this.dom.container.style.top = `${top + startTop + lineHeight}px` + } + private _setNow() { this.now = new Date() } private _update() { - // 本地年月 + // 本地年月日 const localDate = new Date() const localYear = localDate.getFullYear() const localMonth = localDate.getMonth() + 1 + const localDay = localDate.getDate() // 当前年月日 const year = this.now.getFullYear() const month = this.now.getMonth() + 1 @@ -163,20 +247,23 @@ export class DatePicker { dayDom.innerText = `${i}` dayDom.onclick = () => { this.now = new Date(year, month - 2, i) - this.dispose() + this._update() } this.dom.day.append(dayDom) } // 渲染当月日期 for (let i = 1; i <= curDay; i++) { const dayDom = document.createElement('div') - if (localYear === year && localMonth === month && i === day) { + if (localYear === year && localMonth === month && localDay === i) { dayDom.classList.add('active') } + if (i === day) { + dayDom.classList.add('select') + } dayDom.innerText = `${i}` dayDom.onclick = () => { this.now = new Date(year, month - 1, i) - this.dispose() + this._update() } this.dom.day.append(dayDom) } @@ -188,12 +275,24 @@ export class DatePicker { dayDom.innerText = `${i}` dayDom.onclick = () => { this.now = new Date(year, month, i) - this.dispose() + this._update() } this.dom.day.append(dayDom) } } + private _toggleDateTimePicker() { + if (this.isDatePicker) { + this.dom.dateWrap.classList.add('active') + this.dom.timeWrap.classList.remove('active') + this.dom.menu.time.innerText = `时间选择` + } else { + this.dom.dateWrap.classList.remove('active') + this.dom.timeWrap.classList.add('active') + this.dom.menu.time.innerText = `返回日期` + } + } + private _preMonth() { this.now.setMonth(this.now.getMonth() - 1) this._update() @@ -227,9 +326,13 @@ export class DatePicker { } } - public render() { + public render(option: IRenderOption) { + this.renderOptions = option this._setNow() this._update() + this._setPosition() + this.isDatePicker = true + this._toggleDateTimePicker() this._toggleVisible(true) }