設定UIをクラスで表現してみる。
前回で、設定UI(テーブル形式のUI)をTABLEタグと関連タグで作れることがわかった。
ただ、UIを作るたびにHTMLを作るのはナンセンスな気がした。
※前回のUIは以下のURLを参照してください。
https://qiita.com/puyon/items/cb273b2c79a5b1ea1f1a
なので、他の言語にもあるように「クラス」を定義してインスタンス生成するよう考えた。
※これ以降、私個人の思想が入ります。さらっと読み飛ばしていただければ幸いです。
利用側のイメージ
せっかくクラス化するのだから、少しは利用側の利便性を考慮したいと思った。
こんな感じ。
・テーブルインスタンス作成
・テーブルの列数×行数を確保
・セルのタイプと内容をセット
・DIVコンテナとテーブルのHTMLを作成
要はHTMLの事情を意識せずにテーブル形式UIを作りたい。
実装イメージ。
//テーブルインスタンス作成
const table = new HtmlMakerTable()
//テーブルの列数×行数を確保
table.makeDim(2, 1)
//セルのタイプと内容をセット
table.getCell(0, 0).typeInfo.setLabel(`タイトル`, false)
table.getCell(1, 0).typeInfo.setButton(`タップ`)
//DIVコンテナとテーブルのHTMLを作成
const html = table.ToScrollHTML(`className`, `id`)
見た目を表現するとこんな感じ。
| セル1 | セル2 |
|---|---|
| タイトル(ラベル) | タップ(ボタン) |
クラス実装イメージ
サポートするセルの形式
まずは、クラスがサポートするセルの形式を定義。
export const HtmlMakerOptionItemUsingTypes = {
Unknown: "Unknown",
Btn: "Btn",
Label: "Label",
LabelRO: "LabelRO",
} as const;
export type HtmlMakerOptionItemUsingType = typeof HtmlMakerOptionItemUsingTypes[keyof typeof HtmlMakerOptionItemUsingTypes];
セルを表現するクラス
次にセルを作り出すクラスを実装。
(1)実際のHTMLを作成することを担当するクラス
export class HtmlMakerOptionItemUsing {
itemType: HtmlMakerOptionItemUsingType = HtmlMakerOptionItemUsingTypes.Unknown
label: string = ""
}
export class HtmlMakerOption {
toolTip: string = ""
using: HtmlMakerOptionItemUsing = new HtmlMakerOptionItemUsing()
public setButton(labelText: string) {
this.using.itemType = HtmlMakerOptionItemUsingTypes.Btn
this.using.label = labelText
}
public setLabel(labelText: string, isRW: boolean) {
this.using.itemType = isRW ? HtmlMakerOptionItemUsingTypes.Label : HtmlMakerOptionItemUsingTypes.LabelRO
this.using.label = labelText
}
public ToButtonHTML(className: string): string {
const itemId = this.using.itemId >= 0 ? ` item-id="${this.using.itemId}"` : ``
return `
<button class="${className}"${itemId} title="${this.toolTip}">${this.using.label}</button>
`.trim()
}
public ToLableHTML(className: string): string {
const toolTip = this.toolTip !== `` ? ` title="${this.toolTip}"` : ``
return `
<span class="${className}" data-readonly="false"${toolTip}>${this.using.label}</span>
`.trim()
}
}
(2)セルの形式を作り出すクラス
export class HtmlMakerTableCellInfo {
typeInfo: HtmlMakerOption = new HtmlMakerOption()
className: string = ``
public ToHTML() {
let dispTag = ``
switch (this.typeInfo.using.itemType) {
case HtmlMakerOptionItemUsingTypes.Btn:
dispTag = this.typeInfo.ToButtonHTML(this.className)
break
case HtmlMakerOptionItemUsingTypes.Label:
dispTag = this.typeInfo.ToLableHTML(this.className)
break
return dispTag
}
}
export class HtmlMakerTableCell {
items: Array<HtmlMakerTableCellInfo> = new Array<HtmlMakerTableCellInfo>()
public makeItems(nItem: number = 1) {
if (this.items.length > 0)
this.items.splice(0, this.items.length)
for (let i = 0; i < nItem; i++) {
const item = new HtmlMakerTableCellInfo()
this.items.push(item)
}
}
public ToHTML(): string {
let resHTML = ``
for (const item of this.items) {
const dispTag = item.ToHTML()
if (dispTag !== ``) {
if (this.items.length >= 2)
resHTML = `${resHTML}<div>${dispTag}</div>`
else
resHTML = dispTag
}
}
return resHTML
}
}
行(Row)を表現するクラス
export class HtmlMakerTableRow {
rowName: string = ``
cols: Array<HtmlMakerTableCell> = new Array<HtmlMakerTableCell>()
public makeCols(nCol: number) {
if (this.cols.length > 0)
this.cols.splice(0, this.cols.length)
for (let i = 0; i < nCol; i++) {
const cell = new HtmlMakerTableCell()
cell.makeItems()
this.cols.push(cell)
}
}
public ToHTML(): string {
let resHTML = ``
for (const item of this.cols) {
const dispTag = item.ToHTML()
if (dispTag !== ``) {
resHTML = `${resHTML}<td>${dispTag}</td>`
}
}
return resHTML
}
}
テーブルを表現するクラス
export class HtmlMakerTable {
tableName: string = ``
rows: Array<HtmlMakerTableRow> = new Array<HtmlMakerTableRow>()
public makeDim(nCol: number, nRow: number) {
if (this.rows.length > 0)
this.rows.splice(0, this.rows.length)
for (let i = 0; i < nRow; i++) {
const row = new HtmlMakerTableRow()
row.makeCols(nCol)
this.rows.push(row)
}
}
public getCell(colIndex: number, rowIndex: number, itemIndex: number = 0): HtmlMakerTableCellInfo {
return this.rows[rowIndex].cols[colIndex].items[itemIndex]
}
public ToHTML(className: string, idName: string): string {
this.tableName = className
let resHTML = ``
let rowId = 0 //初期値1~
for (const row of this.rows) {
rowId++
let dispTag = row.ToHTML()
if (dispTag !== ``) {
const rowClassName = (row.rowName !== ``) ? ` class="${row.rowName}"` : ``
resHTML = `${resHTML}<tr ${rowClassName} item-id="${rowId}">${dispTag}</tr>`
}
}
const cssClassName = (className !== ``) ? ` class="${className}"` : ``
const id = (idName !== ``) ? ` id="${idName}"` : ``
const itemId = (idName !== ``) ? ` item-id="${idName}"` : ``
resHTML = `<table${cssClassName}${id}${itemId}>${resHTML}</table>`
return resHTML
}
public ToScrollHTML(className: string, id: string): string {
const cssClassName = (className !== ``) ? ` class="${className}"` : ``
const itemId = (id !== ``) ? ` item-id="${id}"` : ``
return `<div${cssClassName}${itemId}>
${this.ToHTML(className, id)}
</div>`
}
}
つぎは。
テーブルを表現することができたので、必要に応じてセルの形式を追加していけばコンボックスや他のセルにも対応できそう。
複雑なパッケージを導入する手間や将来性を考えると自分で作った方が手っ取り早いこともある気がした。
※自分で作れれば無限の可能性&超高速、かも。
テーブルの内容を読みだしたり更新したりしたいと思った。
つづく。
https://qiita.com/puyon/items/7568eddc916104fb718b