Commit 50637863ce7fae40ec0298fe02e5fb1ec46668ba

Authored by 梁灏
1 parent d3eee3f4

update DatePicker

update DatePicker
src/components/date-picker/base/date-table.vue
1 1 <template>
2   - <table
3   - cellspacing="0"
4   - cellpadding="0"
  2 + <div
5 3 :class="classes"
6 4 @click="handleClick"
7 5 @mousemove="handleMouseMove">
8   - <tbody>
9   - <tr>
10   - <th v-if="showWeekNumber"></th>
11   - <th>日</th>
12   - <th>一</th>
13   - <th>二</th>
14   - <th>三</th>
15   - <th>四</th>
16   - <th>五</th>
17   - <th>六</th>
18   - </tr>
19   - <tr :class="rowCls(row[1])" v-for="row in rows">
20   - <td :class="getCellClasses(cell)" v-for="cell in row">{{ cell.text }}</td>
21   - </tr>
22   - </tbody>
23   - </table>
  6 + <div :class="[prefixCls + '-header']">
  7 + <span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>
  8 + </div>
  9 + <span :class="getCellCls(cell)" v-for="cell in cells"><em>{{ cell.text }}</em></span>
  10 + </div>
24 11 </template>
25 12 <script>
26   - const prefixCls = 'ivu-date-picker-table';
  13 + import { getFirstDayOfMonth, getDayCountOfMonth, getStartDateOfMonth } from '../util';
  14 + import { deepCopy } from '../../../utils/assist';
  15 +
  16 + const prefixCls = 'ivu-date-picker-cells';
  17 +
  18 + const clearHours = function (time) {
  19 + const cloneDate = new Date(time);
  20 + cloneDate.setHours(0, 0, 0, 0);
  21 + return cloneDate.getTime();
  22 + };
27 23  
28 24 export default {
29 25 props: {
30 26 date: {},
31 27 year: {},
32 28 month: {},
33   - week: {},
34 29 selectionMode: {
35 30 default: 'day'
36 31 },
37   - showWeekNumber: {
38   - type: Boolean,
39   - default: false
40   - },
41 32 disabledDate: {},
42 33 minDate: {},
43 34 maxDate: {},
... ... @@ -51,7 +42,7 @@
51 42 };
52 43 }
53 44 },
54   - value: {}
  45 + value: ''
55 46 },
56 47 data () {
57 48 return {
... ... @@ -61,11 +52,77 @@
61 52 computed: {
62 53 classes () {
63 54 return [
64   - `${prefixCls}`,
65   - {
66   - [`${prefixCls}-week-mode`]: this.selectionMode === 'week'
67   - }
  55 + `${prefixCls}`
68 56 ]
  57 + },
  58 + startDate() {
  59 + return getStartDateOfMonth(this.year, this.month);
  60 + },
  61 + cells () {
  62 + const date = new Date(this.year, this.month, 1);
  63 + let day = getFirstDayOfMonth(date); // day of first day
  64 + day = (day === 0 ? 7 : day);
  65 + const today = clearHours(new Date()); // timestamp of today
  66 + const selectDay = clearHours(new Date(this.value)); // timestamp of selected day
  67 +
  68 + const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth());
  69 + const dateCountOfLastMonth = getDayCountOfMonth(date.getFullYear(), (date.getMonth() === 0 ? 11 : date.getMonth() - 1));
  70 +
  71 + const disabledDate = this.disabledDate;
  72 +
  73 + let cells = [];
  74 + const cell_tmpl = {
  75 + text: '',
  76 + type: '',
  77 + selected: false,
  78 + disabled: false
  79 + };
  80 + if (day !== 7) {
  81 + for (let i = 0; i < day; i++) {
  82 + const cell = deepCopy(cell_tmpl);
  83 + cell.type = 'prev-month';
  84 + cell.text = dateCountOfLastMonth - (day - 1) + i;
  85 +
  86 + let prevMonth = this.month - 1;
  87 + let prevYear = this.year;
  88 + if (this.month === 0) {
  89 + prevMonth = 11;
  90 + prevYear -= 1;
  91 + }
  92 + const time = clearHours(new Date(prevYear, prevMonth, cell.text));
  93 + cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
  94 + cells.push(cell);
  95 + }
  96 + }
  97 +
  98 + for (let i = 1; i <= dateCountOfMonth; i++) {
  99 + const cell = deepCopy(cell_tmpl);
  100 + const time = clearHours(new Date(this.year, this.month, i));
  101 + cell.type = time === today ? 'today' : 'normal';
  102 + cell.text = i;
  103 + cell.selected = time === selectDay;
  104 + cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
  105 + cells.push(cell);
  106 + }
  107 +
  108 + const nextMonthCount = 42 - cells.length;
  109 + for (let i = 1; i <= nextMonthCount; i++) {
  110 + const cell = deepCopy(cell_tmpl);
  111 + cell.type = 'next-month';
  112 + cell.text = i;
  113 +
  114 + let nextMonth = this.month + 1;
  115 + let nextYear = this.year;
  116 + if (this.month === 11) {
  117 + nextMonth = 0;
  118 + nextYear += 1;
  119 + }
  120 + const time = clearHours(new Date(nextYear, nextMonth, cell.text));
  121 + cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(time));
  122 + cells.push(cell);
  123 + }
  124 +
  125 + return cells;
69 126 }
70 127 },
71 128 methods: {
... ... @@ -75,25 +132,19 @@
75 132 handleMouseMove () {
76 133  
77 134 },
78   - rowCls (cell) {
79   - return [
80   - `${prefixCls}-row`,
81   - {
82   - [`${prefixCls}-row-current`]: this.value && this.isWeekActive(cell)
83   - }
84   - ]
85   - },
86   - isWeekActive (cell) {
87   -
88   - },
89 135 getCellCls (cell) {
90 136 return [
91 137 `${prefixCls}-cell`,
92 138 {
93   - [`${prefixCls}-cell-today`]: cell.type === 'today'
  139 + [`${prefixCls}-cell-selected`]: cell.selected,
  140 + [`${prefixCls}-cell-disabled`]: cell.disabled,
  141 + [`${prefixCls}-cell-today`]: cell.type === 'today',
  142 + [`${prefixCls}-cell-prev-month`]: cell.type === 'prev-month',
  143 + [`${prefixCls}-cell-next-month`]: cell.type === 'next-month'
94 144 }
95 145 ]
96   - }
  146 + },
  147 +
97 148 }
98 149 }
99 150 </script>
100 151 \ No newline at end of file
... ...
src/components/date-picker/panel/date.vue
... ... @@ -32,7 +32,14 @@
32 32 </div>
33 33 <div :class="[prefixCls + '-content']">
34 34 <date-table
35   - v-show="currentView === 'date'"></date-table>
  35 + v-show="currentView === 'date'"
  36 + :year="year"
  37 + :month="month"
  38 + :date="date"
  39 + :value="value"
  40 + :week="week"
  41 + :selection-mode="selectionMode"
  42 + :disabled-date="disabledDate"></date-table>
36 43 <year-table
37 44 v-show="currentView === 'year'"></year-table>
38 45 <month-table
... ... @@ -56,10 +63,37 @@
56 63 prefixCls: prefixCls,
57 64 datePrefixCls: datePrefixCls,
58 65 shortcuts: [],
59   - currentView: 'date'
  66 + currentView: 'date',
  67 + date: new Date(),
  68 + value: '',
  69 + showTime: false,
  70 + selectionMode: 'day',
  71 + visible: false,
  72 + disabledDate: '',
  73 + year: null,
  74 + month: null,
  75 + week: null,
  76 + showWeekNumber: false,
  77 + timePickerVisible: false
  78 + }
  79 + },
  80 + computed: {
  81 +
  82 + },
  83 + watch: {
  84 + value (newVal) {
  85 + newVal = new Date(newVal);
  86 + if (!isNaN(newVal)) {
  87 + // todo
  88 +// if (typeof this.disabledDate === 'function' && this.disabledDate(new Date(newVal))) return;
  89 +
  90 + this.date = newVal;
  91 + this.year = newVal.getFullYear();
  92 + this.month = newVal.getMonth();
  93 +// this.$emit('on-pick', newVal, true);
  94 + }
60 95 }
61 96 },
62   - computed: {},
63 97 methods: {
64 98 handleShortcutClick (shortcut) {
65 99  
... ... @@ -90,11 +124,18 @@
90 124  
91 125 }
92 126 },
93   - ready () {
94   - console.log(123)
  127 + compiled () {
  128 + if (this.selectionMode === 'month') {
  129 + this.currentView = 'month';
  130 + }
  131 +
  132 + if (this.date && !this.year) {
  133 + this.year = this.date.getFullYear();
  134 + this.month = this.date.getMonth();
  135 + }
95 136 },
96 137 beforeDestroy () {
97   - console.log(456)
  138 +
98 139 }
99 140 }
100 141 </script>
101 142 \ No newline at end of file
... ...
src/components/date-picker/picker.vue
... ... @@ -27,6 +27,7 @@
27 27 import Drop from '../../components/select/dropdown.vue';
28 28 import clickoutside from '../../directives/clickoutside';
29 29 import { oneOf } from '../../utils/assist';
  30 + import { formatDate } from './util';
30 31  
31 32 const prefixCls = 'ivu-date-picker';
32 33  
... ... @@ -90,7 +91,8 @@
90 91 showClose: false,
91 92 visualValue: '',
92 93 visible: false,
93   - picker: null
  94 + picker: null,
  95 + internalValue: ''
94 96 }
95 97 },
96 98 computed: {
... ... @@ -126,6 +128,13 @@
126 128 showPicker () {
127 129 if (!this.picker) {
128 130 this.picker = new Vue(this.panel).$mount(this.$els.picker);
  131 + this.picker.value = this.internalValue;
  132 + if (this.format) this.picker.format = this.format;
  133 +
  134 + const options = this.options;
  135 + for (const option in options) {
  136 + this.picker[option] = options[option];
  137 + }
129 138 }
130 139 }
131 140 },
... ... @@ -137,6 +146,12 @@
137 146 } else {
138 147 this.$refs.drop.destroy();
139 148 }
  149 + },
  150 + value: {
  151 + immediate: true,
  152 + handler (val) {
  153 + this.internalValue = formatDate(val);
  154 + }
140 155 }
141 156 },
142 157 beforeDestroy () {
... ...
src/components/date-picker/picker/date-picker.js
... ... @@ -19,9 +19,20 @@ export default {
19 19 return oneOf(value, ['year', 'month', 'week', 'date', 'daterange', 'datetime', 'datetimerange']);
20 20 },
21 21 default: 'date'
  22 + },
  23 + value: {
  24 + type: [String, Array]
22 25 }
23 26 },
24   - created() {
  27 + created () {
  28 + if (!this.value) {
  29 + if (this.type === 'daterange' || this.type === 'datetimerange') {
  30 + this.value = ['',''];
  31 + } else {
  32 + this.value = '';
  33 + }
  34 + }
  35 +
25 36 this.panel = getPanel(this.type);
26 37 }
27 38 }
28 39 \ No newline at end of file
... ...
src/styles/components/date-picker.less 0 → 100644
  1 +@date-picker-prefix-cls: ~"@{css-prefix}date-picker";
  2 +
  3 +.@{date-picker-prefix-cls} {
  4 + position: relative;
  5 + .@{select-dropdown-prefix-cls} {
  6 + width: auto;
  7 + overflow: visible;
  8 + max-height: none;
  9 + }
  10 + &-cells{
  11 + width: 196px;
  12 + margin: 10px;
  13 + span{
  14 + display: inline-block;
  15 + width: 24px;
  16 + height: 24px;
  17 +
  18 + em{
  19 + display: inline-block;
  20 + width: 24px;
  21 + height: 24px;
  22 + line-height: 24px;
  23 + margin: 2px;
  24 + font-style: normal;
  25 + border-radius: @btn-border-radius-small;
  26 + text-align: center;
  27 + transition: all @transition-time @ease-in-out;
  28 + }
  29 + }
  30 + &-header span{
  31 + line-height: 24px;
  32 + text-align: center;
  33 + margin: 2px;
  34 + color: @btn-disable-color;
  35 + }
  36 + &-cell{
  37 + span&{
  38 + width: 28px;
  39 + height: 28px;
  40 + cursor: pointer;
  41 + }
  42 + &:hover{
  43 + em{
  44 + background: @date-picker-cell-hover-bg;
  45 + }
  46 + }
  47 + &-prev-month,&-next-month{
  48 + em{
  49 + color: @btn-disable-color;
  50 + }
  51 + &:hover{
  52 + em{
  53 + background: transparent;
  54 + }
  55 + }
  56 + }
  57 + span&-disabled,span&-disabled:hover{
  58 + cursor: @cursor-disabled;
  59 + background: @btn-disable-bg;
  60 + color: @btn-disable-color;
  61 + em{
  62 + color: inherit;
  63 + background: inherit;
  64 + }
  65 + }
  66 + &-today{
  67 + em {
  68 + position: relative;
  69 + &:after{
  70 + content: '';
  71 + display: block;
  72 + width: 6px;
  73 + height: 6px;
  74 + border-radius: 50%;
  75 + background: @primary-color;
  76 + position: absolute;
  77 + top: 1px;
  78 + right: 1px;
  79 + }
  80 + }
  81 + }
  82 + &-selected,&-selected:hover {
  83 + em{
  84 + background: @primary-color;
  85 + color: #fff;
  86 + }
  87 + }
  88 + span&-disabled&-selected{
  89 + em {
  90 + background: @btn-disable-color;
  91 + color: @btn-disable-bg;
  92 + }
  93 + }
  94 + &-today&-selected{
  95 + em{
  96 + &:after{
  97 + background: #fff;
  98 + }
  99 + }
  100 + }
  101 + }
  102 + }
  103 +}
0 104 \ No newline at end of file
... ...
src/styles/components/index.less
... ... @@ -31,4 +31,5 @@
31 31 @import "table";
32 32 @import "dropdown";
33 33 @import "tabs";
34   -@import "menu";
35 34 \ No newline at end of file
  35 +@import "menu";
  36 +@import "date-picker";
36 37 \ No newline at end of file
... ...
src/styles/themes/default/custom.less
... ... @@ -43,6 +43,7 @@
43 43 @table-td-hover-bg : #ebf7ff;
44 44 @table-td-highlight-bg : #ebf7ff;
45 45 @menu-dark-active-bg : #313540;
  46 +@date-picker-cell-hover-bg : #e1f0fe;
46 47  
47 48 // Shadow
48 49 @shadow-color : rgba(0, 0, 0, .2);
... ...
test/routers/date.vue
1 1 <template>
2 2 <div style="margin: 50px">
3   - <date-picker style="width:200px" placeholder="请选择日期"></date-picker>
  3 + <date-picker style="width:200px" placeholder="请选择日期" :value.sync="value" :options="options"></date-picker>
4 4 </div>
5 5 </template>
6 6 <script>
7 7 export default {
8   - props: {},
9 8 data () {
10   - return {}
  9 + return {
  10 + value: '2016-12-18',
  11 +// value: '',
  12 + options: {
  13 + disabledDate(time) {
  14 + return time.getTime() < Date.now() - 8.64e7;
  15 +// return time && time.valueOf() < Date.now();
  16 + }
  17 + }
  18 + }
11 19 },
12 20 computed: {},
13 21 methods: {}
... ...
test/routers/table.vue
1 1 <template>
2   - <i-table width="550" border :columns="columns2" :data="data3"></i-table>
  2 + <i-button @click="changeFilter">改变filter</i-button>
  3 + <i-table border :columns="columns6" :data="data5"></i-table>
3 4 </template>
4 5 <script>
5 6 export default {
6 7 data () {
7 8 return {
8   - columns2: [
  9 + columns6: [
  10 + {
  11 + title: '日期',
  12 + key: 'date'
  13 + },
9 14 {
10 15 title: '姓名',
11   - key: 'name',
12   - width: 100,
13   - fixed: 'left'
  16 + key: 'name'
14 17 },
15 18 {
16 19 title: '年龄',
17 20 key: 'age',
18   - width: 100
19   - },
20   - {
21   - title: '省份',
22   - key: 'province',
23   - width: 100
24   - },
25   - {
26   - title: '市区',
27   - key: 'city',
28   - width: 100
  21 + filters: [
  22 + {
  23 + label: '大于25岁',
  24 + value: 1
  25 + },
  26 + {
  27 + label: '小于25岁',
  28 + value: 2
  29 + }
  30 + ],
  31 + filterMultiple: false,
  32 + filterMethod (value, row) {
  33 + if (value === 1) {
  34 + return row.age > 25;
  35 + } else if (value === 2) {
  36 + return row.age < 25;
  37 + }
  38 + }
29 39 },
30 40 {
31 41 title: '地址',
32 42 key: 'address',
33   - width: 200
34   - },
35   - {
36   - title: '邮编',
37   - key: 'zip',
38   - width: 100
39   - },
40   - {
41   - title: '操作',
42   - key: 'action',
43   - fixed: 'right',
44   - width: 120,
45   - render () {
46   - return `<i-button type="text" size="small">查看</i-button><i-button type="text" size="small">编辑</i-button>`;
  43 + filters: [
  44 + {
  45 + label: '北京',
  46 + value: '北京'
  47 + },
  48 + {
  49 + label: '上海',
  50 + value: '上海'
  51 + },
  52 + {
  53 + label: '深圳',
  54 + value: '深圳'
  55 + }
  56 + ],
  57 + filterMethod (value, row) {
  58 + return row.address.indexOf(value) > -1;
47 59 }
48 60 }
49 61 ],
50   - data3: [
  62 + data5: [
51 63 {
52 64 name: '王小明',
53 65 age: 18,
54 66 address: '北京市朝阳区芍药居',
55   - province: '北京市',
56   - city: '朝阳区',
57   - zip: 100000
  67 + date: '2016-10-03'
58 68 },
59 69 {
60 70 name: '张小刚',
61 71 age: 25,
62 72 address: '北京市海淀区西二旗',
63   - province: '北京市',
64   - city: '海淀区',
65   - zip: 100000
  73 + date: '2016-10-01'
66 74 },
67 75 {
68 76 name: '李小红',
69 77 age: 30,
70 78 address: '上海市浦东新区世纪大道',
71   - province: '上海市',
72   - city: '浦东新区',
73   - zip: 100000
  79 + date: '2016-10-02'
74 80 },
75 81 {
76 82 name: '周小伟',
77 83 age: 26,
78 84 address: '深圳市南山区深南大道',
79   - province: '广东',
80   - city: '南山区',
81   - zip: 100000
  85 + date: '2016-10-04'
  86 + }
  87 + ]
  88 + }
  89 + },
  90 + methods: {
  91 + changeFilter () {
  92 + this.columns6[2].filters = [
  93 + {
  94 + label: '小于25岁',
  95 + value: 2
82 96 }
83 97 ]
84 98 }
... ...