react 实战:写一个年份选择器
上代码。
组件的Js文件。
import React, { Component } from "react";
import Style from './myYearSelect.less' function getOffsetTop(el){
return el.offsetParent
? el.offsetTop + getOffsetTop(el.offsetParent)
: el.offsetTop
}
function getOffsetLeft(el){
return el.offsetParent
? el.offsetLeft + getOffsetLeft(el.offsetParent)
: el.offsetLeft
} class YearPicker extends Component {
constructor(props) {
super(props);
this.state = {
isShow: false,
selectedyear:"",
boxPos:{},
years: []
};
} componentWillMount() {
let { defaultValue } = this.props;
if (defaultValue) {
this.setState({ selectedyear: defaultValue });
}
}
componentDidMount() {
let _this = this;
document.addEventListener(
"click",
_this.clickFunc,
false
);
}
componentWillUnmount(){
let _this = this
document.removeEventListener(
"click",
_this.clickFunc,
false
);
}
clickFunc = e => {
const { isShow } = this.state;
let clsName = e.target.className;
// console.log(e.target.dataset)
if (!e.target.dataset || !e.target.dataset.tag || e.target.dataset.tag !== "year") {
this.onBlurFunc()
}
}
onFocusFunc = e => {
const { selectedyear } = this.state;
const operand = 12;
const d = document.documentElement || document.body || null
let top, left this.initData(operand, selectedyear); if (d) {
top = d.scrollTop
left = d.scrollLeft
}
this.setState({
isShow: true,
boxPos:{
x: getOffsetTop(e.currentTarget) - (top ? top : 0),
y: getOffsetLeft(e.currentTarget) - (left ? left : 0),
}
})
}
onBlurFunc = e => {
this.setState({
isShow: false
})
}
// 向前的年份
prev = () => {
const { years } = this.state;
if (years[0] <= 1970) {
return;
}
this.getNewYearRangestartAndEnd("prev");
};
// 向后的年份
next = () => {
this.getNewYearRangestartAndEnd("next");
};
getNewYearRangestartAndEnd = type => {
const { selectedyear, years } = this.state;
let operand = Number(this.props.operand);
operand = operand ? operand : 12;
let start = Number(years[0]);
let end = Number(years[years.length - 1]);
let newstart;
let newend;
if (type == "prev") {
newstart = parseInt(start - operand);
newend = parseInt(end - operand);
this.getYearsArr(newstart, newend);
}
if (type == "next") {
newstart = parseInt(start + operand);
newend = parseInt(end + operand);
this.getYearsArr(newstart, newend);
}
}
initData = (operand, defaultValue) => {
operand = operand ? operand : 12; let year = defaultValue - 1970;
let curr = year % operand;
let start = defaultValue - curr;
let end = parseInt(defaultValue) + parseInt(operand) - 1 - curr;
this.getYearsArr(start, end);
};
getYearsArr = (start, end) => {
let arr = [];
for (let i = start; i <= end; i++) {
arr.push(Number(i));
}
this.setState({
years: arr
});
};
// 选中某一年
selects = e => {
let val = Number(e.target.value);
this.setState({ selectedyear: val });
if (this.props.callback) {
this.props.callback(val);
}
}; render() {
const { width } = this.props
const { isShow, boxPos, selectedyear, years } = this.state;
const w = width ? width : 200 return (
<div className={Style.main} data-tag="year">
<input className={Style.mainInput}
data-tag="year"
value={selectedyear}
readOnly
onFocus={this.onFocusFunc}
/>
{ isShow && boxPos.x ? <div data-tag="year" tabIndex="0" className={Style.box}
style={{ top:boxPos.x, left: boxPos.y, width:w }}>
<List
data={years}
value={selectedyear}
prev={this.prev}
next={this.next}
cback={this.selects}
/>
</div> : '' }
</div>
);
}
} const List = props => {
const { data, value, prev, next, cback } = props;
return (
<div className={Style.list} tabIndex="-1" data-tag="year">
<div className={Style.header} data-tag="year">
<a
type="double-left"
role="button"
className={Style.prevBtn}
onClick={prev}
data-tag="year"
></a>
<span data-tag="year">{value}</span>
<a
type="double-left"
role="button"
className={Style.nextBtn}
onClick={next}
data-tag="year"
></a>
</div>
<div className={Style.body} data-tag="year">
<ul className={Style.yearUl} data-tag="year">
{data.map((item, index) => (
<li
key={index}
title={item}
data-tag="year"
className={
item == value
? Style.calendarYearSelected
: ""
}
>
<button onClick={cback} value={item}>
{item}
</button>
</li>
))}
</ul>
</div>
</div>
);
}; export default YearPicker;
组件的 Less 文件。
.main{
width: 100%;
}
.mainInput{
box-sizing: border-box;
margin:;
padding:;
font-variant: tabular-nums;
list-style: none;
font-feature-settings: 'tnum';
position: relative;
display: inline-block;
width: 100%;
height: 32px;
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;
}
.box{
// width: 100%;
height: 260px;
max-width: 400px;
// max-height: 400px;
background-color: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
position: fixed;
}
.list{
width: 100%;
height: 100%;
}
.header{
position: relative;
height: 34px;
line-height: 34px;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border-bottom: 1px solid #e9e9e9;
background-color: #fff;
color:#000;
}
.prevBtn, .nextBtn{
position: absolute;
top:;
color: #000;
font-family: Arial, "Hiragino Sans GB", "Microsoft Yahei", "Microsoft Sans Serif", sans-serif;
padding: 0 5px;
font-size: 16px;
display: inline-block;
line-height: 34px;
height: 100%;
&:hover{
&::before, &::after{
border-color: rgba(0, 0, 0, 0.65);
}
}
&::before, &::after{
position: relative;
top: -1px;
display: inline-block;
width: 8px;
height: 8px;
vertical-align: middle;
border: 0 solid #aaa;
border-width: 1.5px 0 0 1.5px;
border-radius: 1px;
transform: rotate(-45deg) scale(0.8);
transition: all 0.3s;
content: '';
}
&::after{
left:-3px
}
}
.nextBtn{
&::before,&::after{
transform: rotate(135deg) scale(0.8);
}
}
.prevBtn{
left:7%;
}
.nextBtn{
right:7%;
}
.body{
height: calc(100% - 34px);
background-color: #fff;
}
.yearUl{
padding:;
margin:;
overflow: hidden;
list-style: none;
li{
float: left;
width: 33.33%;
max-width: 76px;
text-align: center;
cursor: pointer;
button{
cursor: pointer;
outline: none;
border:;
display: inline-block;
margin: 0 auto;
color: rgba(0, 0, 0, 0.65);
background: transparent;
text-align: center;
height: 24px;
line-height: 24px;
padding: 0 6px;
border-radius: 4px;
transition: background 0.3s ease;
margin: 14px 0;
}
}
}
li.calendarYearSelected{
button{
background-color: #108ee9;
color: #fff;
}
}
使用组件的页面 jsx 文件。
import React from 'react'
import moment from 'moment' import YearPicker from './yearPicker/myYearSelect' class yaerSelectPageNew extends React.Component {
constructor(props){
super(props)
this.state = {
mockData:{
year:2020
},
YPWidth:231
}
} filterByYear = (e) => {
const { mockData } = this.state
this.setState({mockData: {
...mockData,
year: e.toString()
}});
} render(){
const { YPWidth, mockData } = this.state return (
<div> <h1>Page </h1>
<div style={{ width: '200px' }}>
<YearPicker
defaultValue={moment().format('YYYY')}
callback={this.filterByYear}
width={YPWidth}
/>
</div>
</div>
);
}
} export default yaerSelectPageNew
react 实战:写一个年份选择器的更多相关文章
- 放弃antd table,基于React手写一个虚拟滚动的表格
缘起 标题有点夸张,并不是完全放弃antd-table,毕竟在react的生态圈里,对国人来说,比较好用的PC端组件库,也就antd了.即便经历了2018年圣诞彩蛋事件,antd的使用者也不仅不减,反 ...
- 仿照jQuery写一个关于选择器的框架(带了注释,请多多指教~)
var select = (function () { //这是一个异常与捕获的代码,它表示的意思是:如果push方法出现了错误那么就需要重写push方法 try { //这边是自己模拟一个场景,来使 ...
- 在React中写一个Animation组件,为组件进入和离开加上动画/过度
问题 在单页面应用中,我们经常需要给路由的切换或者元素的挂载和卸载加上过渡效果,为这么一个小功能引入第三方框架,实在有点小纠结.不如自己封装. 思路 原理 以进入时opacity: 0 --> ...
- 用react+redux写一个todo
概述 最近学习redux,打算用redux写了一个todo.记录下来,供以后开发时参考,相信对其他人也有用. 代码 代码请见我的github 组织架构如下图:
- 使用React.js写一个类似单选框与复选框的功能
单选框 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <tit ...
- [AST实战]从零开始写一个wepy转VUE的工具
为什么需要 wepy 转 VUE "转转二手"是我司用 wepy 开发的功能与 APP 相似度非常高的小程序,实现了大量的功能性页面,而新业务 H5 项目在开发过程中有时也经常需要 ...
- 深入浅出React Native 3: 从零开始写一个Hello World
这是深入浅出React Native的第三篇文章. 1. 环境配置 2. 我的第一个应用 将index.ios.js中的代码全部删掉,为什么要删掉呢?因为我们准备从零开始写一个应用~学习技术最好的方式 ...
- [闲的蛋疼系列]从零开始用TypeScript写React的UI组件(0)-先写一个Button??
0.咸鱼要说的 一入前端深似海,咸鱼入海更加咸. 最近闲的蛋疼,手上年前的事也完成了7788了,借助[PG1]的话来说,我们要keep real. 咸鱼肯定不real 了,因为我们都活在梦里,所以咱们 ...
- Python+Flask+Gunicorn 项目实战(一) 从零开始,写一个Markdown解析器 —— 初体验
(一)前言 在开始学习之前,你需要确保你对Python, JavaScript, HTML, Markdown语法有非常基础的了解.项目的源码你可以在 https://github.com/zhu-y ...
随机推荐
- awk 命令使用入门
Linux 下处理和分析文本文件内容,AWK 命令是一个强有力的工具.特别是文件内容是以行和列的形式排版的时候,AWK 就是命令行界的 Excel 啊! 简单的 awk 命令可以直接在命令行中使用,复 ...
- EJB JMS javax.naming.NameNotFoundException: XXX not bound
练习EJB MessageDrivenBean时部署不成功,一直报错 09:57:29,017 WARN [JmsActivation] Failure in jms activation org.j ...
- 深入理解React:事件机制原理
目录 序言 DOM事件流 事件捕获阶段.处于目标阶段.事件冒泡阶段 addEventListener 方法 React 事件概述 事件注册 document 上注册 回调函数存储 事件分发 小结 参考 ...
- 使用json-server与Mockjs搭建模拟服务
为什么使用 在项目开发中,常常需要边写前端页面边写后端接口,但是后端接口服务往往是滞后于前端开发的,或者是不能及时提供的.出于前端开发的迅速和便捷去考虑,我们可以根据后端接口数据结构去模拟(mock) ...
- Python3-queue模块-同步队列
Python3中的queue模块实现多生产者,多消费者队列,特别适用于多个线程间的信息的安全交换,主要有三个类 queue.Queue(maxsize=0) 构造一个FIFO(先进先出)的队列 que ...
- GraphicsLab Project 之 Screen Space Planar Reflection
作者:i_dovelemon 日期:2020-06-23 主题:Screen Space Planar Reflection, Compute Shader 引言 前段时间,同事发来一篇讲述特化版本的 ...
- js事件入门(4)
4.表单事件 表单事件处理主要用来验证表单,可以处理用户在表单上所做的任何操作. 4.1.onsubmit事件 当用户点击submit按钮来提交表单时,就会触发onsubmit事件,如果事件处理程序返 ...
- 去除List集合中的重复值(四种好用的方法)(基本数据类型可用)
最近项目中需要对list集合中的重复值进行处理,大部分是采用两种方法,一种是用遍历list集合判断后赋给另一个list集合,一种是用赋给set集合再返回给list集合. 但是赋给set集合后,由于se ...
- 断路器Hystrix(Feign)
上一篇中我们讲了 断路器Hystrix(Ribbon) 本章讲解Feign+Hystrix已经Request请求传递,各种奇淫技巧…. - Hystrix Hystrix支持回退概念:当 断路器 打开 ...
- Cache写策略(Cache一致性问题与骚操作)
写命中 写直达(Write Through) 信息会被同时写到cache的块和主存中.这样做虽然比较慢,但缺少代价小,不需要把整个块都写回主存.也不会发生一致性问题. 对于写直达,多出来%10向主存写 ...