簡體   English   中英

從2D數組創建可編輯的HTML表

[英]Creating an editable HTML table from 2D array

所以我想制作一個flashcards網站,用戶可以在其中添加,編輯和刪除抽認卡。 有兩張牌 - 正面和背面。 用戶可以添加單詞,但無法編輯或刪除它們。 出於這個問題的目的,我將使用一個示例數組:

var flashcards = [["Uomo", "Man"],["Donna", "Woman"],["Ragazzo", "Boy"]]

但是我想要一種更加用戶友好的方式來編輯抽認卡,最好使用這樣的表格:

<table>
  <tr>
    <th>Front</th>
    <th>Back</th> 
  </tr>
  <tr>
    <td><input type="text" name="flashcard" value="Uomo"> </td>
    <td><input type="text" name="flashcard" value="Man"></td>
  </tr>
    <tr>
    <td><input type="text" name="flashcard" value="Donna"></td>
    <td><input type="text" name="flashcard" value="Woman"></td>
  </tr>
      <tr>
    <td><input type="text" name="flashcard" value="Ragazzo"></td>
    <td><input type="text" name="flashcard" value="Boy"></td>
  </tr>
</table>

<button type="button">Add more</button>
<br>
<button type="button">Save changes</button>

因此,他們可以更新編輯輸入字段的抽認卡,或單擊“添加更多”並創建新行。 單擊“保存更改”會將數組更新為表的內容。

我不介意它本身不是HTML表,而是易於為用戶編輯的東西。

我無法弄清楚解決這個問題的最佳方法。 有什么建議?

我認為你可以使用就地編輯系統,我找到了一個很好的教程創建一個就地編輯系統

我已經推薦了VueJS - 它確實是解決這個問題的好工具。 無論如何,我使用vanilla JavaScript鍵入了一個基本解決方案。 對於編輯部分,它使用contenteditable HTML屬性,允許最終用戶雙擊一個元素並更改它的textContent。 html顯示是基本的,因此您可以根據自己的需要進行更改

<div id=style="width: 100%;">
  <ul id="table" style="list-style-type: none; display: inline-block;">

  </ul>
</div>
<script>
var flashcards = [["Uomo", "Man"],["Donna", "Woman"],["Ragazzo", "Boy"]];
var displayedCard = []; //Using a parallel array to keep track of which side is shown
for(var i = 0; i < flashcards.length; i++){
    displayedCard.push(0);
}
function renderFlashcardTable(){ //This will do the initial rendering of the table
    let ulTable = document.getElementById("table");
    for(var i = 0; i < flashcards.length; i++){
        let card = flashcards[i];
        let indexOfSideShown = displayedCard[i];
        let li = document.createElement("li");
        let cardValueSpan = document.createElement("span");
        cardValueSpan.innerHTML = card[indexOfSideShown]; //Get the value of the side of the card that is shown
        cardValueSpan.setAttribute("contenteditable", "true"); 
        cardValueSpan.oninput = function(e){ //This method gets called when the user de-selects the element they have been editing
            let li = this.parentElement;
            let sideIndex = parseInt(li.getAttribute("side-index"));
            card[sideIndex] = this.textContent;
        }
        li.appendChild(cardValueSpan);
        li.appendChild(getFlipSidesButton(li));
        li.setAttribute("side-index", indexOfSideShown);
        li.setAttribute("card-index", i);
        ulTable.appendChild(li);
    }
}
function getFlipSidesButton(listItem){//This is generated for each card and when clicked it "flips the switch"
    let btn = document.createElement("button");
    btn.innerHTML = "Flip card";
    btn.onclick = function(e){
        let card = flashcards[listItem.getAttribute("card-index")];
        let index = parseInt(listItem.getAttribute("side-index"));
        let nextSide = (index == 1) ? 0 : 1;
        listItem.setAttribute("side-index", nextSide);
        listItem.children[0].innerHTML = card[nextSide];
    }
    return btn;
}

renderFlashcardTable();
</script>

我已經使用純本機javascript和數據驅動方法組合了一個工作示例。 您可以查看並了解在大型Js應用程序中如何操作和使用數據的方式。

這里的要點是盡可能地隔離數據和邏輯。

希望這有幫助。

Codepen: https ://codepen.io/DieByMacro/pen/rgQBPZ

 (function() { /** * Default value for Front and Back */ const DEFAULT = { front: '', back: '', } /** * Class Card: using for holding value of front and back. * As well as having `update` method to handle new value * from input itself. */ class Card { constructor({front, back, id} = {}) { this.front = front || DEFAULT.front; this.back = back || DEFAULT.back; this.id = id; } update = (side, value) => this[side] = value; } /** * Table Class: handle rendering data and update new value * according to the instance of Card. */ class Table { constructor() { this.init(); } /** Render basic table and heading of table */ init = () => { const table = document.querySelector('#table'); const thead = document.createElement('tr'); const theadContent = this.renderRow('th', thead, { front: 'Front', back: 'Back' }) const tbody = document.createElement('tbody'); table.appendChild(theadContent); table.appendChild(tbody); } /** Handling add event from Clicking on Add button * Note the `update: updateFnc` line, this means we will refer * `.update()` method of Card instance with `updateFnc()`, this is * used for update value Card instance itself. */ add = ({front, back, id, update: updateFnc }) => { const tbody = document.querySelector('#table tbody'); const row = document.createElement('tr'); const rowWithInput = this.renderRow('td', row, {front, back, id, updateFnc}); tbody.appendChild(rowWithInput); } renderInput = (side, id, fnc) => { const input = document.createElement('input'); input.setAttribute('type','text'); input.setAttribute('name',`${side}-value-${id}`) input.addEventListener('change', e => this.onInputChangeHandler(e, side, fnc)); return input; } renderRow = ( tag, parent, { front, back, id, updateFnc }) => { const frontColumn = document.createElement( tag ); const backColumn = document.createElement( tag ); /** Conditionally rendering based on `tag` type */ if ( tag === 'th') { frontColumn.innerText = front; backColumn.innerText = back; }else { /** Create two new inputs for each Card instance. Each handle * each side (front, back) */ const inputFront = this.renderInput('front', id, updateFnc); const inputBack = this.renderInput('back', id, updateFnc); frontColumn.appendChild(inputFront); backColumn.appendChild(inputBack); } parent.appendChild(frontColumn) parent.appendChild(backColumn) return parent; } /** Getting new value and run `.update()` method of Card, now referred as `fnc` */ onInputChangeHandler = (event, side, fnc) => { fnc(side, event.target.value); } } class App { /** * Holding cards data * Notice this is an object, not an array * Working with react for a while, I see most of the times data as an object works best when it comes to cRUD, this means we don't have to iterate through the array to find the specific element/item to do the work. This saves a lot of time */ cards = {}; constructor(){ this.domTable = new Table(); this.domAdd = document.querySelector('#btn-add'); this.domResult = document.querySelector('#btn-result'); this.domAdd.addEventListener('click', this.onClickAddHandler ); this.domResult.addEventListener('click', this.onClickResultHandler ); } onClickAddHandler = () => { const id = uuid(); const newCard = new Card({id}); this.cards[id] = newCard; this.domTable.add(newCard) } onClickResultHandler = () => { /** * Using `for ... in ` with object. Or you can use 3rd party like lodash for iteration */ for (const id in this.cards) { console.log({ front: this.cards[id].front, back: this.cards[id].back, id: this.cards[id].id }); } }; } // Start the application const app = new App(); })(); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/node-uuid/1.4.8/uuid.min.js"></script> <div id="table"></div> <button id="btn-add">Add</button> <button id="btn-result">Result</button> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM