回答編集履歴

1

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

2021/01/02 02:52

投稿

babu_babu_baboo
babu_babu_baboo

スコア616

test CHANGED
@@ -9,3 +9,447 @@
9
9
  3.テーブル要素には caption があります。その部分に<div class="month__items">の中を移しましょう
10
10
 
11
11
  4.innerHTML を使わずに dom で挑戦しましょう
12
+
13
+
14
+
15
+ なんとなく書いてみました。
16
+
17
+ ```js
18
+
19
+ <!DOCTYPE html>
20
+
21
+ <meta charset="utf-8">
22
+
23
+ <title></title>
24
+
25
+ <style>
26
+
27
+ table {
28
+
29
+ margin: 1em 0;
30
+
31
+ }
32
+
33
+ thead td {
34
+
35
+ font-weight: bold;
36
+
37
+ }
38
+
39
+ thead td, tbody td {
40
+
41
+ text-align: center;
42
+
43
+ border: 1px transparent solid;
44
+
45
+ }
46
+
47
+ tbody td:hover:not(.pDay):not(.nDay) {
48
+
49
+ border: 1px #f80 solid;
50
+
51
+ }
52
+
53
+ tr td:first-of-type {
54
+
55
+ color: red;
56
+
57
+ }
58
+
59
+ tr td:last-of-type {
60
+
61
+ color:#099;
62
+
63
+ }
64
+
65
+ thead td { padding: 0 .5ex;}
66
+
67
+ caption label {
68
+
69
+ padding: 0 .5ex;
70
+
71
+ font-size: large;
72
+
73
+ font-weight: bold;
74
+
75
+ }
76
+
77
+ caption button {
78
+
79
+ background: transparent;
80
+
81
+ border-style: none;
82
+
83
+ font-size: large;
84
+
85
+ padding: 0;
86
+
87
+ }
88
+
89
+ caption .hide {
90
+
91
+ display: none;
92
+
93
+ }
94
+
95
+ tbody td.pDay, tbody td.nDay {
96
+
97
+ color: silver;
98
+
99
+ font-size: small;
100
+
101
+ vertical-align: top;
102
+
103
+ }
104
+
105
+ tbody td.nDay {
106
+
107
+ color: silver;
108
+
109
+ font-size: small;
110
+
111
+ vertical-align: bottom;
112
+
113
+ }
114
+
115
+ </style>
116
+
117
+
118
+
119
+ <body>
120
+
121
+ <table></table>
122
+
123
+ <table></table>
124
+
125
+ <table></table>
126
+
127
+
128
+
129
+ <script>
130
+
131
+
132
+
133
+ class Calendar {
134
+
135
+
136
+
137
+ constructor (table, date, option = { }) {
138
+
139
+ this.table = table;
140
+
141
+ this.date = date;
142
+
143
+ this.option = Object.assign ({ }, this.constructor.defaultOption (), option);
144
+
145
+ this.view ();
146
+
147
+ }
148
+
149
+
150
+
151
+
152
+
153
+ view () {
154
+
155
+ const
156
+
157
+ {table, option, constructor: c } = this,
158
+
159
+ {remove, getYMD, setNo, splice, toTBody, append} = c.tools ();
160
+
161
+
162
+
163
+ let
164
+
165
+ tbody = document.createElement ('tbody'),
166
+
167
+ [y, m] = getYMD (this.current),//日付
168
+
169
+ [,, pd, pw] = getYMD (new Date (y, m, 0)),//先月末日
170
+
171
+ [,, nd, nw] = getYMD (new Date (y, m + 1, 0)),//今月末日
172
+
173
+ pn = (pw + 1) % 7,//先月の繰越す日数
174
+
175
+ nn = 6 - nw,//来月の取入れ日数
176
+
177
+ days = [
178
+
179
+ ...setNo (pn, pd - pn + 1),//連番(先月末)
180
+
181
+ ...setNo (nd),//連番(今月)
182
+
183
+ ...setNo (nn)//連番(翌月)
184
+
185
+ ];
186
+
187
+
188
+
189
+ remove (table.children);//子要素を削除
190
+
191
+ append (table.createCaption (), option.caption);//キャプションをDOMで展開
192
+
193
+ toTBody (table.createTHead (), option.weekName);//週名を展開
194
+
195
+ toTBody (table.appendChild (tbody), [...splice (days, 7)]);//7日で区切る
196
+
197
+
198
+
199
+ [...table.querySelectorAll ('caption label')]
200
+
201
+ .forEach ((e, i)=> e.textContent = [y, option.monthName[m]][i]);
202
+
203
+
204
+
205
+ let es = [...table.querySelectorAll ('tbody td')];
206
+
207
+ if (pn) es.slice (0, pn).forEach (e=> e.classList.add ('pDay'));
208
+
209
+ if (nn) es.slice (-nn).forEach (e=> e.classList.add ('nDay'));
210
+
211
+
212
+
213
+ return this;
214
+
215
+ }
216
+
217
+
218
+
219
+
220
+
221
+ offsetMonth (n = 0) {
222
+
223
+ this.current.setMonth (this.current.getMonth () + n);
224
+
225
+ this.view ();
226
+
227
+ return this;
228
+
229
+ }
230
+
231
+
232
+
233
+
234
+
235
+ set date (dt) {
236
+
237
+ const {getYMD} = this.constructor.tools ();
238
+
239
+ let [y, m] = getYMD (dt);
240
+
241
+ this.current = new Date (y, m, 1);
242
+
243
+ this._date = dt;
244
+
245
+ }
246
+
247
+
248
+
249
+
250
+
251
+ getDate (td) {
252
+
253
+ const {zp, getYMD} = this.constructor.tools ();
254
+
255
+ let
256
+
257
+ [y, m, _, w] = getYMD (this.current),
258
+
259
+ d = Number (td.textContent),
260
+
261
+ ymd = [y, m+1, d],
262
+
263
+ str = ymd.map ((a,b)=>zp(a,[4,2,2][b])).join ('-');
264
+
265
+ return [new Date (y, m, d), str, ...ymd, w];
266
+
267
+ }
268
+
269
+
270
+
271
+
272
+
273
+ event (td) {
274
+
275
+ if (td) {
276
+
277
+ let
278
+
279
+ cbFunc = this.option.cbFunc,
280
+
281
+ args = this.getDate (td);
282
+
283
+ if ('function' === typeof cbFunc)
284
+
285
+ cbFunc.apply (this, args);
286
+
287
+ if (this.option.clipboard)
288
+
289
+ navigator.clipboard.writeText (args[1]).then(()=> console.log (args));
290
+
291
+ }
292
+
293
+ }
294
+
295
+
296
+
297
+
298
+
299
+ handleEvent (event) {
300
+
301
+ let
302
+
303
+ e = event.target,
304
+
305
+ c = e.closest ('caption'),
306
+
307
+ n = e.nodeName;
308
+
309
+
310
+
311
+ if ('BUTTON' === n && c) {
312
+
313
+ let btNo = [...c.querySelectorAll('button')].indexOf (e);
314
+
315
+ return this.offsetMonth ([-12, -1, 1, 12][btNo]);
316
+
317
+ }
318
+
319
+ else if ('TD' === n && e.closest ('tbody'))
320
+
321
+ this.event (e);
322
+
323
+ }
324
+
325
+
326
+
327
+
328
+
329
+ static tools () {
330
+
331
+ return {
332
+
333
+ zp: (a,b=2)=>String(a).padStart(b,'0'),
334
+
335
+ remove: a=>[...a].map(a=>a.remove()),
336
+
337
+ getYMD: a=>['FullYear','Month','Date','Day'].map(b=>a['get'+b]()),
338
+
339
+ setNo: function*(a,b=1,c=1,d=0){for(;d<a;d+=c)yield b+d},
340
+
341
+ splice: function*(a,b=1){while(a.length)yield a.splice(0,b)},
342
+
343
+ 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)(),
344
+
345
+ toTBody: (a,ary)=>{
346
+
347
+ const
348
+
349
+ reg = /^(#?)(?:[(\d+)?(?:\,(\d+)?)?])?\s*(?:(.+)\s)*\s*(?:([+-]?(?:[1-9][0-9]{0,2}(?:\,?[0-9]{3})*)?(?:0?(?:.\d*))?)|(.+))?$/,
350
+
351
+ setAttr = (a,b,O=Object)=>O.assign(a,O.fromEntries(O.entries(b).filter(c=>'undefined'!==typeof c[1])));
352
+
353
+
354
+
355
+ for (let row of ary) {
356
+
357
+ let tr = a.insertRow ();
358
+
359
+ for (let cell of row) {
360
+
361
+ let
362
+
363
+ [,thd, colSpan, rowSpan, className, num, text] = reg.exec (cell),
364
+
365
+ td = tr.appendChild (document.createElement (thd ? 'th': 'td')),
366
+
367
+ attr = {colSpan, rowSpan, className, textContent: text || num || ''};
368
+
369
+ setAttr (td, attr);
370
+
371
+ tr.appendChild (td);
372
+
373
+ }
374
+
375
+ }
376
+
377
+ }
378
+
379
+ };
380
+
381
+ }
382
+
383
+
384
+
385
+
386
+
387
+ static defaultOption () {
388
+
389
+ return {
390
+
391
+ weekName: [['Sun','Mon','Tue','Wed','Thu','Fri','Sat']],
392
+
393
+ monthName: ['January','February','March','April','May','June','July','August','September','October','November','December'],
394
+
395
+ caption: [
396
+
397
+ { tag: 'button', type: 'button', textContent: '⏪', className: 'hide' },
398
+
399
+ { tag: 'button', type: 'button', textContent: '<' },
400
+
401
+ { tag: 'label', className: 'hide' },
402
+
403
+ { tag: 'label'},
404
+
405
+ { tag: 'button', type: 'button', textContent: '>'},
406
+
407
+ { tag: 'button', type: 'button', textContent: '⏩', className: 'hide' }
408
+
409
+ ],
410
+
411
+ cbFunc: null,
412
+
413
+ clipboard: true,
414
+
415
+ };
416
+
417
+ }
418
+
419
+
420
+
421
+
422
+
423
+ static create (table = document.createElement ('table'), date = new Date, option = { }) {
424
+
425
+ const calendar = new this (table, date, option);
426
+
427
+ table.addEventListener ('click', calendar, false);
428
+
429
+ return calendar;
430
+
431
+ }
432
+
433
+ }
434
+
435
+
436
+
437
+
438
+
439
+ const
440
+
441
+ TABLE = document.querySelectorAll ('table'),
442
+
443
+ [a, b, c] = Array.from (TABLE, t=> Calendar.create (t));
444
+
445
+
446
+
447
+ b.offsetMonth (+1);
448
+
449
+ c.offsetMonth (+2);
450
+
451
+
452
+
453
+ </script>
454
+
455
+ ```