vue?+?element-ui?季度選擇器組件?el-quarter-picker示例詳解

使用說(shuō)明
1、復(fù)制組件文件 ElQuarterPicker.vue 到項(xiàng)目(依賴element-ui),組件源碼在后面
2、引用并調(diào)用組件
<template>
<div class="app-container">
<el-quarter-picker v-model="value" placeholder="選擇季度" />
</div>
</template>
<script>
import ElQuarterPicker from './ElQuarterPicker'
export default {
components: { ElQuarterPicker },
data() {
return {
value: ''
}
}
}
</script>ElQuarterPicker.vue
<template>
<div class="el-quarter-picker">
<el-popover
v-model="visible"
:disabled="!canPopover"
:tabindex="null"
placement="bottom-start"
transition="el-zoom-in-top"
trigger="click">
<div class="el-date-picker">
<div class="el-picker-panel__body">
<div class="el-date-picker__header el-date-picker__header--bordered" style="margin:0px; line-height:30px">
<button
type="button"
@click="clickLast"
aria-label="前一年"
class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left"></button>
<span role="button" class="el-date-picker__header-label" @click="clickYear">{{ title }}</span>
<button
type="button"
@click="clickNext"
aria-label="后一年"
class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right"></button>
</div>
<div class="el-picker-panel__content" style="margin:0px; width:100%">
<table class="el-month-table" style="">
<tbody>
<tr v-for="line in lineCount" :key="line">
<td v-for="index in (line * 4 <= viewList.length ? 4 : viewList.length - (line - 1) * 4)" :key="index" :class="{ today: viewList[(line - 1) * 4 + index - 1].current, current: viewList[(line - 1) * 4 + index - 1].active }">
<div><a class="cell" @click="clickItem(viewList[(line - 1) * 4 + index - 1])">{{ viewList[(line - 1) * 4 + index - 1].label }}</a></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<el-input
slot="reference"
@change="changeText"
@mouseenter.native="mouseEnter"
@mouseleave.native="mouseLeave"
:placeholder="placeholder"
v-model="text"
:size="size"
:readonly="!canEdit"
:disabled="disabled">
<i slot="prefix" class="el-input__icon el-icon-date"></i>
<i slot="suffix" class="el-input__icon el-icon-circle-close" v-show="showClear" style="cursor:pointer" @click.stop="clear"></i>
</el-input>
</el-popover>
</div>
</template>
<script>
export default {
name: 'ElQuarterPicker',
props: {
placeholder: {
type: String,
default: ''
},
size: {
type: String,
default: ''
},
readonly: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: true
},
editable: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
},
format: {
type: String,
default: 'yyyy年第Q季度'
},
valueFormat: {
type: String,
default: 'yyyy-qq'
},
value: {
type: String,
default: ''
}
},
model: {
prop: 'value',
event: 'change'
},
watch: {
value(val) {
// console.log('change-------', val)
this.changeValue(val)
},
readonly(val) {
this.canEdit = !val && this.editable
this.canPopover = !this.disabled && !val
},
editable(val) {
this.canEdit = !this.readonly && val
},
disabled(val) {
this.canPopover = !val && !this.readonly
}
},
data() {
return {
visible: false,
showClear: false, // 控制清空按鈕展示
canEdit: true, // 是否可編輯
canPopover: true, // 選擇器彈出是否可用
text: '', // 文本框值
viewType: 1, // 視圖類型,1季度,2年度
viewYear: 0, // 當(dāng)前年份
viewList: [], // 數(shù)據(jù)列表
lineCount: 0, // 數(shù)據(jù)行數(shù)
title: '', // 選擇器標(biāo)題
data: [0, 0] // 當(dāng)前選擇年度-季度
}
},
mounted() {
// console.log('mounted--------', this.value)
this.changeValue(this.value)
// 設(shè)置文本框是否可編輯
this.canEdit = !this.readonly && this.editable
this.canPopover = !this.disabled && !this.readonly
// 監(jiān)聽(tīng)按鍵(上下左右鍵可以切換季度)
document.onkeydown = (event) => {
if (this.visible) {
const data = [this.data[0], this.data[1]]
if (data[0] < 1 || data[1] < 1) {
// 以當(dāng)前季度為標(biāo)準(zhǔn)
const curDate = new Date()
data[0] = curDate.getFullYear()
data[1] = parseInt(curDate.getMonth() / 3) + 1
}
if (event.code === 'ArrowLeft') {
// 上一個(gè)季度
if (data[1] === 1) {
data[0] = data[0] - 1
data[1] = 4
} else {
data[1] = data[1] - 1
}
} else if (event.code === 'ArrowRight') {
// 下一個(gè)季度
if (data[1] === 4) {
data[0] = data[0] + 1
data[1] = 1
} else {
data[1] = data[1] + 1
}
} else if (event.code === 'ArrowUp') {
// 上一年季度
data[0] = data[0] - 1
} else if (event.code === 'ArrowDown') {
// 下一年季度
data[0] = data[0] + 1
} else {
return
}
// 超過(guò)年限的不處理
if (data[0] < 1000 || data[0] > 9999) {
return
}
this.data = data
this.viewType = 1
this.viewYear = data[0]
this.$emit('change', this.formatTo(data, this.valueFormat))
}
}
},
destroyed() {
document.onkeydown = null
},
methods: {
// 季度文本變更
changeText() {
if (this.checkFormat(this.format, this.text)) {
// 設(shè)置值
this.formatFrom(this.text, this.format)
this.$emit('change', this.formatTo(this.data, this.valueFormat))
} else {
// 輸入了無(wú)效的格式,還原回原來(lái)的值
if (this.data[0] < 1 || this.data[1] < 1) {
this.text = ''
} else {
this.text = this.formatTo(this.data, this.format)
}
}
this.visible = false
},
// 鼠標(biāo)進(jìn)入
mouseEnter() {
if (!this.disabled && !this.readonly && this.clearable && this.text !== '') {
this.showClear = true
}
},
// 鼠標(biāo)離開(kāi)
mouseLeave() {
if (!this.disabled && this.clearable) {
this.showClear = false
}
},
// 清除季度
clear() {
this.showClear = false
this.visible = false
this.$emit('change', '')
},
// 季度值變更
changeValue(val) {
this.viewType = 1
if (val) {
// 反向格式化
this.formatFrom(val, this.valueFormat)
this.text = this.formatTo(this.data, this.format)
this.viewYear = this.data[0]
} else {
this.text = ''
this.data = [0, 0]
this.viewYear = new Date().getFullYear()
}
this.initView()
},
// 初始化視圖數(shù)據(jù)
initView() {
const list = []
const curDate = new Date()
const curYear = curDate.getFullYear()
const curQuarter = parseInt(curDate.getMonth() / 3) + 1
if (this.viewType === 1) {
let index = 0
for (const i of '一二三四') {
index++
const item = { label: '第' + i + '季度', year: this.viewYear, quarter: index, current: false, active: false }
if (this.viewYear === curYear && index === curQuarter) {
item.current = true
} else if (this.viewYear === this.data[0] && index === this.data[1]) {
item.active = true
}
list.push(item)
}
this.title = this.viewYear + ' 年'
} else {
const start = parseInt(this.viewYear / 10) * 10
this.viewYear = start
for (let i = 0; i < 10; i++) {
const year = start + i
const item = { label: year + '', year: year, current: false, active: false }
if (year === curYear) {
item.current = true
} else if (year === this.data[0]) {
item.active = true
}
list.push(item)
}
this.title = start + ' 年 - ' + (start + 9) + ' 年'
}
this.viewList = list
this.lineCount = parseInt(list.length / 4)
if (list.length % 4 > 0) {
this.lineCount++
}
},
// 校驗(yàn)季度格式是否正確
checkFormat(pattern, val) {
// 格式轉(zhuǎn)成正則表達(dá)式
let text = ''
for (const char of pattern) {
const dict = '\\^$.+?*[]{}!'
if (dict.indexOf(char) === -1) {
text += char
} else {
text += '\\' + char
}
}
text = text.replace('yyyy', '[1-9]\\d{3}')
text = text.replace('qq', '0[1-4]')
text = text.replace('q', '[1-4]')
text = text.replace('Q', '[一二三四]')
text = '^' + text + '$'
const patt = new RegExp(text)
return patt.test(val)
},
// 格式化季度到指定格式
formatTo(data, pattern) {
let text = pattern.replace('yyyy', '' + data[0])
text = text.replace('qq', '0' + data[1])
text = text.replace('q', '' + data[1])
text = text.replace('Q', '一二三四'.substr(data[1] - 1, 1))
return text
},
// 以指定格式解析季度
formatFrom(str, pattern) {
const year = this.findText(str, pattern, 'yyyy')
const quarter = this.findText(str, pattern, ['qq', 'q', 'Q'])
this.data = [year, quarter]
},
// 查找文本數(shù)值
findText(str, pattern, find) {
if (find instanceof Array) {
for (const f of find) {
const val = this.findText(str, pattern, f)
if (val !== -1) {
return val
}
}
return -1
}
const index = pattern.indexOf(find)
if (index === -1) {
return index
}
const val = str.substr(index, find.length)
if (find === 'Q') {
return '一二三四'.indexOf(val) + 1
} else {
return parseInt(val)
}
},
// 年份點(diǎn)擊
clickYear() {
if (this.viewType !== 1) {
return
}
// 切換年度選擇器
this.viewType = 2
this.initView()
},
// 季度選擇
clickItem(item) {
// console.log('select--------', item)
if (this.viewType === 1) {
// 選擇季度
this.$emit('change', this.formatTo([item.year, item.quarter], this.valueFormat))
this.visible = false
} else {
// 選擇年度
this.viewType = 1
this.viewYear = item.year
this.initView()
}
},
// 上一年
clickLast() {
if (this.viewYear > 1000) {
if (this.viewType === 1) {
this.viewYear--
this.initView()
} else {
this.viewYear = this.viewYear - 10
this.initView()
}
}
},
// 下一年
clickNext() {
if (this.viewYear < 9999) {
if (this.viewType === 1) {
this.viewYear++
this.initView()
} else {
this.viewYear = this.viewYear + 10
this.initView()
}
}
}
}
}
</script>
<style>
.el-quarter-picker {
width: 220px;
display: inline-block;
}
</style>參考文檔
到此這篇關(guān)于vue + element-ui 季度選擇器組件 el-quarter-picker的文章就介紹到這了,更多相關(guān) element-ui 季度選擇器組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- element-ui時(shí)間日期選擇器限制選擇范圍的幾種場(chǎng)景
- vue項(xiàng)目element-ui級(jí)聯(lián)選擇器el-cascader回顯的問(wèn)題及解決
- element-ui動(dòng)態(tài)級(jí)聯(lián)選擇器回顯問(wèn)題詳解(二十多行代碼搞定)
- 解決element-ui的el-select選擇器的@blur事件失效的坑
- 詳解element-ui日期時(shí)間選擇器的日期格式化問(wèn)題
- element-ui 時(shí)間選擇器限制范圍的實(shí)現(xiàn)(隨動(dòng))
- vue2.0 element-ui中el-select選擇器無(wú)法顯示選中的內(nèi)容(解決方法)
相關(guān)文章
在Vant的基礎(chǔ)上實(shí)現(xiàn)添加表單驗(yàn)證框架的方法示例
這篇文章主要介紹了在Vant的基礎(chǔ)上實(shí)現(xiàn)添加驗(yàn)證框架的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
vue線上部署請(qǐng)求接口報(bào)錯(cuò)net::ERR_CONNECTION_REFUSED
vue線上部署請(qǐng)求接口報(bào)錯(cuò)net::ERR_CONNECTION_REFUSED問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
vue element-ui使用required進(jìn)行表單校驗(yàn)時(shí)自定義提示語(yǔ)問(wèn)題
這篇文章主要介紹了vue element-ui使用required進(jìn)行表單校驗(yàn)時(shí)自定義提示語(yǔ)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
Vue與Node.js通過(guò)socket.io通信的示例代碼
這篇文章主要介紹了Vue與Node.js通過(guò)socket.io通信的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Vue項(xiàng)目之安裝引入使用vconsole方式(生產(chǎn)環(huán)境不顯示)
在Vue2開(kāi)發(fā)中,引入vConsole可以為移動(dòng)端提供類似瀏覽器F12的調(diào)試工具,支持查看日志、網(wǎng)絡(luò)請(qǐng)求等功能,vConsole是一個(gè)輕量、可拓展的前端調(diào)試面板,與框架無(wú)關(guān),適用于多種前端框架,安裝方法包括npm和CDN兩種,可根據(jù)項(xiàng)目環(huán)境配置是否顯示調(diào)試面板2024-10-10
vue3自定義指令實(shí)現(xiàn)按鈕防抖示例詳解
這篇文章主要為大家介紹了vue3自定義指令實(shí)現(xiàn)按鈕防抖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
VUE實(shí)時(shí)監(jiān)聽(tīng)元素距離頂部高度的操作
這篇文章主要介紹了VUE實(shí)時(shí)監(jiān)聽(tīng)元素距離頂部高度的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
Antd下拉選擇,自動(dòng)匹配功能的實(shí)現(xiàn)
這篇文章主要介紹了Antd下拉選擇,自動(dòng)匹配功能的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10
vuex vue簡(jiǎn)單使用知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理了關(guān)于vuex vue簡(jiǎn)單使用知識(shí)點(diǎn)總結(jié),有需要的朋友們可以參考下。2019-08-08

