2
0
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:
mengxiong10
2017-05-16 20:11:39 +08:00
parent c24a73ad62
commit b14834456b
6 changed files with 98 additions and 73 deletions
+4 -4
View File
@@ -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;
+18 -21
View File
@@ -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
View File
@@ -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);
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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