基于quasar,只选择年度与月份的组件
为什么要做
quasar是个基于vue的强大的UI开发库,它提供了非常多的组件,比如日期选择。但是有些时候只需要选择到月份就可以了,quasar中没有,所以自己动手写了一个。因为对界面编程我不熟悉,所以,如果你有更好的想法,请不吝赐教。源码在gitcode、gitee、github的至简网格/企业服务上都有,以Apache License
协议开源,gitcode连接如下:
assets/file/v3/components/month_input.js · master · 至简网格 / 企业服务 · GitCode
用法:
1)先引入
import MonthInput from "path_to_components/month_input.js"
2)再注册
组件中注册:components:{"month-input":MonthInput}
或全局注册:app.component('month-input', MonthInput); app是使用Vue.createApp创建的。
3)最后使用
<month-input class="justify-center text-primary" min="-5" max="cur" @update:modelValue="f"></month-input>
属性
min、max、monthName(默认为“月”)
min、max接受以下几种格式:cur当前月份、-x当前年度减x年,+x当前年度加x年,yyyy/MM、yyyy-MM或yyyy.MM具体的月份;不设置则不限制。
update:modelValue触发回调时传递一个对象,其中包括{year:年份,month:月份(从1开始),num:年份*12+月份-1}
操作
没有点击时显示如下:
点击左右箭头前移一个月或后移一个月;点击中间的年/月,显示一个弹窗,在min、max指定范围之外的年月显示为灰色,如果选中的年份不在当前年份列表页中,月份全部显示灰色。点击左右箭头前移或后移12年。先选择年份,然后选择月份就可以了触发update:modelValue,同时隐藏弹窗。
源码
//月份选择组件month-input
export default{
data(){return {maxMonth:0,minMonth:0,year:'',month:'',num:0,//year*12+month-1startYear:0,years:[],months:[],old:{y:0,m:0}
}},
props: {modelValue:{type:String},min:{type:String,default:''}, //年份max:{type:String,default:''},monthName:{type:String, default:"月"}
},
emits: ['update:modelValue'],
created(){var m=this.parse(this.max,{y:9999,m:1});this.maxMonth=m.y*12+m.m-1;m=this.parse(this.min,{y:0,m:1});this.minMonth=m.y*12+m.m-1;var dt=new Date();m=this.parse(this.modelValue,{y:dt.getFullYear(),m:dt.getMonth()+1})this.old={year:m.y, month:m.m};this.year=m.y;this.month=m.m;this.num=this.year*12+this.month-1;this.startYear=this.year-4;this.set_array();
},
methods:{
set_array() {var month;var list=[];var chked=false;var v=this.startYear;var yMax=Math.floor(this.maxMonth/12);var yMin=Math.floor(this.minMonth/12);for(var i=0;i<4;i++) {var yy=[];for(var j=0;j<3;j++) {var y={v:v,cls:"col text-center"};if(v>yMax||v<yMin) {y.cls+=" text-grey";} else if(v==this.year) {y.cls+=" bg-primary text-white";chked=true;}yy.push(y);v++;}list.push(yy);}this.years=list;v=1;list=[];for(var i=0;i<4;i++) {var mm=[];for(var j=0;j<3;j++) {var m={v:v,cls:"col text-center"};if(chked) {//所选年份可见month=this.year*12+v-1;if(month>this.maxMonth||month<this.minMonth) {m.cls+=" text-grey";} else if(v==this.month) {m.cls+=" bg-primary text-white";}} else {m.cls+=" text-grey";}mm.push(m);v++;}list.push(mm);} this.months=list;
},
parse(s,def) {if(!s) {return def;}var cfg=s.trim().toLowerCase();var dt=new Date();if(cfg=="cur") {return {y:dt.getFullYear(),m:dt.getMonth()+1};}if(cfg.startsWith('-')) {var v = parseInt(cfg.substring(1));return {y:dt.getFullYear()-v, m:1};}if(cfg.startsWith('+')) {var v = parseInt(cfg.substring(1));return {y:dt.getFullYear()+v, m:1};}var y,m;var p=cfg.indexOf('/');if(p<0)p=cfg.indexOf('-');if(p<0)p=cfg.indexOf('.');if(p>0) {y=parseInt(cfg.substring(0,p));m=parseInt(cfg.substring(p+1));} else {y=parseInt(cfg);m=1;}return {y:y,m:m};
},
pageUp() {this.startYear-=12;this.set_array();
},
pageDn() {this.startYear+=12;this.set_array();
},
fore(){if(this.num<=this.minMonth)return;this.month--;if(this.month==0) {this.year--;this.month=12;}this.num=this.year*12+this.month-1;this.old={year:this.year, month:this.month,num:this.num};this.$emit('update:modelValue', this.old);
},
next(){if(this.num>=this.maxMonth)return;this.month++;if(this.month>12) {this.year++;this.month=1;}this.num=this.year*12+this.month-1;this.old={year:this.year, month:this.month,num:this.num};this.$emit('update:modelValue', this.old);
},
set_year(v) {var yMax=Math.ceil(this.maxMonth/12);var yMin=Math.floor(this.minMonth/12);if(v>yMax||v<yMin) {return;}this.month=-1;this.year=v;this.set_array();
},
set_month(v) {if(this.year<this.startYear||this.year>=this.startYear+12) {return;//未选择年份}var m=v-1+this.year*12;if(m>this.maxMonth||m<this.minMonth) {return; //不在有效范围内}this.month=v;if(v!=this.old.month||this.year!=this.old.year) {this.num=this.year*12+this.month-1;this.old={year:this.year, month:this.month,num:this.num};this.$emit('update:modelValue',this.old);}this.$refs._my_dlg.hide();
}
},
computed: {value: {get() {return this.year+'/'+(this.month>9?this.month:('0'+this.month))},set(v) {var ym=this.parse(v);this.year=ym.y;this.month=ym.m;this.num=this.year*12+this.month-1;}}
},
template: `
<div class="row"><div class="rol q-pr-lg"><q-icon name="navigate_before" @click="fore":class="num<=minMonth?'text-grey':''"></q-icon></div><div class="rol" style="cursor:pointer">{{year}} / {{month<10?('0'+month):month}}<q-popup-proxy cover @before-show="set_array" ref="_my_dlg"><div class="row q-pa-sm" style="min-width:20em;"><div class="col self-center"><q-icon name="navigate_before" @click="pageUp" size="2em" class="q-px-sm"></q-icon></div><div class="col-8"><div class="row" v-for="yy in years"><div v-for="y in yy" :class="y.cls" @click="set_year(y.v)"style="cursor:pointer">{{y.v}}</div></div><q-separator spaced="md"></q-separator><div class="row" v-for="mm in months"><div v-for="m in mm" :class="m.cls" @click="set_month(m.v)"style="cursor:pointer">{{m.v}}{{monthName}}</div></div></div><div class="col self-center"><q-icon name="navigate_next" @click="pageDn" size="2em" class="q-px-sm"></q-icon></div></div></q-popup-proxy></div><div class="rol q-pl-lg"><q-icon name="navigate_next" @click="next":class="num>=maxMonth?'text-grey':''"></q-icon></div>
</div>
`
}