“This is the 16th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
Project source: gitee.com/yang-yiming…
This article implements the add task
Create a file
Create a new AddTask component under TaskList/ Components
index.tsx
Let’s take a look at what variables we need, and their types, because our data is used inside the component, so we don’t need props.
- First, you need to think about the content.
- Task time, preferably with create time, and deadline.
- There are also mouse focus on the input box and not the input box state, to switch styles.
import styles from './index.less';
interface AddTask{
content:string;
startTime:string;
endTime:string;
clickStatu:boolean;
showTime: boolean;
}
export default function AddTask() {
const [task, setTask] = useState<AddTask>({
content:' '.startTime:' '.endTime:' '.clickStatu:false.showTime: false;
})
return (
<div className={styles.task_add}>
</div>
);
}
Copy the code
Perfect style function
Before clicking
index.tsx
- Through the task. ClickStatu
true/false
To switch. - We’re using ICONS here,
<PlusOutlined>
The importimport {PlusOutlined} from '@ant-design/icons'
import styles from './index.less';
import {useState} from 'react';
import {PlusOutlined} from '@ant-design/icons'
import {Input} from 'antd'
interface AddTask{
content:string;
startTime:string;
endTime:string;
clickStatu:boolean;
}
export default function AddTask() {
const [task, setTask] = useState<AddTask>({
content:' '.startTime:' '.endTime:' '.clickStatu:false
})
return (
<div className={styles.task_add}>
{
task.clickStatu ? <div>11</div> :
<div className={styles.task_add_before} onClick={()= >{setTask({... task, clickStatu:true})}}><div className={styles.task_add_before_icon_container}>
<PlusOutlined className={styles.task_add_before_icon} />
</div>
<div className={styles.task_add_before_name}>Add tasks</div>
</div>
}
</div>
);
}
Copy the code
index.less
.task_add {
box-shadow: 0 0 1px 1px #dddadaad;
transition: all .4s cubic-bezier(.215.610.355.1);
background: white;
margin-bottom: 8px;
border-radius: 5px;
margin: 3px 20px 10px 10px;
&_before {
height: 50px;
width: 100%;
display: flex;
&_icon_container {
width: 30px;
line-height: 50px;
padding-left: 10px;
.task_add_before_icon {
font-size: 20px;
color: #3372fe;
cursor: pointer;
:hover {
font-size: 22px;
color: #2565ee; }}}&_name {
color: #ada7a7;
line-height: 50px;
padding-left: 10px; }}}Copy the code
We achieved the following effect and clicked to switch to another state (the add content state to be written below).
Click [Add Content]
At the top is an input box, below are today, tomorrow and custom times, as well as create buttons and cancel buttons.Here’s what we achieved
I’ll post the entire code here and then break it down
import styles from './index.less';
import React, { useState, useEffect } from 'react';
import { PlusOutlined, CloseCircleOutlined } from '@ant-design/icons';
import IconFont from '@/public/Icon';
import { Input, Button, Tag, DatePicker, Popover } from 'antd';
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 AddTask {
content: string;
startTime: string;
endTime: string;
clickStatu: boolean;
showTime: boolean;
}
export default function AddTask() {
const [task, setTask] = useState<AddTask>({
content: ' '.startTime: ' '.endTime: ' '.clickStatu: true.showTime: false});// 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 [definedDatePickShow, setDefinedDatePick] = useState(false);
// useRef
const inputRef = React.useRef<any>(null);
// Input gets the focus configuration parameter
const sharedProps = {
style: { width: '100%' },
ref: inputRef,
};
/ / closing Tag
const closeTag = () = >{ setTask({ ... task,showTime: false });
};
// Cancel the task
const onCancle = () = >{ setTask({ ... task,clickStatu: false });
};
// Modify the date in the time picker
const changeDate = date= > {
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`)}); };// Create a task
const onCreate = () = > {
console.log(defaultTime);
};
// 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 });
}
setDefinedDatePick(false);
};
useEffect(() = > {
// Click on the true state to get Input into focustask.clickStatu ? inputRef.current! .focus({cursor: 'start' }) : ' ';
}, [task.clickStatu]);
return (
<div className={styles.task_add}>
{task.clickStatu ? (
<div className={styles.task_add_after}>
<Input {. sharedProps} placeholder="Enter task content" />
<div className={styles.btn_container}>
{task.showTime && (
<div>
<Popover
placement="bottomLeft"
title={"'}content={(
<DatePicker
showTime
defaultValue={defaultTime.time}
locale={locale}
autoFocus
onChange={e= > {
changeDate(e);
}}
/>
)}
trigger="click"
>
<Tag closable onClose={closeTag} color="gold" style={{ padding: '5px' }}>
{defaultTime.tag}
</Tag>
</Popover>
</div>)} {! task.showTime && (<div className={styles.time_btn_container}>
<div
className={` ${styles.time_btn} ${definedDatePickShow ? styles.disabled :"'} `}onClick={()= >{ setTask({ ... task, showTime: true }); chooseDefaultTime('today'); }} ><IconFont type="iconjintian" className={styles.icon} />today</div>
<div
className={` ${styles.time_btn} ${definedDatePickShow ? styles.disabled :"'} `}onClick={()= >{ setTask({ ... task, showTime: 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>
{definedDatePickShow ? (
<div style={{ height: '30px', lineHeight: '40px', marginLeft: '30px' }}>
<DatePicker
showTime
defaultValue={defaultTime.time}
locale={locale}
autoFocus
style={{ height: '30px', lineHeight: '40px'}}onChange={e= >{ changeDate(e); }} / ><span style={{ marginLeft: '3px', color: '#1890ff' }}>{'}<CloseCircleOutlined
onClick={()= >{ setDefinedDatePick(false); }} / ></span>
</div>
) : (
<span />
)}
</div>
)}
<div className={styles.function_btn_container}>
<Button onClick={onCancle}>cancel</Button>
<Button type="primary" className={styles.create_btn} onClick={onCreate}>create</Button>
</div>
</div>
</div>
) : (
<div
className={styles.task_add_before}
onClick={()= >{ setTask({ ... task, clickStatu: true }); }} ><div className={styles.task_add_before_icon_container}>
<PlusOutlined className={styles.task_add_before_icon} />
</div>
<div className={styles.task_add_before_name}>Add tasks</div>
</div>
)}
</div>
);
}
Copy the code
.task_add {
box-shadow: 0 0 1px 1px #dddadaad;
transition: all .4s cubic-bezier(.215.610.355.1);
background: white;
margin-bottom: 8px;
border-radius: 5px;
margin: 3px 20px 10px 10px;
&_before {
height: 50px;
width: 100%;
display: flex;
&_icon_container {
width: 30px;
line-height: 50px;
padding-left: 10px;
.task_add_before_icon {
font-size: 20px;
color: #3372fe;
cursor: pointer;
:hover {
font-size: 22px;
color: #2565ee; }}}&_name {
color: #ada7a7;
line-height: 50px;
padding-left: 10px; }}&_after {
width: 100%;
padding: 10px;
.disabled {
pointer-events: none;
}
.btn_container {
display: flex;
padding: 8px 0;
.time_btn_container {
display: flex;
flex: 3;
cursor: pointer;
.time_btn {
margin-top: 4px;
padding: 8px;
font-size: 12px;
background-color: #f5f1f1;
border-radius: 5px;
&:hover {
background-color: #cfcbcb ;
}
.icon {
font-size: 15px;
margin-right: 3px; }}.time_btn:nth-child(n+2) {
margin-left: 5px; }}.function_btn_container {
flex: 2;
text-align: right;
line-height: 38px;
.create_btn {
margin-left: 10px;
}
}
}
}
}
Copy the code
Input box
When you switch to add content by clicking Add, you will default to the 📌 input box.
Antdesgin’s Input component does just that.
// Import the Input component
import { Input, Button, Tag, DatePicker, Popover } from 'antd';
// useRef can also be introduced in {} and then we don't need the react. useRef directly useRef
import React, { useState, useEffect } from 'react';
// useRef
const inputRef = React.useRef<any>(null);
// Input gets the focus configuration parameter
const sharedProps = {
style: { width: '100%' },
ref: inputRef,
};
// Because this input box does not exist when you click Add task switch state. Direct use of
// inputRef.current! .focus({cursor: 'start'}) returns an error. So we pass in useEffect
// Monitor task.clickStatu changes and assign to true. Cursor: 'start' places the focus on the input box
// Start position, and 'all','end'
useEffect(() = > {
// Click on the true state to get Input into focustask.clickStatu ? inputRef.current! .focus({cursor: 'start' }) : ' ';
}, [task.clickStatu]);
<div className={styles.task_add}>{// Data defined above task.clickStatu? (<div className={styles.task_add_after}>// inputRef is obtained in sharedProps<Input {. sharedProps} placeholder='Enter task content' />
</div>)
: (
<div
className={styles.task_add_before}
onClick={()= >{ setTask({ ... task, clickStatu: true }); }} ><div className={styles.task_add_before_icon_container}>
<PlusOutlined className={styles.task_add_before_icon} />
</div>
<div className={styles.task_add_before_name}>Add tasks</div>
</div>
)
Copy the code
.task_add {
box-shadow: 0 0 1px 1px #dddadaad;
transition: all .4s cubic-bezier(.215.610.355.1);
background: white;
margin-bottom: 8px;
border-radius: 5px;
margin: 3px 20px 10px 10px;
&_before{... }// & stands for task_add
&_after{
width: 100%;
padding: 10px; }}Copy the code
Use of ICONS
We used Alibaba’s iconfont icon, which you can see in my previous article✈ ️
Because the ICONS we use are custom ICONS, they are best encapsulated as a component. I created a new public folder under SRC to hold the Icon component
Create a new index. TSX under Icon
import { createFromIconfontCN } from '@ant-design/icons';
const IconFont = createFromIconfontCN({
scriptUrl: [
// This address needs to be changed every time the icon is updated
'//at.alicdn.com/t/font_2503482_lgnt38a7d1f.js']});export default IconFont
Copy the code
It is then referenced in our AddTask component
import IconFont from '@/public/Icon';
// type corresponds to the content of the iconfont official website copy code
<IconFont type="iconjintian" className={styles.icon} />
Copy the code
At the bottom of the layout
A CALSS is definedtime_btn_container
To store everything at the bottom. The child elements aretime_btn_container
和 function_btn_container
.time_btn_container
I’m also going to be a div, class nametime_btn
&_after {
width: 100%;
padding: 10px;
.btn_container {
display: flex;
padding: 8px 0;
.time_btn_container {
display: flex;
flex: 3;
cursor: pointer;
.time_btn {
margin-top: 4px;
padding: 8px;
font-size: 12px;
background-color: #f5f1f1;
border-radius: 5px;
&:hover {
background-color: #cfcbcb ;
}
.icon {
font-size: 15px;
margin-right: 3px;
}
}
.time_btn:nth-child(n+2) {
margin-left: 5px;
}
}
.function_btn_container {
flex: 2; text-align: right; line-height: 38px; .create_btn { margin-left: 10px; }}}}Copy the code
Click today to switch to Tag
The default time after clicking today is 18:00 and replace these buttons with CloseTag
Toggle today, tomorrow, custom buttons and tags. Control by task.showTime value
-
Task. showTime is true to display the Tag.
-
Task. showTime is false to display today, tomorrow, custom buttons.
writing
{task.showTime && (<div>Tag</div> ) }
{!task.showTime && (<div>Today tomorrow button</div>)}Copy the code
This is today’s button. The onClick event sets task.showtime to true. Also fires the chooseDefaultTime(‘today’) function.
<div
className={styles.time_btn}
onClick={() = >{ setTask({ ... task,showTime: true });
chooseDefaultTime('today'); }} ><IconFont type="iconjintian" className={styles.icon} />Today < / div >Copy the code
ChooseDefaultTime function
Here we use a new variable defaultTime, which is the moment object used by the time picker DatePicker. Tag is the time format of the tag. By the way, the time picker is used for moment and we also need to import moment
// The time used by the time selector and tag
const [defaultTime, setDefaultTime] = useState<any>({
time: ' '.tag: ' '});// Select today and tomorrow
const chooseDefaultTime = (day: string) = > {
// Click today
if (day == 'today') {
// The default is 18:00
const time = moment(moment().format('YYYY-MM-DD 18:00'));
// Default 18:00 today shows today, tomorrow, yesterday and other days of the week
const tag = `${moment().format('M month DD date ')}18:00 ` (today);
setDefaultTime({ time, tag });
// Click the tomorrow button
} 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 });
}
setDefinedDatePick(false)};Copy the code
closeTag
// Closable turns the tag color onClose closes the function
<Tag closable onClose={closeTag} color="gold" style={{ padding: '5px' }}>
{defaultTime.tag}
</Tag>
Copy the code
Click Tag to bring up the time picker
The Popover component is used here. Click on the Tag to display the Popover, just write the Tag inside the Popover.
Here again, the time picker is in English, not Chinese. You need to import this and add locale={locale} to DatePicker
import 'moment/locale/zh-cn';
// Time selector bottom English --> Chinese
import locale from 'antd/lib/date-picker/locale/zh_CN';
Copy the code
<Popover
// The shell position
placement="bottomLeft"
// The title is empty
title={' '}
// The shell content here is the time selector
content={(
<DatePicker
showTime
defaultValue={defaultTime.time}
locale={locale}
autoFocus
onChange={e= >{ changeDate(e); }} / >
)}
// Trigger mode
trigger="click"
>
<Tag closable onClose={closeTag} color="gold" style={{ padding: '5px' }}>
{defaultTime.tag}
</Tag>
</Popover>
Copy the code
Change the time picker to re-render the Tag
That’s changeDate(e) in the time selector; function
- We want today, tomorrow, yesterday and the day of the week
- The comparison time frame is judged to be today…. Moment object
- For comparison, several time periods are needed: 00:00 today, 24:00 today, 00:00 yesterday, and 24:00 tomorrow.
- Subtract is a way for moment to gain the first few days
- Add is a way for moment to get the next few days
// Modify the date in the time picker
const changeDate = date= > {
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'));
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`)}); };Copy the code
Custom time
We write another time picker to the right of it and control whether it is displayed by the variable definedDatePickShow. At the same time when the custom time selector appears today, tomorrow button can not be clicked
<div className={styles.time_btn}
onClick={() = > {
setDefinedDatePick(true); }} ><IconFont
type="icona-rili3"
className={styles.icon}
/>Custom < / div >Copy the code
{definedDatePickShow ? (
<div style={{height:'30px',lineHeight:'40px',marginLeft:'30px'}} >
<DatePicker
showTime
defaultValue={defaultTime.time}
locale={locale}
autoFocus
style={{height:'30px',lineHeight:'40px'}}
onChange={e= >{ changeDate(e); }} / ><span style={{marginLeft:'3px',color:'#1890ff'}} > <CloseCircleOutlined onClick={()= >{
setDefinedDatePick(false)
}} /></span>
</div>
) : (
<span />
)}
Copy the code