mirror of
https://github.com/tenrok/vue2-datepicker.git
synced 2026-06-24 22:30:36 +03:00
添加popup position 检测
This commit is contained in:
+4
-4
@@ -16,11 +16,11 @@ import DatePicker from './datepicker/index.vue'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components:{ DatePicker },
|
components: { DatePicker },
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
value1:'2017-5-9',
|
value1: '2017-5-9',
|
||||||
value2:'',
|
value2: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ export default {
|
|||||||
<style>
|
<style>
|
||||||
.demo {
|
.demo {
|
||||||
float:left;
|
float:left;
|
||||||
margin:60px;
|
margin:250px;
|
||||||
}
|
}
|
||||||
.label{
|
.label{
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
|
|||||||
@@ -29,48 +29,46 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Languages from './languages.js'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
startAt: null,
|
startAt: null,
|
||||||
endAt: null,
|
endAt: null,
|
||||||
value: null,
|
value: null,
|
||||||
show: Boolean,
|
show: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
const translation = this.$parent.translation
|
const translation = this.$parent.translation
|
||||||
return {
|
return {
|
||||||
days: translation.days,
|
days: translation.days,
|
||||||
months: translation.months,
|
months: translation.months,
|
||||||
dates: [],
|
dates: [],
|
||||||
now: new Date(),
|
now: new Date()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created () {
|
||||||
this.updateCalendar()
|
this.updateCalendar()
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
show(val) {
|
show (val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
this.updateNow()
|
this.updateNow()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
handler:'updateNow',
|
handler: 'updateNow',
|
||||||
immediate: true,
|
immediate: true
|
||||||
},
|
},
|
||||||
now: 'updateCalendar',
|
now: 'updateCalendar'
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateNow() {
|
updateNow () {
|
||||||
let now = this.value ? new Date(this.value) : new Date()
|
let now = this.value ? new Date(this.value) : new Date()
|
||||||
now.setDate(1)
|
now.setDate(1)
|
||||||
this.now = now
|
this.now = now
|
||||||
},
|
},
|
||||||
// 更新面板选择时间
|
// 更新面板选择时间
|
||||||
updateCalendar() {
|
updateCalendar () {
|
||||||
function getCalendar(time, firstday, length, classes) {
|
function getCalendar (time, firstday, length, classes) {
|
||||||
return Array.apply(null, { length }).map((v, i) => { // eslint-disable-line
|
return Array.apply(null, { length }).map((v, i) => { // eslint-disable-line
|
||||||
let day = firstday + i
|
let day = firstday + i
|
||||||
const date = new Date(time.getFullYear(), time.getMonth(), day)
|
const date = new Date(time.getFullYear(), time.getMonth(), day)
|
||||||
@@ -78,7 +76,7 @@ export default {
|
|||||||
title: date.toLocaleDateString(),
|
title: date.toLocaleDateString(),
|
||||||
date,
|
date,
|
||||||
day,
|
day,
|
||||||
classes,
|
classes
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -106,7 +104,7 @@ export default {
|
|||||||
}
|
}
|
||||||
this.dates = result
|
this.dates = result
|
||||||
},
|
},
|
||||||
getClasses(cell) {
|
getClasses (cell) {
|
||||||
const classes = []
|
const classes = []
|
||||||
const cellTime = cell.date.getTime()
|
const cellTime = cell.date.getTime()
|
||||||
const curTime = this.value ? new Date(this.value).setHours(0, 0, 0, 0) : 0
|
const curTime = this.value ? new Date(this.value).setHours(0, 0, 0, 0) : 0
|
||||||
@@ -138,24 +136,24 @@ export default {
|
|||||||
|
|
||||||
return classes.join(' ')
|
return classes.join(' ')
|
||||||
},
|
},
|
||||||
changeYear(flag) {
|
changeYear (flag) {
|
||||||
const now = new Date(this.now)
|
const now = new Date(this.now)
|
||||||
now.setFullYear(now.getFullYear() + flag)
|
now.setFullYear(now.getFullYear() + flag)
|
||||||
this.now = now
|
this.now = now
|
||||||
},
|
},
|
||||||
changeMonth(flag) {
|
changeMonth (flag) {
|
||||||
const now = new Date(this.now)
|
const now = new Date(this.now)
|
||||||
now.setMonth(now.getMonth() + flag)
|
now.setMonth(now.getMonth() + flag)
|
||||||
this.now = now
|
this.now = now
|
||||||
},
|
},
|
||||||
selectDate(cell) {
|
selectDate (cell) {
|
||||||
const classes = this.getClasses(cell)
|
const classes = this.getClasses(cell)
|
||||||
if (classes.indexOf('disabled') !== -1) {
|
if (classes.indexOf('disabled') !== -1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$emit('input', cell.date)
|
this.$emit('input', cell.date)
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -242,4 +240,3 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
+69
-41
@@ -16,6 +16,8 @@
|
|||||||
@click="clickIcon" ></i>
|
@click="clickIcon" ></i>
|
||||||
<div class="datepicker-popup"
|
<div class="datepicker-popup"
|
||||||
:class="{'range':range}"
|
:class="{'range':range}"
|
||||||
|
:style="position"
|
||||||
|
ref="calendar"
|
||||||
v-show="showPopup">
|
v-show="showPopup">
|
||||||
<template v-if="!range">
|
<template v-if="!range">
|
||||||
<calendar-panel v-model="currentValue" :show="showPopup"></calendar-panel>
|
<calendar-panel v-model="currentValue" :show="showPopup"></calendar-panel>
|
||||||
@@ -40,56 +42,63 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
format: {
|
format: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'yyyy-MM-dd',
|
default: 'yyyy-MM-dd'
|
||||||
},
|
},
|
||||||
range: {
|
range: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: 210,
|
default: 210
|
||||||
},
|
},
|
||||||
placeholder: String,
|
placeholder: String,
|
||||||
lang: {
|
lang: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'zh'
|
default: 'zh'
|
||||||
},
|
},
|
||||||
value: null,
|
value: null
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
showPopup: false,
|
showPopup: false,
|
||||||
showCloseIcon: false,
|
showCloseIcon: false,
|
||||||
currentValue: this.value,
|
currentValue: this.value,
|
||||||
ranges: [], // 快捷选项
|
position: null,
|
||||||
|
ranges: [] // 快捷选项
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value: {
|
value: {
|
||||||
handler(val) {
|
handler (val) {
|
||||||
if (!this.range) {
|
if (!this.range) {
|
||||||
this.currentValue = this.isValidDate(val) ? val : undefined
|
this.currentValue = this.isValidDate(val) ? val : undefined
|
||||||
} else {
|
} else {
|
||||||
this.currentValue = this.isValidRange(val) ? val : [undefined, undefined]
|
this.currentValue = this.isValidRange(val) ? val : [undefined, undefined]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
immediate: true,
|
immediate: true
|
||||||
},
|
},
|
||||||
currentValue(val) {
|
currentValue (val) {
|
||||||
if ((!this.range && val) || (this.range && val[0] && val[1])) {
|
if ((!this.range && val) || (this.range && val[0] && val[1])) {
|
||||||
this.$emit('input', val)
|
this.$emit('input', val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
showPopup (val) {
|
||||||
|
if (val) {
|
||||||
|
this.$nextTick(this.displayPopup)
|
||||||
|
// this.displayPopup()
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
translation() {
|
translation () {
|
||||||
return Languages[this.lang] || Languages['en']
|
return Languages[this.lang] || Languages['en']
|
||||||
},
|
},
|
||||||
innerPlaceholder() {
|
innerPlaceholder () {
|
||||||
return this.placeholder || (this.range ? this.translation.placeholder.dateRange : this.translation.placeholder.date)
|
return this.placeholder || (this.range ? this.translation.placeholder.dateRange : this.translation.placeholder.date)
|
||||||
},
|
},
|
||||||
text() {
|
text () {
|
||||||
if (!this.range && this.currentValue) {
|
if (!this.range && this.currentValue) {
|
||||||
return this.stringify(this.currentValue)
|
return this.stringify(this.currentValue)
|
||||||
}
|
}
|
||||||
@@ -97,16 +106,13 @@ export default {
|
|||||||
return this.stringify(this.currentValue[0]) + ' ~ ' + this.stringify(this.currentValue[1])
|
return this.stringify(this.currentValue[0]) + ' ~ ' + this.stringify(this.currentValue[1])
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
},
|
}
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.initRanges()
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closePopup() {
|
closePopup () {
|
||||||
this.showPopup = false
|
this.showPopup = false
|
||||||
},
|
},
|
||||||
togglePopup() {
|
togglePopup () {
|
||||||
if (this.showPopup) {
|
if (this.showPopup) {
|
||||||
this.$refs.input.blur()
|
this.$refs.input.blur()
|
||||||
this.showPopup = false
|
this.showPopup = false
|
||||||
@@ -115,7 +121,7 @@ export default {
|
|||||||
this.showPopup = true
|
this.showPopup = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hoverIcon(e) {
|
hoverIcon (e) {
|
||||||
if (e.type === 'mouseenter' && this.text) {
|
if (e.type === 'mouseenter' && this.text) {
|
||||||
this.showCloseIcon = true
|
this.showCloseIcon = true
|
||||||
}
|
}
|
||||||
@@ -123,14 +129,14 @@ export default {
|
|||||||
this.showCloseIcon = false
|
this.showCloseIcon = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clickIcon() {
|
clickIcon () {
|
||||||
if (this.showCloseIcon) {
|
if (this.showCloseIcon) {
|
||||||
this.$emit('input', '')
|
this.$emit('input', '')
|
||||||
} else {
|
} else {
|
||||||
this.togglePopup()
|
this.togglePopup()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
formatDate(date, fmt) {
|
formatDate (date, fmt) {
|
||||||
const map = {
|
const map = {
|
||||||
'M+': date.getMonth() + 1, // 月份
|
'M+': date.getMonth() + 1, // 月份
|
||||||
'[Dd]+': date.getDate(), // 日
|
'[Dd]+': date.getDate(), // 日
|
||||||
@@ -138,7 +144,7 @@ export default {
|
|||||||
'm+': date.getMinutes(), // 分
|
'm+': date.getMinutes(), // 分
|
||||||
's+': date.getSeconds(), // 秒
|
's+': date.getSeconds(), // 秒
|
||||||
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
|
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
|
||||||
'S': date.getMilliseconds(), // 毫秒
|
'S': date.getMilliseconds() // 毫秒
|
||||||
}
|
}
|
||||||
let str = fmt.replace(/[Yy]+/g, function (str) {
|
let str = fmt.replace(/[Yy]+/g, function (str) {
|
||||||
return ('' + date.getFullYear()).slice(4 - str.length)
|
return ('' + date.getFullYear()).slice(4 - str.length)
|
||||||
@@ -151,51 +157,72 @@ export default {
|
|||||||
})
|
})
|
||||||
return str
|
return str
|
||||||
},
|
},
|
||||||
stringify(date) {
|
stringify (date) {
|
||||||
return this.formatDate(new Date(date), this.format)
|
return this.formatDate(new Date(date), this.format)
|
||||||
},
|
},
|
||||||
isValidDate(date) {
|
isValidDate (date) {
|
||||||
return !!new Date(date).getTime()
|
return !!new Date(date).getTime()
|
||||||
},
|
},
|
||||||
isValidRange(date) {
|
isValidRange (date) {
|
||||||
return Array.isArray(date) &&
|
return Array.isArray(date) &&
|
||||||
date.length === 2 &&
|
date.length === 2 &&
|
||||||
this.isValidDate(date[0]) &&
|
this.isValidDate(date[0]) &&
|
||||||
this.isValidDate(date[1])
|
this.isValidDate(date[1])
|
||||||
},
|
},
|
||||||
selectRange(range) {
|
selectRange (range) {
|
||||||
this.$emit('input', [range.start, range.end])
|
this.$emit('input', [range.start, range.end])
|
||||||
},
|
},
|
||||||
initRanges() {
|
initRanges () {
|
||||||
this.ranges = [{
|
this.ranges = [{
|
||||||
text: '今天',
|
text: '未来7天',
|
||||||
start: new Date(),
|
start: new Date(),
|
||||||
end: new Date(),
|
end: new Date(Date.now() + 3600 * 1000 * 24 * 7)
|
||||||
}, {
|
}, {
|
||||||
text: '未来一周',
|
text: '未来30天',
|
||||||
start: new Date(),
|
|
||||||
end: new Date(Date.now() + 3600 * 1000 * 24 * 7),
|
|
||||||
}, {
|
|
||||||
text: '未来一个月',
|
|
||||||
start: new Date(),
|
start: new Date(),
|
||||||
end: new Date(Date.now() + 3600 * 1000 * 24 * 30)
|
end: new Date(Date.now() + 3600 * 1000 * 24 * 30)
|
||||||
}, {
|
}, {
|
||||||
text: '最近一周',
|
text: '最近7天',
|
||||||
start: new Date(Date.now() - 3600 * 1000 * 24 * 7),
|
start: new Date(Date.now() - 3600 * 1000 * 24 * 7),
|
||||||
end: new Date(),
|
end: new Date()
|
||||||
}, {
|
}, {
|
||||||
text: '最近一个月',
|
text: '最近30天',
|
||||||
start: new Date(Date.now() - 3600 * 1000 * 24 * 30),
|
start: new Date(Date.now() - 3600 * 1000 * 24 * 30),
|
||||||
end: new Date(),
|
end: new Date()
|
||||||
}]
|
}]
|
||||||
this.ranges.forEach((v, i) => {
|
this.ranges.forEach((v, i) => {
|
||||||
v.text = this.translation.pickers[i]
|
v.text = this.translation.pickers[i]
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
displayPopup () {
|
||||||
|
console.log()
|
||||||
|
const dw = document.documentElement.clientWidth
|
||||||
|
const dh = document.documentElement.clientHeight
|
||||||
|
const InputRect = this.$el.getBoundingClientRect()
|
||||||
|
const PopupRect = this.$refs.calendar.getBoundingClientRect()
|
||||||
|
this.position = {}
|
||||||
|
if (dw - InputRect.left < PopupRect.width && InputRect.right < PopupRect.width) {
|
||||||
|
this.position.left = 1 - InputRect.left + 'px'
|
||||||
|
} else if (InputRect.left + InputRect.width / 2 <= dw / 2) {
|
||||||
|
this.position.left = 0
|
||||||
|
} else {
|
||||||
|
this.position.right = 0
|
||||||
|
}
|
||||||
|
if (InputRect.top <= PopupRect.height + 1 && dh - InputRect.bottom <= PopupRect.height + 1) {
|
||||||
|
this.position.top = dh - InputRect.top - PopupRect.height - 1 + 'px'
|
||||||
|
} else if (InputRect.top + InputRect.height / 2 <= dh / 2) {
|
||||||
|
this.position.top = '100%'
|
||||||
|
} else {
|
||||||
|
this.position.bottom = '100%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.initRanges()
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
clickoutside: {
|
clickoutside: {
|
||||||
bind(el, binding, vnode) {
|
bind (el, binding, vnode) {
|
||||||
el['@clickoutside'] = (e) => {
|
el['@clickoutside'] = (e) => {
|
||||||
if (!el.contains(e.target) && binding.expression && vnode.context[binding.expression]) {
|
if (!el.contains(e.target) && binding.expression && vnode.context[binding.expression]) {
|
||||||
binding.value()
|
binding.value()
|
||||||
@@ -203,9 +230,9 @@ export default {
|
|||||||
}
|
}
|
||||||
document.addEventListener('click', el['@clickoutside'], true)
|
document.addEventListener('click', el['@clickoutside'], true)
|
||||||
},
|
},
|
||||||
unbind(el) {
|
unbind (el) {
|
||||||
document.removeEventListener('click', el['@clickoutside'], true)
|
document.removeEventListener('click', el['@clickoutside'], true)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,6 +255,7 @@ export default {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
width: 248px;
|
width: 248px;
|
||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
|
margin-bottom: 1px;
|
||||||
border: 1px solid #d9d9d9;
|
border: 1px solid #d9d9d9;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export default {
|
|||||||
'zh': {
|
'zh': {
|
||||||
'days': ['日', '一', '二', '三', '四', '五', '六'],
|
'days': ['日', '一', '二', '三', '四', '五', '六'],
|
||||||
'months': ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
'months': ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
||||||
'pickers': ['今天', '未来一周', '未来一个月', '最近一周', '最近一个月'],
|
'pickers': ['未来7天', '未来30天', '最近7天', '最近30天'],
|
||||||
'placeholder': {
|
'placeholder': {
|
||||||
'date': '请选择日期',
|
'date': '请选择日期',
|
||||||
'dateRange': '请选择日期范围'
|
'dateRange': '请选择日期范围'
|
||||||
@@ -11,10 +11,10 @@ export default {
|
|||||||
'en': {
|
'en': {
|
||||||
'days': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
'days': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||||||
'months': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
'months': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
||||||
'pickers': ['today', 'next week', 'next month', 'last week', 'last month'],
|
'pickers': ['next 7 days', 'next 30 days', 'previous 7 days', 'previous 30 days'],
|
||||||
'placeholder': {
|
'placeholder': {
|
||||||
'date': 'Select Date',
|
'date': 'Select Date',
|
||||||
'dateRange': 'Select Date Range'
|
'dateRange': 'Select Date Range'
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
|
||||||
new Vue({
|
new Vue({ // eslint-disable-line
|
||||||
el: '#app',
|
el: '#app',
|
||||||
render: h => h(App)
|
render: h => h(App)
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ module.exports = {
|
|||||||
devServer: {
|
devServer: {
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
noInfo: true,
|
noInfo: true,
|
||||||
port:9000
|
port: 9000
|
||||||
},
|
},
|
||||||
performance: {
|
performance: {
|
||||||
hints: false
|
hints: false
|
||||||
|
|||||||
Reference in New Issue
Block a user