說明:
版本:V2.0
此文章代碼復制不可用,有需要可以留言,或者聯系我。
功能介紹:
1.可以設置 可選擇的時間范圍,范圍超出部分置灰不可選擇。
2.點擊空白處默認收起彈窗,也可以在外部通過 open 屬性控制。
3.按確定按鈕后過 onOk 屬性返回 一個函數,第一個參數為選擇的時間。
4.*新增:用戶可以選擇是否使用確定按鈕。
5.*新增: disabled (禁用狀態)、className (設置選擇器)、defaultValue(時間為空時的默認顯示) 。
6.寬高自動獲取父級,最小高度22px,最下寬度90px。
改進方向:
此版本基本滿足開發時的各種需要,及突發情況。目前暫無改進計划。
觀眾老爺們若有什么好的建議,我也會采納,主要是得有時間。😊
效果展示:


更多版本:
ts 版 (網友 Ever-Lose 改進提供的)
js(部分代碼):
import React from "react"; import "./QuarterlyPicker.less" import moment from "moment"; import { connect } from "react-redux"; import PropTypes from "prop-types"; const quarterData = ["第一季度", "第二季度", "第三季度", "第四季度"]; class QuarterlyPicker extends React.Component { constructor(props) { super(props) this.state = { stateOpen: false, // 是否展示彈窗 year: "", // "2020" selectTime: `${moment().format("YYYY")}-${moment().quarter()}`, // 選中的時間, "2020-1", "-1" 代表第一季度 selectionTime: "", // 點確定后需要返回的時間 oneDisplay: "block", twoDisplay: "block" } } componentDidMount() { const { value, open } = this.props; let { year, selectTime } = this.state; year = value ? value.split("-")[0] : selectTime.split("-")[0] this.setState({ selectTime: value ? value : selectTime, selectionTime: value ? value : "", year }) this.idBlock(year) if (open === undefined) { document.addEventListener("click", this.eventFn, true) } } componentWillUnmount() { document.removeEventListener("click", this.eventFn, true) } eventFn = (ev) => { // ... } onclick = (ev) => { // ... } ulliclick = (index) => { // ... } iconLeftClick = () => { // ... } iconRightClick = () => { // ... } idBlock = (year) => { // ... } okBut = (ev) => { // ... } textChange = () => { // ... } quarterDataBefore = () => { // ... } render() { const { oneDisplay, twoDisplay, selectTime, year, selectionTime, stateOpen } = this.state; const { className, defaultValue, disabled, showOk, open } = this.props; let openOnOff = false; if (typeof (this.props.open) === "boolean") { openOnOff = open; } else { openOnOff = stateOpen; } return ( <div className={`QuarterlyPicker ${className}`} id="QuarterlyPicker" onClick={disabled ? console.log("禁用") : ev => { this.onclick(ev) }}> <div className="begin"> <input className={selectionTime ? "zjl-input" : "zjl-input default_input"} value={selectionTime ? selectionTime : defaultValue} disabled={disabled} onChange={() => { this.textChange() }} /> <i className="img" ></i> </div> <div className="child" style={{ display: openOnOff ? "block" : "none" }}> <header className="zjl-timehear"> <span>{selectTime}</span> </header> <div className="con"> <ul className="content-one"> <li className="lefticon" onClick={this.iconLeftClick} style={{ display: oneDisplay }}>{"<<"}</li> <li className="righticon" onClick={this.iconRightClick} style={{ display: twoDisplay }}>{">>"}</li> <li>{year}</li> </ul> </div> <div className="TimerXhlleft"> <ul className="quaterleft"> {this.quarterDataBefore()} </ul> </div> { showOk ? <div className="zjl-but"> <span onClick={this.okBut}>確 定</span> </div> : null } </div> </div> ) } } QuarterlyPicker.propTypes = { value: PropTypes.string, startValue: PropTypes.string, endValue: PropTypes.string, open: PropTypes.bool, onOk: PropTypes.func, disabled: PropTypes.bool } QuarterlyPicker.defaultProps = { showOk: false, // 是否使用確定按鈕,默認不使用 disabled: false, // 組件是否禁用,默認組件可以使用 defaultValue: "請選擇時間", // 默認日期 or 沒有日期時的提示語 value: "", startValue: "1970-1", endValue: `${moment().format("YYYY")}-${moment().quarter()}`, open: undefined, onOk: () => { console.log(1) }, className: "" } export default connect(state => state, {})(QuarterlyPicker)
less部份:
.QuarterlyPicker{ width: 100%; height: 100%; min-height: 22px; min-width: 90px; box-sizing: border-box; margin: 0; padding: 0; color: rgba(0, 0, 0, 0.65); font-size: 14px; font-variant: tabular-nums; line-height: 1.5; list-style: none; font-feature-settings: 'tnum'; position: relative; display: inline-block; outline: none; cursor: text; transition: opacity 0.3s; .begin{ position: relative; height: 100%; .zjl-input{ text-overflow: ellipsis; touch-action: manipulation; box-sizing: border-box; margin: 0; padding: 0; font-variant: tabular-nums; list-style: none; font-feature-settings: 'tnum'; position: relative; display: inline-block; width: 100%; height: 100%; padding: 4px 11px; color: rgba(0, 0, 0, 0.65); font-size: 14px; line-height: 1.5; background-color: #fff; background-image: none; border: 1px solid #d9d9d9; border-radius: 4px; transition: all 0.3s; &:hover{ border-color: #40a9ff; border-right-width: 1px !important; } &:focus { border-color: #40a9ff; border-right-width: 1px !important; outline: 0; box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); } } .zjl-input[disabled] { color: rgba(0, 0, 0, 0.25); background-color: #f5f5f5; cursor: not-allowed; opacity: 1; } .default_input{ color: rgba(0, 0, 0, 0.25); } .img{ display: inline-block; position: absolute; top: 50%; right: 12px; height: 14px; width: 14px; margin-top: -7px; background: url("../../assets/imgs/日歷1.png") no-repeat center; background-size: 100% 100%; color: rgba(0, 0, 0, 0.25); font-size: 14px; line-height: 1; z-index: 1; transition: all 0.3s; user-select: none; } } .child{ box-sizing: border-box; margin: 0; padding: 0; color: rgba(0, 0, 0, 0.65); font-variant: tabular-nums; line-height: 1.5; list-style: none; font-feature-settings: 'tnum'; position: absolute; z-index: 1050; width: 280px; font-size: 14px; line-height: 1.5; text-align: left; list-style: none; background-color: #fff; background-clip: padding-box; border: 1px solid #fff; border-radius: 4px; outline: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); .zjl-but { position: relative; height: auto; text-align: right; padding: 0 12px; line-height: 38px; border-top: 1px solid #e8e8e8; span{ position: relative; display: inline-block; font-weight: 400; white-space: nowrap; text-align: center; background-image: none; border: 1px solid transparent; box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); cursor: pointer; transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); user-select: none; touch-action: manipulation; height: 32px; padding: 0 15px; color: #fff; background-color: #1890ff; border-color: #1890ff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); -webkit-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); height: 24px; padding: 0 7px; font-size: 14px; border-radius: 4px; line-height: 22px; &:hover{ color: #fff; background-color: #40a9ff; border-color: #40a9ff; } } } .zjl-timehear{ height: 34px; padding: 6px 10px; border-bottom: 1px solid #e8e8e8; span{ display: inline-block; width: 100%; margin: 0; cursor: default; } } .TimerXhlleft{ width: 100%; padding: 20px; .quaterleft{ display: flex; width: 100%; flex-direction: row; flex-wrap: wrap; justify-content: space-between; .quaterleftli{ width: 43%; margin-right: 0 !important; text-align: center; line-height: 50px; height: 50px; color: #333; .normalcolor{ display: inline-block; line-height: 30px; height: 30px; padding: 0 20px; cursor: pointer; &:hover{ background: #e6f7ff; cursor: pointer; } &.nonormaocolor{ background: #bae7ff; border-radius: 1px; // color: #fff; } &.warnnodata{ background: #F5f5f5; color: rgba(0, 0, 0, 0.25); cursor: not-allowed; } } } } } .con{ height: 40px; line-height: 40px; text-align: center; border-bottom: 1px solid #e8e8e8; user-select: none; .content-one{ white-space: nowrap; overflow: hidden; position: relative; .lefticon{ position: absolute; z-index: 100; top: 0; left: 0; font-size: 18px; cursor: pointer; width: 30px; margin-left: 20px; &:hover{ color: #40a9ff; } } .righticon{ position: absolute; z-index: 100; top: 0; right: 0; font-size: 18px; cursor: pointer; width: 30px; margin-right: 20px; &:hover{ color: #40a9ff; } } li { display: inline-block; text-align: center; cursor: default; } } } } }
