Skip to content

Commit 1c6ebbb

Browse files
author
luchunyu
committed
fix(datepicker): fix datepicker style bug
fix datepicker panel to flex style
1 parent cb2e611 commit 1c6ebbb

File tree

6 files changed

+467
-3
lines changed

6 files changed

+467
-3
lines changed

src/components/datepicker/index.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
background: color(var(--white));
6363
padding: 1em;
6464
font-size: 14px;
65+
display: flex;
66+
padding-bottom: 4em;
6567

6668
&.is-sm {
6769
font-size: 12px;
@@ -106,6 +108,10 @@
106108
.c-datepicker__text {
107109
text-align: center;
108110
margin: 0.5em 0;
111+
position: absolute;
112+
bottom: 1em;
113+
padding-right: 2em;
114+
width: 100%;
109115
}
110116

111117
.c-datepicker__btns {
@@ -121,6 +127,7 @@
121127
padding-top: 6px;
122128
background-color: #fff;
123129
overflow: auto;
130+
width: 6em;
124131
}
125132

126133
.c-datepicker__sidebar ul {

src/components/datepicker/index.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
:class="className"
99
)
1010
c-icon(name="x-circle")
11-
.c-datepicker__icon(:clas="className")
11+
.c-datepicker__icon(:class="className")
1212
c-icon(name="calendar")
1313
c-input(
1414
v-if="type == 'daterange' || type == 'monthrange'"
@@ -81,6 +81,7 @@ import './index.css'
8181
import validatable from '@scripts/mixins/validatable'
8282
import resettable from '@scripts/mixins/resettable'
8383
import ZIndexManager from '@scripts/utils/zIndexManager.js'
84+
import { getScrollBarSize } from '@util'
8485
8586
import Icon from '../icon/index.vue'
8687
import Input from '../input/index.vue'
@@ -285,10 +286,11 @@ export default {
285286
286287
const clientY = clientRect.y
287288
const compTop = windowH - droplistHeight - scrollHeight
288-
const marginRight = 15 // scrollbar width
289-
const left = droplistWidth + clientRect.left + window.pageXOffset > windowW ? windowW - droplistWidth - marginRight : clientRect.left + window.pageXOffset
289+
const marginRight = getScrollBarSize() + 5 // scrollbar width
290+
const left = droplistWidth + clientRect.left + marginRight + window.pageXOffset > windowW ? windowW - droplistWidth - marginRight : clientRect.left + window.pageXOffset
290291
const top = droplistHeight + clientHeight + clientY + scrollHeight > windowH ? compTop : defaultTop
291292
const zIndex = ZIndexManager.next()
293+
292294
return `
293295
position: absolute;
294296
top: ${top}px;

src/components/timepicker/index.css

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* c-timepicker
3+
*/
4+
@import url('../../styles/variables.css');
5+
6+
.c-timepicker {
7+
display: inline-block;
8+
position: relative;
9+
border-radius: 0.2em;
10+
width: 15em;
11+
12+
& .c-input-wrap {
13+
width: 100%;
14+
}
15+
16+
& input {
17+
margin: 0;
18+
width: 100%;
19+
}
20+
21+
& .c-timepicker__icon {
22+
position: absolute;
23+
right: 0.5em;
24+
top: 50%;
25+
transform: translateY(-50%);
26+
color: color(var(--text-color) l(65%));
27+
}
28+
29+
& .c-timepicker__hovericon {
30+
z-index: -1;
31+
opacity: 0;
32+
}
33+
34+
&:hover .c-timepicker__hovericon + .c-timepicker__icon {
35+
z-index: -1;
36+
opacity: 0;
37+
}
38+
39+
&:hover .c-timepicker__hovericon {
40+
z-index: 2;
41+
opacity: 1;
42+
}
43+
}
44+
45+
.c-timepicker__panel {
46+
display: flex;
47+
width: 12em;
48+
49+
& li {
50+
list-style: none;
51+
color: color(var(--text-color));
52+
-webkit-box-sizing: content-box;
53+
box-sizing: content-box;
54+
margin: 0;
55+
padding: 0 0 0 12px;
56+
width: 100%;
57+
height: 2em;
58+
line-height: 2em;
59+
text-align: left;
60+
cursor: pointer;
61+
}
62+
63+
& li.active {
64+
font-weight: bold;
65+
color: color(var(--text-color));
66+
background: color(var(--gray) l(95%));
67+
}
68+
}
69+
.c-timepicker__wrap {
70+
display: none;
71+
background: #fff;
72+
border: 1px solid #d4d9db;
73+
overflow: hidden;
74+
75+
& ul {
76+
list-style: none;
77+
width: 100%;
78+
-webkit-box-sizing: border-box;
79+
box-sizing: border-box;
80+
padding: 0 0 12em;
81+
text-align: center;
82+
margin: 0;
83+
}
84+
85+
& .c-timepicker__item {
86+
flex: 1;
87+
-webkit-box-sizing: border-box;
88+
box-sizing: border-box;
89+
overflow: hidden;
90+
position: relative;
91+
max-height: 14em;
92+
93+
&:hover {
94+
overflow-y: auto;
95+
}
96+
}
97+
98+
& .c-timepicker__item + .c-timepicker__item {
99+
border-left: 1px solid color(var(--gray) l(85%));
100+
}
101+
}
102+
.show {
103+
display: block;
104+
}

src/components/timepicker/index.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
title: Timepicker
3+
route: /component/timepicker
4+
layout: component
5+
---
6+
7+
# Timepicker
8+
9+
选择或者输入时间
10+
11+
## 基本用法
12+
13+
```html
14+
<c-timepicker
15+
v-model="time"
16+
:disabled="disabled"
17+
:defaultValue="defaultTime"
18+
@change="timeChange"
19+
></c-timepicker>
20+
21+
<script>
22+
export default {
23+
data () {
24+
return {
25+
disabled: false,
26+
time: '',
27+
defaultTime: '12:23:45'
28+
}
29+
},
30+
methods: {
31+
timeChange (time) {
32+
this.time = time
33+
console.log('time changed')
34+
}
35+
}
36+
}
37+
</script>
38+
```
39+
40+
## API
41+
42+
### 属性
43+
44+
| 属性 | 类型 | 默认值 | 说明 |
45+
|-----|------|-------|-----|
46+
| placeholder | String | 请选择时间 | 未进行选择时的提示 |
47+
| disabled | Boolean | false | 时间框是否被禁用 |
48+
| format | String | hh:mm:ss | 时间格式,如果使用12小时制,可设置'hh:mm:ss a' |
49+
| size | String | | 尺寸大小 |
50+
| defaultValue | moment | | 默认显示的时间 |

src/components/timepicker/index.vue

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
<template lang="pug">
2+
.c-timepicker(@click="openTimePanel")
3+
.c-timepicker__icon.c-timepicker__hovericon(:class="sizeClassName"
4+
v-if="!disabled")
5+
c-icon(name="x-circle")
6+
.c-timepicker__icon(:class="sizeClassName")
7+
c-icon(type="feather" name="clock")
8+
c-input(
9+
v-model="showValue"
10+
:placeholder="placeholder"
11+
:disabled="disabled"
12+
:size="size"
13+
@change="valueChange"
14+
)
15+
.c-timepicker__wrap(
16+
ref="timepickerPanel"
17+
:class="{show: isOpen}"
18+
)
19+
c-timepanel(
20+
:isShown="isOpen"
21+
:hour="hour"
22+
:minute="minute"
23+
:second="second"
24+
:defaultValue="defaultValue"
25+
@change="timeChange"
26+
)
27+
</template>
28+
29+
<script>
30+
import { VueTypes } from '@util'
31+
import './index.css'
32+
import { getScrollBarSize } from '@util'
33+
import ZIndexManager from '../../scripts/utils/zIndexManager.js'
34+
35+
export default {
36+
name: 'c-timepicker',
37+
props: {
38+
value: String,
39+
size: String,
40+
format: {
41+
type: String,
42+
default: 'hh:mm:ss'
43+
},
44+
disabled: Boolean,
45+
placeholder: {
46+
type: String,
47+
default: '请输入时间'
48+
},
49+
defaultValue: [String, Date]
50+
},
51+
data () {
52+
return {
53+
timepickerPanel: '',
54+
showValue: '',
55+
isOpen: false,
56+
hour: '',
57+
minute: '',
58+
second: '',
59+
lastValue: ''
60+
}
61+
},
62+
computed: {
63+
sizeClassName () {
64+
return this.size ? `is-size-${this.size}` : ''
65+
}
66+
},
67+
watch: {
68+
isOpen () {
69+
if (this.isOpen) {
70+
this.resize()
71+
this.lastValue = this.showValue
72+
window.addEventListener('mouseup', this.onBodyClick, true)
73+
} else {
74+
this.checkValue()
75+
window.removeEventListener('mouseup', this.onBodyClick, true)
76+
}
77+
},
78+
value (newVal) {
79+
if (newVal !== this.showValue) {
80+
this.showValue = newVal
81+
[this.hour, this.minute, this.second] = this.showValue ? this.showValue.split(':') : ['', '', '']
82+
}
83+
}
84+
},
85+
mounted () {
86+
this.showValue = this.value
87+
if (this.showValue) {
88+
[this.hour, this.minute, this.second] = this.showValue.split(':')
89+
}
90+
if (typeof document === 'object') {
91+
this.timepickerPanel = this.$el.querySelector('.c-timepicker__wrap')
92+
document.body.appendChild(this.timepickerPanel)
93+
this.resize()
94+
window.addEventListener('resize', this.resize, false)
95+
}
96+
},
97+
methods: {
98+
valueChange (value) {
99+
console.log(value)
100+
if (this.showValue) {
101+
[this.hour, this.minute, this.second] = this.showValue.split(':')
102+
} else {
103+
this.hour = ''
104+
this.minute = ''
105+
this.second = ''
106+
}
107+
},
108+
checkValue () {
109+
console.log('check')
110+
if (this.second > 59 || this.minute > 59 || this.hour > 23) {
111+
this.showValue = this.lastValue
112+
// [this.hour, this.minute, this.second] = this.lastValue.split(':')
113+
}
114+
},
115+
timeChange ({ hour, minute, second }) {
116+
this.hour = hour
117+
this.minute = minute
118+
this.second = second
119+
this.showValue = `${this.hour}:${this.minute}:${this.second}`
120+
},
121+
onBodyClick (e) {
122+
const isInPicker = this.$el.contains(e.target)
123+
const isInPanel = this.timepickerPanel.contains(e.target)
124+
if (!isInPicker && !isInPanel) {
125+
this.$emit('change', this.showValue)
126+
this.close()
127+
this.$el.focus()
128+
}
129+
},
130+
close () {
131+
this.isOpen = false
132+
},
133+
openTimePanel () {
134+
if (this.disabled) return
135+
this.isOpen = true
136+
console.log('open time')
137+
},
138+
getStyle () {
139+
const clientRect = this.$el.getBoundingClientRect()
140+
const windowH = window.innerHeight
141+
const windowW = window.innerWidth
142+
const marginTop = 2
143+
const scrollHeight = document.body.scrollWidth > window.innerWidth ? 20 : 0
144+
const droplistHeight = this.timepickerPanel.clientHeight
145+
const droplistWidth = this.timepickerPanel.clientWidth
146+
const defaultTop = clientRect.top + clientRect.height + marginTop + window.pageYOffset
147+
const clientHeight = clientRect.height + marginTop
148+
149+
const clientY = clientRect.y
150+
const compTop = windowH - droplistHeight - scrollHeight
151+
const marginRight = getScrollBarSize() + 5 // scrollbar width
152+
const left = droplistWidth + clientRect.left + marginRight + window.pageXOffset > windowW ? windowW - droplistWidth - marginRight : clientRect.left + window.pageXOffset
153+
const top = droplistHeight + clientHeight + clientY + scrollHeight > windowH ? compTop : defaultTop
154+
const zIndex = ZIndexManager.next()
155+
return `
156+
position: absolute;
157+
top: ${top}px;
158+
left: ${left}px;
159+
z-index: ${zIndex};
160+
`
161+
},
162+
resize () {
163+
this.$nextTick(() => {
164+
this.timepickerPanel.style.cssText = this.getStyle()
165+
})
166+
}
167+
}
168+
}
169+
</script>

0 commit comments

Comments
 (0)