“This is the 21st day of my participation in the First Challenge 2022. For details: First Challenge 2022”
Project source: gitee.com/yang-yiming…
I haven’t done this series for a few days, because I want to do it bit by bit, and there are many possible changes. Excuse me, everybody.
This article implements tasks detailed in a drawer.Our implementation effect
Train of thought
- When we click on the task, open the drawer and display the content of the task.
- Write the drawer as a component
<TaskDetail>
In the task component<TaskItem>
Referenced in the - in
<TaskItem>
To define a variable visible passed into the component<TaskDetail>
In, control drawer switch - The same will be
<TaskDetail>
To show the required data, pass it to props. - Drawers contain headings, task details, and time displays and revisions.
Open dry
The new file
New Folder
file
TSX we performed a type constraint on props.
- Data is the data of a task component, including five items
- Visible is a variable that controls drawer opening and closing
- HandleClose is a callback function used to close the drawer. When the drawer is closed, the child component passes a value to the parent component to change the visible value in the parent component.
- TimeTag is the value of the timeTag that we store when we create the task, so we don’t have to do the processing in this component
import styles from './index.less';
import { Drawer, Input,Popover,Tag,DatePicker } from 'antd';
import { useEffect, useState } from 'react';
import { CloseOutlined, CalendarOutlined } from '@ant-design/icons';
import IconFont from '@/public/Icon/index';
import 'moment/locale/zh-cn';
interface TaskDetailProps {
data: data;
visible: boolean;
handleClose: () = > void;
timeTag:string;
}
interface data {
title: string;
desc: string;
startTime: string;
endTime: string;
status: 'doing' | 'done';
}
export default function TaskDetail(props: TaskDetailProps) {
return (
<div>Task details</div>
);
}
Copy the code
Add drawers and switch
Imported components
Some of these are for later use and are quoted here first.
import styles from './index.less';
import { Drawer, Input,Popover,Tag,DatePicker } from 'antd';
import { useEffect, useState } from 'react';
import { CloseOutlined, CalendarOutlined } from '@ant-design/icons';
import IconFont from '@/public/Icon/index';
Copy the code
The parameters are
- Placement =” Right “Popbox on the right
- OnClose ={handleClose} closes the drawer function
- Visible ={visible} Show drawer
- Keyboard ={true} Specifies whether to enable esc
- Closable ={false} does it show the off button in the top left corner because it’s on the left, which is kind of obtrusive let’s get rid of it and write another icon for the off button
export default function TaskDetail(props: TaskDetailProps) {
const { TextArea } = Input;
// Decompose the props content
const { data, visible, handleClose,timeTag } = props;
// Submit the parameters to be used after modification
const [submitData, setSubmitData] = useState({
title: ' '.desc: ' '.startTime: ' '.endTime: ' '.status: ' '});return (
<Drawer placement="right" onClose={handleClose} visible={visible} keyboard={true} closable={false}>
<div className={styles.container}>
<div className={styles.close}>
<CloseOutlined onClick={handleClose} />
</div>
</div>
</Drawer>
);
}
Copy the code
Corresponding style
.container {
width: 100%;
.close {
width: 100%;
height: 30px;
text-align: right; }}Copy the code
Task title input box
The normal I use here does not use antDesign components. We don’t want an input border here.
<div className={styles.inputCon}>
<input
className={styles.input}
value={submitData.title}
onChange={e= >{ setSubmitData({ ... submitData, title: e.target.value }); }} / >
</div>
Copy the code
The corresponding style
.inputCon {
width: 100%;
.input {
/** remove the border */
border: 0;
outline: none;
border: none;
width: 100%;
/** Change the color */
outline-color: "red";
font-size: 20px; }}Copy the code
Task description text box
const { TextArea } = Input;
<div className={styles.desc}>
<TextArea/ / of the five elementsrows={5}// Whether to display the word countshowCount={true}
value={submitData.desc}// Maximum number of wordsmaxLength={100}
onChange={e= >{ setSubmitData({ ... submitData, desc: e.target.value }); }} / ></div>
Copy the code
The corresponding style
.desc {
margin-top: 20px;
}
Copy the code
time
Display content switch
// Toggle time labels and buttons
const [isBtnShow,setIsBtnShow] = useState(false)
Copy the code
This part is all the processing time written before, the main logic is:
- Click the Today, Tomorrow, Customize button to change the display state of the time picker to True. Click call today, call tomorrow
chooseDefaultTime
function - After clicking the custom time button, disable today and tomorrow buttons
// The time used by the time selector and tag
const [defaultTime, setDefaultTime] = useState<any>({
time: ' '.tag: ' '});// Whether to display the time selector when you customize the time
const [datePickShow, setDefinedDatePick] = useState(false);
Copy the code
<div className={styles.calender}>
// Calendar icon
<div className={styles.iconCon}>
<CalendarOutlined style={{ fontSize: '17px' }} />
</div>
<div className={styles.dateCon}>
{
!isBtnShow ? (
<>
<div
className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
setDefinedDatePick(true)
chooseDefaultTime('today');
}}
>
<IconFont type="iconjintian" className={styles.icon} />today</div>
<div
className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
setDefinedDatePick(true)
chooseDefaultTime('tomorrow');
}}
>
<IconFont type="icona-rili2" className={styles.icon} />tomorrow</div>
<div
className={styles.time_btn}
onClick={()= > {
setDefinedDatePick(true)
}}
>
<IconFont type="icona-rili3" className={styles.icon} />The custom</div>
</>) : (<>
<Tag closable onClose={closeTag} className={styles.tag} color="gold" style={{ padding: '5px'}}onClick={()= >{setDefinedDatePick(true)}}>
{defaultTime.tag}
</Tag>
</>
)
}
</div>
</div>
</div>
Copy the code
The same method is used to add tasks
// Select today and tomorrow
const chooseDefaultTime = (day: string) = > {
if (day == 'today') {
const time = moment(moment().format('YYYY-MM-DD 18:00'));
const tag = `${moment().format('M month DD date ')}18:00 ` (today);
setDefaultTime({ time, tag });
} else if (day == 'tomorrow') {
const time = moment(moment().add(1.'days').format('YYYY-MM-DD 18:00'));
const tag = `${moment().add(1.'days').format('M month DD date ')}18:00 ` (tomorrow); setDefaultTime({ time, tag }); }};// Modify the date in the time picker
const changeDate = (date:any) = > {
const todayStart = moment(moment().format('YYYY-MM-DD 00:00'));
const yestardayStart = moment(moment(todayStart).subtract(1.'days'));
const todayEnd = moment(moment().format('YYYY-MM-DD 24:00'));
const tomorrowEnd = moment(moment(todayEnd).add(1.'days'));
console.log(tomorrowEnd, 'tomorrowEndtomorrowEnd');
let today = ' ';
if (todayStart < date && date < todayEnd) {
today = '(today);
} else if (todayEnd < date && date < tomorrowEnd) {
today = '(tomorrow);
} else if (yestardayStart < date && date < todayStart) {
today = '(yesterday);
} else {
today = ` (week${moment(date).day() == 0 ? 'day' : moment(date).day()}) `;
}
setDefaultTime({ time: date, tag: moment(date).format(` on DD MM${today} HH:mm`)}); };/ / closing Tag
const closeTag = () = > {
setDefinedDatePick(false);
setIsBtnShow(false)};Copy the code
Time selector
Remove the input field
When we create the task time picker, there is an input box, click to open the time picker.
We don’t want this input box here today
Direct use ofopen={datePickShow}
A switch that controls the time selector.
But the input box is still there
There was nothing else I could do, so I covered the input field with a layer of divs. The following className is dateConwrap
<DatePicker
showTime
open={datePickShow}
defaultValue={defaultTime.time}
locale={locale}
onOk={() = >{setDefinedDatePick(false); setIsBtnShow(true)}}
autoFocus
onChange={e= >{ changeDate(e); }} / ><div className={styles.dateConwrap}></div>
Copy the code
.dateConwrap{
position:absolute;
width:90%;
height:40px;
background-color: #fff;
}
Copy the code
The complete code
index.tsx
import styles from './index.less';
import { Drawer, Input,Popover,Tag,DatePicker } from 'antd';
import { useEffect, useState } from 'react';
import { CloseOutlined, CalendarOutlined } from '@ant-design/icons';
import IconFont from '@/public/Icon/index';
import 'moment/locale/zh-cn';
// Time selector bottom English --> Chinese
import locale from 'antd/lib/date-picker/locale/zh_CN';
import moment from 'moment';
interface TaskDetailProps {
data: data;
visible: boolean;
handleClose: () = > void;
timeTag:string;
}
interface data {
title: string;
desc: string;
startTime: string;
endTime: string;
status: 'doing' | 'done';
}
export default function TaskDetail(props: TaskDetailProps) {
const { TextArea } = Input;
const { data, visible, handleClose,timeTag } = props;
const [submitData, setSubmitData] = useState({
title: ' '.desc: ' '.startTime: ' '.endTime: ' '.status: ' '});// The time used by the time selector and tag
const [defaultTime, setDefaultTime] = useState<any>({
time: ' '.tag: ' '});const [isBtnShow,setIsBtnShow] = useState(false)
// Whether to display the time selector when you customize the time
const [datePickShow, setDefinedDatePick] = useState(false);
// Select today and tomorrow
const chooseDefaultTime = (day: string) = > {
if (day == 'today') {
const time = moment(moment().format('YYYY-MM-DD 18:00'));
const tag = `${moment().format('M month DD date ')}18:00 ` (today);
setDefaultTime({ time, tag });
} else if (day == 'tomorrow') {
const time = moment(moment().add(1.'days').format('YYYY-MM-DD 18:00'));
const tag = `${moment().add(1.'days').format('M month DD date ')}18:00 ` (tomorrow); setDefaultTime({ time, tag }); }};// Modify the date in the time picker
const changeDate = (date:any) = > {
const todayStart = moment(moment().format('YYYY-MM-DD 00:00'));
const yestardayStart = moment(moment(todayStart).subtract(1.'days'));
const todayEnd = moment(moment().format('YYYY-MM-DD 24:00'));
const tomorrowEnd = moment(moment(todayEnd).add(1.'days'));
console.log(tomorrowEnd, 'tomorrowEndtomorrowEnd');
let today = ' ';
if (todayStart < date && date < todayEnd) {
today = '(today);
} else if (todayEnd < date && date < tomorrowEnd) {
today = '(tomorrow);
} else if (yestardayStart < date && date < todayStart) {
today = '(yesterday);
} else {
today = ` (week${moment(date).day() == 0 ? 'day' : moment(date).day()}) `;
}
setDefaultTime({ time: date, tag: moment(date).format(` on DD MM${today} HH:mm`)}); };/ / closing Tag
const closeTag = () = > {
setDefinedDatePick(false);
setIsBtnShow(false)}; useEffect(() = > {
setSubmitData(data);
setDefaultTime({
// time:endTime,
tag:timeTag,
})
console.log(timeTag,'timeTagtimeTagtimeTag') timeTag? setIsBtnShow(true):setIsBtnShow(false)
}, [data]);
console.log(submitData);
return (
<Drawer placement="right" onClose={handleClose} visible={visible} keyboard={true} closable={false}>
<div className={styles.container}>
<div className={styles.close}>
<CloseOutlined onClick={handleClose} />
</div>
<div className={styles.inputCon}>
<input
className={styles.input}
value={submitData.title}
onChange={e= >{ setSubmitData({ ... submitData, title: e.target.value }); }} / ></div>
<div className={styles.desc}>
<TextArea
rows={5}
showCount={true}
value={submitData.desc}
maxLength={100}
onChange={e= >{ setSubmitData({ ... submitData, desc: e.target.value }); }} / ></div>
<div className={styles.calender}>
<div className={styles.iconCon}>
<CalendarOutlined style={{ fontSize: '17px' }} />
</div>
<div className={styles.dateCon}>
{
!isBtnShow ? (
<>
<div
className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
setDefinedDatePick(true)
chooseDefaultTime('today');
}}
>
<IconFont type="iconjintian" className={styles.icon} />today</div>
<div
className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
setDefinedDatePick(true)
chooseDefaultTime('tomorrow');
}}
>
<IconFont type="icona-rili2" className={styles.icon} />tomorrow</div>
<div
className={styles.time_btn}
onClick={()= > {
setDefinedDatePick(true)
}}
>
<IconFont type="icona-rili3" className={styles.icon} />The custom</div>
</>) : (<>
<Tag closable onClose={closeTag} className={styles.tag} color="gold" style={{ padding: '5px'}}onClick={()= >{setDefinedDatePick(true)}}>
{defaultTime.tag}
</Tag>
</>)}<DatePicker
showTime
open={datePickShow}
defaultValue={defaultTime.time}
locale={locale}
onOk={()= >{setDefinedDatePick(false); setIsBtnShow(true)}} autoFocus onChange={e => { changeDate(e); }} / ><div className={styles.dateConwrap}></div>
</div>
</div>
</div>
</Drawer>
);
}
Copy the code
index.less
.container {
width: 100%;
.close {
width: 100%;
height: 30px;
text-align: right;
}
.inputCon {
width: 100%;
.input {
border: 0;
outline: none;
border: none;
width: 100%;
/** Change the color */
outline-color: "red";
font-size: 20px; }}.desc {
margin-top: 20px;
}
.calender {
width: 100%;
margin-top: 40px;
display: flex;
// height:40px;
.iconCon {
width: 30px;
display: flex;
align-items: center;
vertical-align: middle;
}
.tag{
z-index:10;
}
.dateConwrap{
position:absolute;
width:90%;
height:40px;
background-color: #fff;
}
.dateCon {
flex:1;
display: flex;
.time_btn {
margin-top: 4px;
padding: 5px;
font-size: 12px;
background-color: #f5f1f1;
z-index: 10;
border-radius: 5px;
&:hover {
background-color: #cfcbcb ;
}
.icon {
font-size: 15px;
margin-right: 3px; }}.time_btn:nth-child(n+2) {
margin-left: 5px; }}} :global{
.ant-picker-input{
// display: none;
}
.ant-picker{
width:30px; }}}Copy the code