最近接手的任务用的是KnockoutJS + TypeScript,所以第二个项目就采用KnockoutJS做一个老生常谈的TODO List。
https://codepen.io/xinxhe/pen/qBBMoVL
KnockoutJS的特点是双向绑定,在ViewModel中定义一系列的变量,然后用data-bind绑定到对应的HTML元件中即可。做这个项目的时候有几个难点:1.实现输入to-do后按回车键添加; 2. 实现动态组件变化,如点击编辑按钮后变成储存按钮,点击编辑按钮后to-do文字部分变成编辑框; 3. 修改样式让to-do变得好看(没错,这个花费时间最长!)☺
下面上代码:
HTML
<div class="todo-container"> <div class="todo-sub-container todo-title"> <h2>To-do list by KnockoutJS</h2> </div> <div class="todo-sub-container todo-input"> <input data-bind="value: itemToAdd, valueUpdate: 'afterkeydown', event: { keyup : addItem }" placeholder="Add a to-do" /> </div> <div class="todo-sub-container todo-list"> <ul data-bind="foreach: items" class="todo-items"> <li class="todo-item"> <div class="todo-item-text"> <span data-bind="visible: !$data.isEditMode(), text: $data.name"></span> <input data-bind="visible: $data.isEditMode, value: $data.name, hasFocus: isEditMode" /> </div> <div class="todo-item-control"> <button data-bind="click: $parent.removeItem" class="icon fas fa-trash-alt"></button> <button data-bind="visible: !$data.isEditMode(), click: $parent.editItem" class="icon fas fa-pen"></button> <button data-bind="visible: $data.isEditMode, click: $parent.saveItem" class="icon fas fa-save"></button> </div> </li> </ul> </div> </div>
CSS
* { font-family: Arial, Helvetica, sans-serif; margin: 0; padding: 0; box-sizing: border-box; } .todo-container { margin: auto; width: 60%; , height: 100 } .todo-sub-container { margin: auto; min-width: 500px; height: 20vh; display: flex; justify-content: center; align-items: center; } .todo-title { background: #ff7f35; color: #fff; font-size: 25px; border-radius: 0 0 5px 5px; } .todo-input { height: 15vh; } .todo-input > input { width: 100%; margin: 0 20px; height: 50px; border: 4px solid #ff8c3e; border-radius: 5px; padding: 5px; font-size: 18px; } .todo-input > input:focus{ outline: none; } .todo-list { height: 65vh; background: #fbffde; align-items: flex-start; border-radius: 5px 5px 0 0; } .todo-items { list-style: none; width: 100%; margin: 0 20px; } .todo-item { background: #ffe999; margin-top: 10px; padding: 10px 10px 10px 20px; display: flex; justify-content: space-between; align-items: center; min-height: 50px; border-radius: 5px; border: 2px solid #ffc25c; } .todo-item-text { font-size: 18px; color: #9a1717; width: 80%; word-wrap: break-word; } .todo-item-text > input { padding: 5px; font-size: 18px; background: #fbffde; border: none; width: 100%; } .todo-item-text > input:focus { outline: none; } .todo-item-control > button { background: #fff6ca; margin-left: 5px; border: 2px solid #ff7f35; border-radius: 20px; width: 25px; height: 25px; } .todo-item-control > button:hover, .icon { background: #fff; border-color: #fff; cursor: pointer; color: #9a1717; } .icon { color: #ff7f35; }
JS
function ToDoItem(name) { var self = this; self.name = ko.observable(name); self.isEditMode = ko.observable(false); } var ViewModel = function() { var self = this; let todoItems = [ new ToDoItem("Exercise one hour"), new ToDoItem("Supermarket")]; self.items = ko.observableArray(todoItems); self.itemToAdd = ko.observable(""); self.addItem = function(data, event) { if (event.keyCode === 13 && self.itemToAdd() != "") { self.items.push(new ToDoItem(self.itemToAdd())); self.itemToAdd(""); } }; self.removeItem = function() { self.items.remove(this); }; self.editItem = function() { this.isEditMode(true); }; self.saveItem = function() { this.isEditMode(false); }; }; ko.applyBindings(new ViewModel());
这个项目花费三个晚上,本来想要用TypeScript,但是因为KnockoutJS的文档是用JS写的,所以为了参考起来方便就直接用了JS。之后可以试着将其改成TypeScript。