teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

再勉強をかねてコードを書いてみた

2021/01/02 02:52

投稿

babu_babu_baboo
babu_babu_baboo

スコア616

answer CHANGED
@@ -3,4 +3,226 @@
3
3
  初期化も忘れずに。
4
4
  2.関数 showCalendar の呼び出す際の引数に DateObject を渡すようにしましょう
5
5
  3.テーブル要素には caption があります。その部分に<div class="month__items">の中を移しましょう
6
- 4.innerHTML を使わずに dom で挑戦しましょう
6
+ 4.innerHTML を使わずに dom で挑戦しましょう
7
+
8
+ なんとなく書いてみました。
9
+ ```js
10
+ <!DOCTYPE html>
11
+ <meta charset="utf-8">
12
+ <title></title>
13
+ <style>
14
+ table {
15
+ margin: 1em 0;
16
+ }
17
+ thead td {
18
+ font-weight: bold;
19
+ }
20
+ thead td, tbody td {
21
+ text-align: center;
22
+ border: 1px transparent solid;
23
+ }
24
+ tbody td:hover:not(.pDay):not(.nDay) {
25
+ border: 1px #f80 solid;
26
+ }
27
+ tr td:first-of-type {
28
+ color: red;
29
+ }
30
+ tr td:last-of-type {
31
+ color:#099;
32
+ }
33
+ thead td { padding: 0 .5ex;}
34
+ caption label {
35
+ padding: 0 .5ex;
36
+ font-size: large;
37
+ font-weight: bold;
38
+ }
39
+ caption button {
40
+ background: transparent;
41
+ border-style: none;
42
+ font-size: large;
43
+ padding: 0;
44
+ }
45
+ caption .hide {
46
+ display: none;
47
+ }
48
+ tbody td.pDay, tbody td.nDay {
49
+ color: silver;
50
+ font-size: small;
51
+ vertical-align: top;
52
+ }
53
+ tbody td.nDay {
54
+ color: silver;
55
+ font-size: small;
56
+ vertical-align: bottom;
57
+ }
58
+ </style>
59
+
60
+ <body>
61
+ <table></table>
62
+ <table></table>
63
+ <table></table>
64
+
65
+ <script>
66
+
67
+ class Calendar {
68
+
69
+ constructor (table, date, option = { }) {
70
+ this.table = table;
71
+ this.date = date;
72
+ this.option = Object.assign ({ }, this.constructor.defaultOption (), option);
73
+ this.view ();
74
+ }
75
+
76
+
77
+ view () {
78
+ const
79
+ {table, option, constructor: c } = this,
80
+ {remove, getYMD, setNo, splice, toTBody, append} = c.tools ();
81
+
82
+ let
83
+ tbody = document.createElement ('tbody'),
84
+ [y, m] = getYMD (this.current),//日付
85
+ [,, pd, pw] = getYMD (new Date (y, m, 0)),//先月末日
86
+ [,, nd, nw] = getYMD (new Date (y, m + 1, 0)),//今月末日
87
+ pn = (pw + 1) % 7,//先月の繰越す日数
88
+ nn = 6 - nw,//来月の取入れ日数
89
+ days = [
90
+ ...setNo (pn, pd - pn + 1),//連番(先月末)
91
+ ...setNo (nd),//連番(今月)
92
+ ...setNo (nn)//連番(翌月)
93
+ ];
94
+
95
+ remove (table.children);//子要素を削除
96
+ append (table.createCaption (), option.caption);//キャプションをDOMで展開
97
+ toTBody (table.createTHead (), option.weekName);//週名を展開
98
+ toTBody (table.appendChild (tbody), [...splice (days, 7)]);//7日で区切る
99
+
100
+ [...table.querySelectorAll ('caption label')]
101
+ .forEach ((e, i)=> e.textContent = [y, option.monthName[m]][i]);
102
+
103
+ let es = [...table.querySelectorAll ('tbody td')];
104
+ if (pn) es.slice (0, pn).forEach (e=> e.classList.add ('pDay'));
105
+ if (nn) es.slice (-nn).forEach (e=> e.classList.add ('nDay'));
106
+
107
+ return this;
108
+ }
109
+
110
+
111
+ offsetMonth (n = 0) {
112
+ this.current.setMonth (this.current.getMonth () + n);
113
+ this.view ();
114
+ return this;
115
+ }
116
+
117
+
118
+ set date (dt) {
119
+ const {getYMD} = this.constructor.tools ();
120
+ let [y, m] = getYMD (dt);
121
+ this.current = new Date (y, m, 1);
122
+ this._date = dt;
123
+ }
124
+
125
+
126
+ getDate (td) {
127
+ const {zp, getYMD} = this.constructor.tools ();
128
+ let
129
+ [y, m, _, w] = getYMD (this.current),
130
+ d = Number (td.textContent),
131
+ ymd = [y, m+1, d],
132
+ str = ymd.map ((a,b)=>zp(a,[4,2,2][b])).join ('-');
133
+ return [new Date (y, m, d), str, ...ymd, w];
134
+ }
135
+
136
+
137
+ event (td) {
138
+ if (td) {
139
+ let
140
+ cbFunc = this.option.cbFunc,
141
+ args = this.getDate (td);
142
+ if ('function' === typeof cbFunc)
143
+ cbFunc.apply (this, args);
144
+ if (this.option.clipboard)
145
+ navigator.clipboard.writeText (args[1]).then(()=> console.log (args));
146
+ }
147
+ }
148
+
149
+
150
+ handleEvent (event) {
151
+ let
152
+ e = event.target,
153
+ c = e.closest ('caption'),
154
+ n = e.nodeName;
155
+
156
+ if ('BUTTON' === n && c) {
157
+ let btNo = [...c.querySelectorAll('button')].indexOf (e);
158
+ return this.offsetMonth ([-12, -1, 1, 12][btNo]);
159
+ }
160
+ else if ('TD' === n && e.closest ('tbody'))
161
+ this.event (e);
162
+ }
163
+
164
+
165
+ static tools () {
166
+ return {
167
+ zp: (a,b=2)=>String(a).padStart(b,'0'),
168
+ remove: a=>[...a].map(a=>a.remove()),
169
+ getYMD: a=>['FullYear','Month','Date','Day'].map(b=>a['get'+b]()),
170
+ setNo: function*(a,b=1,c=1,d=0){for(;d<a;d+=c)yield b+d},
171
+ splice: function*(a,b=1){while(a.length)yield a.splice(0,b)},
172
+ append: ((f=(a,b,c,{tag:T,child:C,...O}=b)=>Array.isArray(b)?b.reduce((a,b)=>f(a,b),a):(Object.assign(a.appendChild(c=document.createElement(T)),O),C&&f(c,C),a))=>f)(),
173
+ toTBody: (a,ary)=>{
174
+ const
175
+ reg = /^(#?)(?:[(\d+)?(?:\,(\d+)?)?])?\s*(?:(.+)\s)*\s*(?:([+-]?(?:[1-9][0-9]{0,2}(?:\,?[0-9]{3})*)?(?:0?(?:.\d*))?)|(.+))?$/,
176
+ setAttr = (a,b,O=Object)=>O.assign(a,O.fromEntries(O.entries(b).filter(c=>'undefined'!==typeof c[1])));
177
+
178
+ for (let row of ary) {
179
+ let tr = a.insertRow ();
180
+ for (let cell of row) {
181
+ let
182
+ [,thd, colSpan, rowSpan, className, num, text] = reg.exec (cell),
183
+ td = tr.appendChild (document.createElement (thd ? 'th': 'td')),
184
+ attr = {colSpan, rowSpan, className, textContent: text || num || ''};
185
+ setAttr (td, attr);
186
+ tr.appendChild (td);
187
+ }
188
+ }
189
+ }
190
+ };
191
+ }
192
+
193
+
194
+ static defaultOption () {
195
+ return {
196
+ weekName: [['Sun','Mon','Tue','Wed','Thu','Fri','Sat']],
197
+ monthName: ['January','February','March','April','May','June','July','August','September','October','November','December'],
198
+ caption: [
199
+ { tag: 'button', type: 'button', textContent: '⏪', className: 'hide' },
200
+ { tag: 'button', type: 'button', textContent: '<' },
201
+ { tag: 'label', className: 'hide' },
202
+ { tag: 'label'},
203
+ { tag: 'button', type: 'button', textContent: '>'},
204
+ { tag: 'button', type: 'button', textContent: '⏩', className: 'hide' }
205
+ ],
206
+ cbFunc: null,
207
+ clipboard: true,
208
+ };
209
+ }
210
+
211
+
212
+ static create (table = document.createElement ('table'), date = new Date, option = { }) {
213
+ const calendar = new this (table, date, option);
214
+ table.addEventListener ('click', calendar, false);
215
+ return calendar;
216
+ }
217
+ }
218
+
219
+
220
+ const
221
+ TABLE = document.querySelectorAll ('table'),
222
+ [a, b, c] = Array.from (TABLE, t=> Calendar.create (t));
223
+
224
+ b.offsetMonth (+1);
225
+ c.offsetMonth (+2);
226
+
227
+ </script>
228
+ ```