最近用react开发了个日期范围选择的自定义组件,效果图如下
页面滚动的时候就变成这样了
如何将自定义组件中的部分元素增加到body中?
我写的代码如下,请大神多多指教,最好附上同样功能的源码,谢谢!
import React, { useState, useEffect } from 'react'
import { Card, DatePicker, Input, message } from 'antd'
import { CalendarOutlined } from '@ant-design/icons'
import './index.less';
const { RangePicker } = DatePicker
export default function CustomDatePicker(props) {
let tabIndex = 1;
if (typeof props.tab !== 'undefined') {
tabIndex = Number(props.tab)
}
const tabsList = [
{
desc: '昨天',
val: 1,
type: 'day',
},
{
desc: '今天',
val: 0,
type: 'day',
},
{
desc: '近7天',
val: 7,
type: 'near',
},
{
desc: '近30天',
val: 30,
type: 'near',
},
]
const cycleList = [
{
desc: '自然日',
type: 'day',
},
{
desc: '自然周',
type: 'week',
},
{
desc: '自然月',
type: 'month',
},
{
desc: '自然年',
type: 'year',
},
{
desc: '自定义',
type: 'custom',
},
]
const dateFormatStr = 'yyyy-MM-dd'
const [tabCurrent, setTabCurrent] = useState(tabIndex)
const [cycle, setCycle] = useState('day')
const [cycleCurrent, setCycleCurrent] = useState(0)
const [startDate, setStartDate] = useState()
const [endDate, setEndDate] = useState()
const [inputVal, setInputVal] = useState(dateFormat(new Date(), dateFormatStr))
const [isShowSelect, setIsShowSelect] = useState(false)
// 格式化时间
function dateFormat(date, format) {
if (!format) {
format = dateFormatStr
}
date = new Date(date)
var map = {
M: date.getMonth() + 1, //月份
d: date.getDate(), //日
h: date.getHours(), //小时
m: date.getMinutes(), //分
s: date.getSeconds(), //秒
q: Math.floor((date.getMonth() + 3) / 3), //季度
S: date.getMilliseconds(),
//毫秒
}
format = format.replace(/([yMdhmsqS])+/g, function (all, t) {
var v = map[t]
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v
v = v.substr(v.length - 2)
}
return v
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length)
}
return all
})
return format
}
useEffect(() => {
if (tabCurrent > -1) {
setDate(tabsList[tabCurrent])
}
}, [tabCurrent])
const emitDate = (data) => {
const { type, start, end } = data
if (type === 'day') {
setInputVal(start)
} else {
setInputVal(start + '/' + end)
}
setStartDate(start)
setEndDate(end)
setIsShowSelect(false)
typeof props.onChange === 'function' && props.onChange(data)
}
const setDate = (data) => {
const { val, type } = data
const now = new Date().getTime()
const day = 24 * 3600 * 1000
setCycle(type)
if (type === 'day') {
const date = dateFormat(now - val * day, dateFormatStr)
setCycleCurrent(0)
emitDate({
type: 'day',
start: date,
end: date,
})
} else {
setCycleCurrent(4)
emitDate({
type: 'custom',
start: dateFormat(now - (val + 1) * day, dateFormatStr),
end: dateFormat(now - day, dateFormatStr),
})
}
}
const showDateSelect = () => {
setIsShowSelect(!isShowSelect)
}
const clickTab = (index) => {
if (tabCurrent !== index) {
setTabCurrent(index)
}
}
const TabsNode = () => {
const list = tabsList.map((item, index) => {
return (
<span className={tabCurrent === index ? 'tab active' : 'tab'} key={index} onClick={() => clickTab(index)}>
{item.desc}
</span>
)
})
return (
<div className="flex tabs">
{list}
<Input className="dateVal" readOnly suffix={<CalendarOutlined />} defaultValue={inputVal} onClick={() => showDateSelect()}></Input>
</div>
)
}
const changePicker = () => {
const item = cycleList[cycleCurrent]
const { type } = item
if (type === 'custom') {
} else {
}
}
const CyClePicker = () => {
const clickCyCle = (index) => {
setCycleCurrent(index)
changePicker()
}
const CycleView = () => {
const list = cycleList.map((item, index) => {
return (
<div key={index} className={cycleCurrent === index ? 'tab active' : 'tab'} onClick={() => clickCyCle(index)}>
{item.desc}
</div>
)
})
return <div className="dateAreaTabs tabs">{list}</div>
}
const changeDate = (date, dateStr) => {
const item = cycleList[cycleCurrent]
let { type } = item
setTabCurrent(-1)
let start, end
switch (type) {
case 'day':
start = dateStr
end = dateStr
break
case 'week':
start = dateFormat(date.startOf('week').valueOf())
end = dateFormat(date.endOf('week').valueOf())
break
case 'month':
start = dateFormat(date.startOf('month').valueOf())
end = dateFormat(date.endOf('month').valueOf())
break
case 'year':
start = dateFormat(date.startOf('year').valueOf())
end = dateFormat(date.endOf('year').valueOf())
break
default:
start = dateStr[0]
end = dateStr[1]
if ((new Date(end).getTime() - new Date(start).getTime()) / 1000 / 3600 / 24 > 90) {
message.warning('最多选择90天')
return
}
if (start === end) {
type = 'day'
}
}
emitDate({
type,
start,
end,
})
}
const disabledDate = (current) => {
const item = cycleList[cycleCurrent]
const { type } = item
switch (type) {
case 'day':
return current && current.valueOf() > new Date().getTime()
case 'week':
const now = new Date()
const day = now.getDay()
return current && current.valueOf() > new Date().getTime() - day * 24 * 3600 * 1000
case 'month':
return current && current.endOf('month').valueOf() > new Date().getTime()
case 'year':
return current && current.endOf('year').valueOf() > new Date().getTime()
default:
return current && current.valueOf() > new Date().getTime() - 24 * 3600 * 1000
}
}
const PickerView = () => {
const item = cycleList[cycleCurrent]
const { type } = item
if (type === 'custom') {
return (
<div className="picker" style={{ width: '550px' }}>
<RangePicker open style={{ opacity: 0 }} onChange={changeDate} disabledDate={disabledDate}></RangePicker>
</div>
)
} else {
return (
<div className="picker">
<DatePicker open style={{ opacity: 0 }} picker={type} onChange={changeDate} disabledDate={disabledDate}></DatePicker>
</div>
)
}
}
if (isShowSelect) {
return (
<div
className="dateArea flex"
onClick={(e) => {
e.stopPropagation()
}}
>
<CycleView />
<PickerView />
</div>
)
} else {
return <></>
}
}
return (
<Card className="customDate">
<TabsNode />
<CyClePicker />
</Card>
)
}
index.less
.customDate {
background-color: #fcfcfc;
position: relative;
width: 720px;
.flex {
display: flex;
}
.tabs {
align-items: center;
.tab {
width: 80px;
height: 30px;
line-height: 30px;
text-align: center;
border: 1px solid #e8eaec;
border-radius: 15px;
margin-right: 12px;
box-sizing: border-box;
cursor: pointer;
&.active {
color: #fff;
background: #027aff;
border: 1px solid transparent;
}
}
.dateVal {
width: 280px;
}
}
.dateArea {
height: 320px;
overflow-y: hidden;
position: absolute;
top: 80px;
right: 30px;
z-index: 1;
background: #fff;
padding: 20px;
&Tabs {
text-align: center;
margin-right: 20px;
.tab {
margin: 12px 0;
}
}
.picker {
width: 280px;
position: relative;
top: -30px;
}
}
}
通过React的createPortal
方法 就能实现了
React Antd 的机制是什么鬼?输入框怎么没值? 为什么输入以后 再打印 navCreateName 是空?晕了什么情况
本文向大家介绍javascript实现无法关闭的弹框,包括了javascript实现无法关闭的弹框的使用技巧和注意事项,需要的朋友参考一下 大家都见过某网页中的恶意广告,你关闭了又出来了!为何,JS来告诉你 HTML CSS JS 以上就是本文的全部内容,希望对大家有所帮助,同时也希望多多支持呐喊教程!
像这种卡券的缺口请问如何实现,如果背景是纯色直接定位个纯色上去也就没啥问题,但这种背景渐变的显然不行,请巨佬贴个demo给我学习一下谢谢
本文向大家介绍基于JavaScript实现弹出框效果,包括了基于JavaScript实现弹出框效果的使用技巧和注意事项,需要的朋友参考一下 弹出框在网站页面中是必不可少的一部分,今天借助呐喊教程平台给大家分享使用js实现简单的弹出框效果,本文写不好,还请见谅! 首先我们来分析弹出框的部件.简单弹出框分为头,内容,尾部. 头部中有标题和关闭按钮,内容就可以图文,媒体,iframe,flash等等
本文向大家介绍怎么实现移动端的边框0.5px?相关面试题,主要包含被问及怎么实现移动端的边框0.5px?时的应答技巧和注意事项,需要的朋友参考一下 一种是通过transform中的scale 一种是通过meta viewport中设置init-scale为0.5 一种是设置hr 一种是基于背景渐变实现
本文向大家介绍React+Antd+Redux实现待办事件的方法,包括了React+Antd+Redux实现待办事件的方法的使用技巧和注意事项,需要的朋友参考一下 之前也是写过一篇关于Redux的文章,来简单理解一下Redux,以及该如何使用。今天我就来分享一个也是入门级别的,React+Redux+antd来实现简单的待办事件。同时也讲讲自己对Redux的理解。先来看一张图吧: 我们简单的比喻来