繁体   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