ソート付き表《完成》添削してください\r\n
\r\n```\r\n```css\r\n*{\r\n margin:0;\r\n padding:0;\r\n box-sizing: border-box;\r\n}\r\n.tbl {\r\n border-collapse: collapse;\r\n margin:20px auto;\r\n font-family: Verdana, Geneva, Tahoma, sans-serif;\r\n font-size: 16px;\r\n & td,& th {\r\n width:180px;\r\n height: 36px;\r\n padding:5px 20px;\r\n border:1px solid #E9EAE8;\r\n }\r\n & thead {\r\n cursor: pointer;\r\n & th::after {\r\n content: '\\f0dc';\r\n font-family:'FontAwesome';\r\n font-size: 12px;\r\n color: #ccc;\r\n float: right;\r\n padding-top: 4px;\r\n font-weight: normal;\r\n }\r\n & th.decend::after {\r\n content: '\\f0dd';\r\n color: #000;\r\n }\r\n & th.ascend::after {\r\n content: '\\f0de';\r\n color: #000;\r\n }\r\n }\r\n & tbody tr td:last-child {\r\n text-align: right;\r\n }\r\n & tbody tr:nth-child(2n) {\r\n background-color: #f8f8f8;\r\n }\r\n \r\n}\r\n\r\n```","answerCount":2,"upvoteCount":0,"datePublished":"2020-05-25T02:18:48.620Z","dateModified":"2020-05-25T02:18:48.620Z","acceptedAnswer":{"@type":"Answer","text":"コメントに書き入れました。\r\nオブジェクト指向が意味をなしていないと思いました。\r\n\r\n追記\r\ndocument.createElement('thead');\r\nは、複数個登録できない。事前にチェックが必要\r\n1回しか使わないからいいのでは?と思うかもしれないけれど\r\nそれならば class で書く必要がないのでは? といわれてしまう。\r\n\r\n```javascript\r\n\r\nlet tbl_sort;//使われてない\r\n//以下4つは、グローバス変数として使わなくてもできる!\r\nlet col;\r\nlet _a;\r\nlet _b;\r\nlet cf;\r\n\r\nfunction doSort(/* cf これで呼び出してみては? */){\r\n\r\n const ths =document.querySelectorAll('th');//テーブル要素が複数あることを想定していない\r\n ths.forEach((th,index) =>{\r\n if (index !== col){\r\n th.className = '';//これは空白で複数していできることを否定している\r\n }\r\n })\r\n tbl_dat.sort((a, b)=> {\r\n if(isNaN( a[col])){\r\n _a = a[col].toLocaleLowerCase();\r\n _b = b[col].toLocaleLowerCase();\r\n } else {\r\n _a = Number(a[col]);\r\n _b = Number(b[col]);\r\n }\r\n\r\n if (_a > _b){\r\n return 1*cf\r\n } else if (_a < _b){\r\n return -1*cf\r\n } else {\r\n return 0\r\n }\r\n })\r\n\r\nconst tbody=document.querySelector('tbody');//これも複数のテーブルを考慮していない\r\ntbody.remove();\r\n\r\n const date = new SetDate(tbl_dat);//なんのために data に保存する?\r\n}\r\n\r\n\r\nclass SetHead {\r\n constructor(els){//els の型のチェックがされていない\r\n const table = document.querySelector('table');//これも複数のテーブルを考慮していない\r\n const thead = document.createElement('thead');// table.createTHead を使う\r\n const tr=document.createElement('tr');// tbody.inserRow を使えばあとの appendChild が不要\r\n\r\n for(let i=0;i{ //個人的には、イベントの管理は document で行う。\r\n col=th.cellIndex;\r\n\r\n if(th.classList.contains('ascend')){\r\n th.className='decend';//ここでも複数の指定を破壊している\r\n cf=-1;//event.shiftKey を使えば、逆ソートもできるんじゃね?\r\n }else {\r\n th.className='ascend';\r\n cf=1;\r\n }\r\n doSort();//\r\n\r\n })\r\n tr.appendChild(th);//上で指摘したものを使えば不要\r\n }\r\n thead.appendChild(tr);//上で指摘したものを使えば不要\r\n table.appendChild(thead);//上で指摘したものを使えば不要\r\n //もし可能ならdocument.createDocumentFragmentを使ってみては?\r\n }\r\n}\r\n\r\n//なんのためのクラスなのかわからない。設計図を書くべきなのにその現場でしか使えない設計図を書いている\r\nclass SetDate {\r\n constructor(array){\r\n const table = document.querySelector('table');//複数の場合はどうする?\r\n const tbody = document.createElement('tbody');\r\n\r\n array.forEach(els => {//els がグローバル\r\n const tr=document.createElement('tr');//insertRow\r\n\r\n for(let i=0;ihogeになっているかもしれないから。\r\n\r\n```js\r\nclass HYOU {\r\n constructor (table) {\r\n this.table = table;\r\n }\r\n setData (ary) { }\r\n setTHead () { }\r\n\r\n handleEvent (event) {\r\n let e = event.target;\r\n //this.table.tHead が必ずある前提\r\n if (8 === (e.compareDocumentPosition (this.table.tHead) & e.DOCUMENT_POSITION_CONTAINS)) {\r\n let th = e.closest ('th');// e === th と限らない \r\n if (th) {\r\n console.log (th.cellIndex);\r\n }\r\n }\r\n }\r\n}\r\nconst a = new HYOU (document.querySelector('table'));\r\ndocument.addEventListener ('click', a, false);\r\n```","dateModified":"2020-05-25T09:01:02.591Z","datePublished":"2020-05-25T05:36:09.373Z","upvoteCount":2,"url":"https://teratail.com/questions/264609#reply-379209"},"suggestedAnswer":[{"@type":"Answer","text":"考え方は2つ\r\n- 配列をソートして毎回テーブルを書き換える\r\n- tbodyのtrをソートしてappendChild処理する\r\n\r\n※ [codepen sample](https://codepen.io/yambejp/pen/xxweGQv)","dateModified":"2020-05-25T04:33:25.606Z","datePublished":"2020-05-25T02:29:39.285Z","upvoteCount":1,"url":"https://teratail.com/questions/264609#reply-379151","comment":[{"@type":"Comment","text":"とりあえず、ご自身でソースは書けるみたいなので、オリジナルを\r\nまったく参考にせず1から書いてみました。参考までに","datePublished":"2020-05-25T04:34:28.186Z","dateModified":"2020-05-25T04:34:28.186Z"},{"@type":"Comment","text":"ありがとうございます。\r\n初見のメソッドも多々あり。\r\n勉強させていただきます。","datePublished":"2020-05-25T07:39:24.505Z","dateModified":"2020-05-25T07:39:24.505Z"}]}],"breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"トップ","url":"https://teratail.com"},{"@type":"ListItem","position":2,"name":"JavaScriptに関する質問","url":"https://teratail.com/tags/JavaScript"},{"@type":"ListItem","position":3,"name":"JavaScript","url":"https://teratail.com/tags/JavaScript"}]}}}javascriptでソート付きの表を作りました。
一応自分の希望するような動きにはなったのですが、もっと洗練された書き方があれば教えてください。
ソートしたデータを表示する過程がこれでいいのか??と思っています。
js
1const tbl_ths =['Name', 'gender','Team', 'Score',];
2let tbl_dat=[
3 ['Tokieda','男','red','2'],
4 ['takahashi','男','blue','12'],
5 ['miyahashi','男','blue','31'],
6 ['taguchi','女','Orange','32'],
7 ['fkoji','男','red','84'],
8 ['masako','女','Blue','49'],
9];
10let tbl_sort;
11let col;
12let _a;
13let _b;
14let cf;
15
16function doSort(){
17
18 const ths =document.querySelectorAll('th');
19 ths.forEach((th,index) =>{
20 if (index !== col){
21 th.className = '';
22 }
23 })
24 tbl_dat.sort((a, b)=> {
25 if(isNaN( a[col])){
26 _a = a[col].toLocaleLowerCase();
27 _b = b[col].toLocaleLowerCase();
28 } else {
29 _a = Number(a[col]);
30 _b = Number(b[col]);
31 }
32
33 if (_a > _b){
34 return 1*cf
35 } else if (_a < _b){
36 return -1*cf
37 } else {
38 return 0
39 }
40 })
41
42const tbody=document.querySelector('tbody');
43tbody.remove();
44
45 const date = new SetDate(tbl_dat);
46}
47
48
49class SetHead {
50 constructor(els){
51 const table = document.querySelector('table');
52 const thead = document.createElement('thead');
53 const tr=document.createElement('tr');
54
55 for(let i=0;i<els.length;i++){
56 const th=document.createElement('th');
57 th.innerHTML=els[i];
58 th.addEventListener('click',()=>{
59 col=th.cellIndex;
60
61 if(th.classList.contains('ascend')){
62 th.className='decend';
63 cf=-1;
64 }else {
65 th.className='ascend';
66 cf=1;
67 }
68 doSort();
69
70 })
71 tr.appendChild(th);
72 }
73 thead.appendChild(tr);
74 table.appendChild(thead);
75 }
76}
77
78class SetDate {
79 constructor(array){
80 const table = document.querySelector('table');
81 const tbody = document.createElement('tbody');
82
83 array.forEach(els => {
84 const tr=document.createElement('tr');
85
86 for(let i=0;i<els.length;i++){
87 const td=document.createElement('td');
88 td.innerHTML=els[i];
89 tr.appendChild(td);
90 };
91
92 tbody.appendChild(tr);
93 })
94 table.appendChild(tbody);
95 }
96}
97
98const header=new SetHead(tbl_ths);
99const date = new SetDate(tbl_dat);
html
1<body>
2
3 <table class="tbl">
4 </table>
5
6<script src="main.js"></script>
7</body>
css
1*{
2 margin:0;
3 padding:0;
4 box-sizing: border-box;
5}
6.tbl {
7 border-collapse: collapse;
8 margin:20px auto;
9 font-family: Verdana, Geneva, Tahoma, sans-serif;
10 font-size: 16px;
11 & td,& th {
12 width:180px;
13 height: 36px;
14 padding:5px 20px;
15 border:1px solid #E9EAE8;
16 }
17 & thead {
18 cursor: pointer;
19 & th::after {
20 content: '\f0dc';
21 font-family:'FontAwesome';
22 font-size: 12px;
23 color: #ccc;
24 float: right;
25 padding-top: 4px;
26 font-weight: normal;
27 }
28 & th.decend::after {
29 content: '\f0dd';
30 color: #000;
31 }
32 & th.ascend::after {
33 content: '\f0de';
34 color: #000;
35 }
36 }
37 & tbody tr td:last-child {
38 text-align: right;
39 }
40 & tbody tr:nth-child(2n) {
41 background-color: #f8f8f8;
42 }
43
44}
45
ベストアンサー
コメントに書き入れました。
オブジェクト指向が意味をなしていないと思いました。
追記
document.createElement('thead');
は、複数個登録できない。事前にチェックが必要
1回しか使わないからいいのでは?と思うかもしれないけれど
それならば class で書く必要がないのでは? といわれてしまう。
javascript
1
2let tbl_sort;//使われてない
3//以下4つは、グローバス変数として使わなくてもできる!
4let col;
5let _a;
6let _b;
7let cf;
8
9function doSort(/* cf これで呼び出してみては? */){
10
11 const ths =document.querySelectorAll('th');//テーブル要素が複数あることを想定していない
12 ths.forEach((th,index) =>{
13 if (index !== col){
14 th.className = '';//これは空白で複数していできることを否定している
15 }
16 })
17 tbl_dat.sort((a, b)=> {
18 if(isNaN( a[col])){
19 _a = a[col].toLocaleLowerCase();
20 _b = b[col].toLocaleLowerCase();
21 } else {
22 _a = Number(a[col]);
23 _b = Number(b[col]);
24 }
25
26 if (_a > _b){
27 return 1*cf
28 } else if (_a < _b){
29 return -1*cf
30 } else {
31 return 0
32 }
33 })
34
35const tbody=document.querySelector('tbody');//これも複数のテーブルを考慮していない
36tbody.remove();
37
38 const date = new SetDate(tbl_dat);//なんのために data に保存する?
39}
40
41
42class SetHead {
43 constructor(els){//els の型のチェックがされていない
44 const table = document.querySelector('table');//これも複数のテーブルを考慮していない
45 const thead = document.createElement('thead');// table.createTHead を使う
46 const tr=document.createElement('tr');// tbody.inserRow を使えばあとの appendChild が不要
47
48 for(let i=0;i<els.length;i++){
49 const th=document.createElement('th');//ぜひthでないのなら insertCell でいいような? tr:td.first-of-type で見た目は弄れる
50 th.innerHTML=els[i];//せっかく DOM を使えるのなら innerHTML の使用は避ける
51 th.addEventListener('click',(/* event */)=>{ //個人的には、イベントの管理は document で行う。
52 col=th.cellIndex;
53
54 if(th.classList.contains('ascend')){
55 th.className='decend';//ここでも複数の指定を破壊している
56 cf=-1;//event.shiftKey を使えば、逆ソートもできるんじゃね?
57 }else {
58 th.className='ascend';
59 cf=1;
60 }
61 doSort();//
62
63 })
64 tr.appendChild(th);//上で指摘したものを使えば不要
65 }
66 thead.appendChild(tr);//上で指摘したものを使えば不要
67 table.appendChild(thead);//上で指摘したものを使えば不要
68 //もし可能ならdocument.createDocumentFragmentを使ってみては?
69 }
70}
71
72//なんのためのクラスなのかわからない。設計図を書くべきなのにその現場でしか使えない設計図を書いている
73class SetDate {
74 constructor(array){
75 const table = document.querySelector('table');//複数の場合はどうする?
76 const tbody = document.createElement('tbody');
77
78 array.forEach(els => {//els がグローバル
79 const tr=document.createElement('tr');//insertRow
80
81 for(let i=0;i<els.length;i++){
82 const td=document.createElement('td');//insertCell
83 td.innerHTML=els[i];//できるなら textContent
84 tr.appendChild(td); //不要になる
85 };
86
87 tbody.appendChild(tr);//不要になる
88 })
89 table.appendChild(tbody);
90 }
91}
92
93const header=new SetHead(tbl_ths);
94const date = new SetDate(tbl_dat);
95
96/*例えば
97header2=new SetHead(tbl_ths2);
98header3=new SetHead(tbl_ths3);
99header4=new SetHead(tbl_ths4);
100のように、使いまわしができない設計図などただの function でよい!
101*/
質問を閉じてしまったのね
イベントについて流してしまったのでついでに。
document.addEventListener にしているのは、対象のテーブル以外に範囲を広げているけれど
document が全て読み込まれなくてもOKだから。
そして、個々の TH 要素にイベントをくっつけるのは好くない。
やたらとくっつけたがる人が多い。
クリックされた要素から this.table の中の要素か判断する
その要素からTH 要素を取得する。
<th><labele>hoge</label></th>になっているかもしれないから。
js
1class HYOU {
2 constructor (table) {
3 this.table = table;
4 }
5 setData (ary) { }
6 setTHead () { }
7
8 handleEvent (event) {
9 let e = event.target;
10 //this.table.tHead が必ずある前提
11 if (8 === (e.compareDocumentPosition (this.table.tHead) & e.DOCUMENT_POSITION_CONTAINS)) {
12 let th = e.closest ('th');// e === th と限らない
13 if (th) {
14 console.log (th.cellIndex);
15 }
16 }
17 }
18}
19const a = new HYOU (document.querySelector('table'));
20document.addEventListener ('click', a, false);
考え方は2つ
- 配列をソートして毎回テーブルを書き換える
- tbodyのtrをソートしてappendChild処理する
※ codepen sample
15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.29%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる
質問する
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/05/25 07:50