组件:
< ! --
* @Author: liuyu liuyu@xizhengtech. com
* @Date: 2023 - 02 - 01 16 : 57 : 27
* @LastEditors: wangping wangping@xizhengtech. com
* @LastEditTime: 2023 - 06 - 30 17 : 25 : 14
* @Description: 时间选择年 - 年
-- >
< template>
< div class = "yearPicker" ref= "yearPicker" : width= "width" >
< input class = "_inner" ref= "inputLeft" v- model= "startShowYear" @focus= "onFocus" @blur= "onBlur" type= "text" name= "yearInput" @keyup= "checkStartInput($event)" placeholder= "开始年份" / >
< span> { { sp } } < / span>
< input class = "_inner" ref= "inputRight" v- model= "endShowYear" @focus= "onFocus" @blur= "onBlur" type= "text" name= "yearInput" @keyup= "checkEndInput($event)" placeholder= "结束年份" / >
< ! -- < i class = "dateIcon el-icon-date" > < / i> 按照自己标准库里面的图标设置-- >
< ! -- < span class = "_inner labelText" > < / span> -- >
< i class = "_inner labelText el-icon-date" > < / i>
< div class = "_inner floatPanel" v- if = "showPanel" >
< div class = "_inner leftPanel" >
< div class = "_inner panelHead" >
< i class = "_inner el-icon-d-arrow-left" @click= "onClickLeft" > < / i>
{ { leftYearList[ 0 ] + " - " + leftYearList[ 9 ] } }
< / div>
< div class = "_inner panelContent" >
< div : class = "{
oneSelected : item === startYear && oneSelected,
startSelected : item === startYear,
endSelected : item === endYear,
betweenSelected : item > startYear && item < endYear,
} " v-for=" item in leftYearList" :key=" item">
< a : class = "{
cell : true ,
_inner : true ,
selected : item === startYear || item === endYear,
} " @click=" onClickItem ( item) " @mouseover=" onHoverItem ( item) ">
{ { item } }
< / a>
< / div>
< / div>
< / div>
< div class = "line" > < / div>
< div class = "_inner rightPanel" >
< div class = "_inner panelHead" >
< i class = "_inner el-icon-d-arrow-right" @click= "onClickRight" > < / i>
{ { rightYearList[ 0 ] + " - " + rightYearList[ 9 ] } }
< / div>
< div class = "_inner panelContent" >
< div : class = "{
startSelected : item === startYear,
endSelected : item === endYear,
betweenSelected : item > startYear && item < endYear,
} " v-for=" item in rightYearList" :key=" item">
< a : class = "{
cell : true ,
_inner : true ,
selected : item === endYear || item === startYear,
} " @click=" onClickItem ( item) " @mouseover=" onHoverItem ( item) ">
{ { item } }
< / a>
< / div>
< / div>
< / div>
< / div>
< / div>
< / template>
< script>
import moment from "moment" ;
const SELECT_STATE = {
unselect : 0 ,
selecting : 1 ,
selected : 2 ,
} ;
export default {
name : "yearPicker" ,
computed : {
oneSelected ( ) {
return (
this . curState === SELECT_STATE . selecting &&
( this . startYear === this . endYear || this . endYear == null )
) ;
} ,
startDate ( ) {
return this . startYear;
} ,
leftYearList ( ) {
return this . yearList. slice ( 0 , 10 ) ;
} ,
rightYearList ( ) {
return this . yearList. slice ( 10 , 20 ) ;
} ,
startYearFormat ( ) {
if ( this . _. isNil ( this . startYear) ) {
return null ;
}
return moment ( this . startYear) . startOf ( "year" ) . format ( "yyyy" ) ;
} ,
endYearFormat ( ) {
if ( this . _. isNil ( this . endYear) ) {
return null ;
}
return moment ( this . endYear) . endOf ( "year" ) . format ( "yyyy" ) ;
} ,
} ,
props : {
width : {
default : 200 ,
} ,
labelWidth : {
default : 40 ,
} ,
sp : {
default : "至" ,
} ,
initYear : {
default : null ,
} ,
} ,
data ( ) {
return {
itemBg : { } ,
startShowYear : null ,
endShowYear : null ,
yearList : [ ] ,
showPanel : false ,
startYear : null ,
endYear : null ,
curYear : 0 ,
curSelectedYear : 0 ,
curState : SELECT_STATE . unselect,
} ;
} ,
methods : {
checkStartInput ( event ) {
if ( isNaN ( this . startShowYear) ) {
this . startShowYear = this . startYear;
} else {
this . startYear = this . startShowYear * 1 ;
this . changeYear ( ) ;
}
} ,
checkEndInput ( ) {
if ( isNaN ( this . endShowYear) ) {
this . endShowYear = this . endYear;
} else {
this . endYear = this . endShowYear * 1 ;
this . changeYear ( ) ;
}
} ,
changeYear ( ) {
if ( this . startYear > this . endYear) {
let tmp = this . endYear;
this . endYear = this . startYear;
this . startYear = tmp;
this . startShowYear = this . startYear;
this . endShowYear = this . endYear;
}
if ( this . startYear && this . endYear) {
this . $emit ( "updateTimeRange" , {
startYear : moment ( this . startYear + "" )
. startOf ( "year" )
. valueOf ( ) ,
endYear :
moment ( this . endYear + "" )
. endOf ( "year" )
. valueOf ( ) + 1 ,
} ) ;
} else {
console. warn ( "WARN:年份不合法" , this . startYear, this . endYear) ;
}
} ,
onHoverItem ( iYear ) {
if ( this . curState === SELECT_STATE . selecting) {
let tmpStart = this . curSelectedYear;
this . endYear = Math. max ( tmpStart, iYear) ;
this . startYear = Math. min ( tmpStart, iYear) ;
}
} ,
onClickItem ( iYear ) {
if (
this . curState === SELECT_STATE . unselect ||
this . curState === SELECT_STATE . selected
) {
this . startYear = iYear;
this . curSelectedYear = iYear;
this . endYear = null ;
this . curState = SELECT_STATE . selecting;
} else if ( this . curState === SELECT_STATE . selecting) {
this . endShowYear = this . endYear;
this . startShowYear = this . startYear;
this . curState = SELECT_STATE . selected;
this . $emit ( "updateTimeRange" , {
startYear : moment ( this . startYear + "" )
. startOf ( "year" )
. valueOf ( ) ,
endYear :
moment ( this . endYear + "" )
. endOf ( "year" )
. valueOf ( ) + 1 ,
} ) ;
setTimeout ( ( ) => {
this . showPanel = false ;
} , 300 ) ;
}
} ,
onFocus ( ) {
this . $nextTick ( ( ) => {
this . showPanel = true ;
} ) ;
} ,
onBlur ( ) {
} ,
updateYearList ( ) {
let iStart = Math. floor ( this . curYear / 10 ) * 10 - 10 ;
iStart = iStart < 0 ? 0 : iStart;
this . yearList = [ ] ;
for ( let index = 0 ; index < 20 ; index++ ) {
this . yearList. push ( iStart + index) ;
}
} ,
closePanel ( e ) {
if ( ! this . showPanel) {
return ;
}
if ( typeof e. target. className !== "string" ) {
this . $nextTick ( ( ) => {
this . showPanel = false ;
} ) ;
return ;
}
if (
e. target. className. indexOf ( "_inner" ) === - 1 ||
( e. target. name === "yearInput" &&
e. target !== this . $refs. inputLeft &&
e. target !== this . $refs. inputRight)
) {
this . $nextTick ( ( ) => {
this . showPanel = false ;
} ) ;
}
e. stopPropagation ( ) ;
return false ;
} ,
onClickLeft ( ) {
this . curYear = this . curYear * 1 - 10 ;
this . updateYearList ( ) ;
} ,
onClickRight ( ) {
this . curYear = this . curYear * 1 + 10 ;
this . updateYearList ( ) ;
} ,
setYear ( startYearStamp, endYearStamp ) {
if ( ! isNaN ( startYearStamp) && ! isNaN ( endYearStamp) ) {
let startYear = moment ( startYearStamp) . format ( "yyyy" ) ;
let endYear = moment ( endYearStamp) . format ( "yyyy" ) ;
this . startYear = startYear * 1 ;
this . endYear = endYear * 1 ;
this . endShowYear = endYear * 1 ;
this . startShowYear = startYear * 1 ;
}
} ,
} ,
created ( ) {
this . curYear = moment ( ) . format ( "yyyy" ) ;
this . updateYearList ( ) ;
} ,
beforeUnmount ( ) {
document. removeEventListener ( "click" , this . closePanel . bind ( this ) ) ;
} ,
mounted ( ) {
this . $refs. yearPicker. style = "padding-left:" + this . labelWidth + "px" ;
document. addEventListener ( "click" , this . closePanel . bind ( this ) ) ;
} ,
} ;
< / script>
< style lang= "scss" scoped>
. yearPicker {
font- size: 14px;
display : flex;
position : relative;
transition : all 0 . 3s;
input : first- child {
text- align: center;
}
. labelText {
position : absolute;
left : 10px;
top : 10px;
color : #c4c6d1;
}
background- color: #fff;
span {
padding : 0 8px;
height : 36px;
line- height: 36px;
}
border : 1px solid #eff1f3;
height : 36px;
line- height: 36px;
border- radius: 4px;
padding : 0 28px 0 8px;
box- sizing: border- box;
. floatPanel {
> div {
width : 50 % ;
}
position : absolute;
display : flex;
background- color: #fff;
z- index: 9999 ! important;
border- radius: 4px;
height : 252px;
top : 50px;
left : 0px;
box- shadow: 0 2px 12px 0 rgba ( 0 , 0 , 0 , 0.1 ) ;
border : 1px solid #dfe4ed;
. panelContent {
display : grid;
grid- template- columns: 25 % 25 % 25 % 25 % ;
width : 100 % ;
height : calc ( 100 % - 15px) ;
margin- top: 8px;
. oneSelected {
border- top- right- radius: 24px;
border- bottom- right- radius: 24px;
}
. startSelected {
background- color: #f2f6fc;
border- top- left- radius: 24px;
border- bottom- left- radius: 24px;
}
. endSelected {
background- color: #f2f6fc;
border- top- right- radius: 24px;
border- bottom- right- radius: 24px;
}
. betweenSelected {
background- color: #f2f6fc;
}
> div {
width : 75px;
height : 48px;
line- height: 48px;
margin : 6px 0 ;
text- align: center;
a {
display : inline- block;
width : 60px;
height : 36px;
cursor : pointer;
line- height: 36px;
border- radius: 18px;
color : #606266 ;
}
. selected {
background- color: #1890ff;
color : #fff;
}
}
}
. panelHead {
height : 38px;
line- height: 38px;
position : relative;
text- align: center;
font- size: 16px;
border- bottom: 1px solid #dfe4ed;
i {
position : absolute;
cursor : pointer;
& : hover {
color : #1890ff;
}
}
}
. rightPanel {
margin : 16px;
display : flex;
flex- direction: column;
}
. line {
width : 1px;
height : 100 % ;
background : #dfe4ed;
}
. leftPanel {
margin : 16px;
display : flex;
flex- direction: column;
}
. leftPanel . panelHead i {
left : 0px;
top : 10px;
font- size: 14px;
color : #717273 ;
}
. rightPanel . panelHead i {
right : 0px;
top : 8px;
}
. leftPanel . panelHead i: hover,
. rightPanel . panelHead i: hover {
cursor : pointer;
}
}
. floatPanel: : before {
content : "" ;
border- bottom: 6 . 5px solid #797979 ;
border- left: 6 . 5px solid transparent;
border- right: 6 . 5px solid transparent;
position : absolute;
left : 44px;
- webkit- transform: translateX ( - 50 % ) ;
transform : translateX ( - 50 % ) ;
top : - 5 . 5px;
border- radius: 5px;
}
. floatPanel: : after {
content : "" ;
border- bottom: 8px solid #fff;
border- left: 8px solid transparent;
border- right: 8px solid transparent;
position : absolute;
left : 44px;
- webkit- transform: translateX ( - 50 % ) ;
transform : translateX ( - 50 % ) ;
top : - 5px;
border- radius: 5px;
}
}
input {
width : 60px;
border : none;
height : 37px;
line- height: 37px;
box- sizing: border- box;
background- color: transparent;
text- align: center;
color : #606266 ;
}
input : focus {
outline : none;
background- color: transparent;
}
. yearPicker: hover {
border- color: #1890ff;
}
. dateIcon {
position : absolute;
right : 16px;
top : 9px;
color : #adb2bc;
}
< / style>
使用:
< YearYear1 style= "width:300px" : initYear= "dateValue2" @updateTimeRange= "updateStatisticYear" / >
dateValue2 : [ ] ,
updateStatisticYear ( val ) {
console. log ( "年" , val) ;
} ,