不知不觉铁人赛也到一半了呢! 开学後,能写文章的时间就渐渐变少(期初各种专题、报告就纷纷露头啦),或许文章的品质有因为赶稿略微下降不少吧XD。
这次的铁人赛是我第一次在网路上公开发表文章,身为一个新人写手,我还真的不是很懂要如何写出一篇既生动又有趣还浅显易懂的文章。
不过一路走到现在,也在不知不觉中体会到了写文章的快乐(ps.写得太放飞自我啦~),接下来的15天,相信我会带着这份快乐的心情来完成这一次的铁人赛。
JS 30 是由加拿大的全端工程师 Wes Bos 免费提供的 JavaScript 简单应用课程,课程主打 No Frameworks
、No Compilers
、No Libraries
、No Boilerplate
在30天的30部教学影片里,建立30个JavaScript的有趣小东西。
另外,Wes Bos 也很无私地在 Github 上公开了所有 JS 30 课程的程序码,有兴趣的话可以去 fork 或下载。
将被新增到menu
的项目储存到localStorage
中,使得後续刷新页面时,可以从localStorage
调用资料回复之前新增在menu
的项目。
最外层的.wrapper
代表的是整个的 menu,.plates
则用来放入 menu 的内容项目。最後,.add-items
是一个表单元素,里面有一个文字输入框(<input type="text"></input>
)用来填入要新增的项目名称,还有一个用来加入项目到 menu 的 submit button(<input type="submit"></input>
)。
<div class="wrapper">
<h2>LOCAL TAPAS</h2>
<p></p>
<ul class="plates">
<li>Loading Tapas...</li>
</ul>
<form class="add-items">
<input type="text" name="item" placeholder="Item Name" required>
<input type="submit" value="+ Add Item">
</form>
</div>
宣告常数addItems
用来存放取得的整个 menu(.add-items
)。
宣告常数itemsList
用来存放 menu 里的所有项目(.plates
)。
宣告常数items
为一个空阵列,用来存放我们每次在文字输入框填入要新增到 menu 的 item。
const addItems = document.querySelector('.add-items');
const itemsList = document.querySelector('.plates');
const items = [];
我们首先用e.preventDefault()
避免每次提交新的内容进入items
造成页面的 reloading。
宣告常数text
用来存放在文字输入框填入的项目名称。
建立物件item
并赋予两个属性text(项目的名称)、done(是否被勾选),这里我们原本可以用text:text;
,但在 ES6 里可以被简写为text
。
将建立出的物件放入(push)阵列items
中,之後用this.reset()
清掉在文字输入框的文字以利下一次新增项目。
function addItem(e){
e.preventDefault();//prevent page from reloading
const text = this.querySelector('[name="item"]').value;
const item = {
text, //text: text
done: false
}
items.push(item);
this.reset(); //form element clear the input
}
addItems.addEventListener('submit',addItem);
用来将items
里所有的item
逐一转换成 HTML 的格式,藉此更新 menu 上的项目。
透过map()
将阵列中的item
(方法里用plate
代称),逐一用<li>~<li>
的格式重新组合成一个有checkBox可以勾选的列表项目。
因为map()
回传的是一个阵列,所以在最後用join()
将阵列中的元素以空白作为间隔符号串联成一个 HTML 格式的字串并修改列表(ul
)里的项目内容(innerHTML
)。
//create the actual html here
function populateList(plates = [], platesList){ //plates default: empty, prvent to crash javascript if you forget to pass it
platesList.innerHTML = plates.map((plate,i) =>{ //i: index
return `
<li>
<input type="checkbox" data-index=${i} id="item${i}" ${plate.done ? 'checked' : ''}>
<label for="item${i}">${plate.text}</label>
</li>
`;
}).join('');
}
JS 的部分完成到这里,基本上就可以将新建立的项目放到 menu 中。
但是将网页重新整理(F5),我们可以发现原来放到 menu 中的东西都不见了。那要怎麽保留我们之前在 menu 放入的项目呢? 相信 localStorage 可以帮我们这个忙。
localStorage
允许我们存取目前文件(Document
)隶属网域来源的Storage
物件,简单来说我们可以用key-value
(键-值)的方式来存取这个Storage
物件的资料,localStorage存放的资料是没有时间限制的(不会关闭网页就不见)。另外,这边的键-值都是以字串
型态存放。
实际在localStorage
放资料(localStorage.setItem()
):
localStorage.setItem('myCat', 'Tom');
打开检查模式,查看我们放的资料(Application -> Local Storage):
资料真的被放到 Local Storage 里面了,我们之後就可以用 Local Storage 的方法调用这些已存的资料。
items :
我们原本宣告常数items
为一个空阵列,但是我们也可以改成如果localStorage
有资料(localStorage.getItem('items')
)就将其放入items
。要注意localStorage
放的资料是字串型态,所以还要藉助JSON.parse()
把它还原成物件再传递给items
。
addItem() :
每一次加入新的item
到items
,我们都需要同时更新现在menu
的项目内容,所以我们在方法里面加上populateList(items,itemsList);
。
localStorage.setItem('items',JSON.stringify(items));
用来把我们新增的item
存进localStorage
保存新增在menu
的项目。要注意items
本身是物件型别(Object),所以要先用JSON.stringify()
将其转换成字串再存入localStorage
。
const items = JSON.parse(localStorage.getItem('items')) || []; // dump data from localstorage if existed
function addItem(e){
/*上略*/
populateList(items,itemsList);
localStorage.setItem('items',JSON.stringify(items));
/*下略...*/
}
只要做到这里,之前加入到menu
的item
就不会在重新整理网页的时候消失不见,每次都会从localStorage
取得之前的资料(如果有资料的话)。
但这样好像还是少了什麽,如果我们将checkBox
勾起来再去重新整理网页,就会发现checkBox
又回到没勾选的状态。要储存checkBox
的勾选状态,我们可以用另一个方法toggleDone()
来处理。
toggleDone() :
Event.target 指向最初触发事件的 DOM 物件。
if(!e.target.matches('input')) return;
,如果触发事件的 DOM 物件不是input element
的话,就停止继续执行。
宣告常数el
存放触发事件的 DOM 物件。
宣告常数index
存放触发事件的 DOM 物件的data-index
属性。
items[index].done = !items[index].done;
,让触发事件的 DOM 物件的done
变为相反值(true to false;false to true),前面我们在populateList()
里设定item (plate)
的done
属性是true就将checkBox
打勾(checked)。(${plate.done ? 'checked' : ''}
)
最後我们需要将变更後的items
再次的放入localStorage
中,要注意先用JSON.stringify()
转换成字串再放入,接着用populateList()
去更新现在menu
的内容就完成了。
function toggleDone(e){
if(!e.target.matches('input')) return;
const el = e.target;
const index = el.dataset.index;
items[index].done = !items[index].done;
localStorage.setItem('items',JSON.stringify(items));
populateList(items,itemsList);
}
itemsList.addEventListener('click',toggleDone);
//create the actual html here
function populateList(plates = [], platesList){ //plates default: empty, prvent to crash javascript if you forget to pass it
platesList.innerHTML = plates.map((plate,i) =>{ //i: index
return `
<li>
<input type="checkbox" data-index=${i} id="item${i}" ${plate.done ? 'checked' : ''}>
<label for="item${i}">${plate.text}</label>
</li>
`;
}).join('');
}
Array.prototype.map()
Window.localStorage
Storage
Event.target
Event Delegation — 事件委派介绍 与 触发委派的回呼函数
<<: 不只懂 Vue 语法:Vue 3 如何使用 Proxy 实现响应式(Reactivity)?
>>: [CSS] Flex/Grid Layout Modules, part 10
这篇调整的方向是 透过 Partial View 来 Render Collection 项目 透过...
30 天挑战终於完成了,终於恢复自由身了!这 30 篇不只是传递分享知识的过程,更是让自己巩固加深原...
前言 目前已经将Protocol都设置完毕了,那现在就要来实作让其他的ViewController执...
Alt + = 在Excel中是设置SUM求和公式的快捷键。可是,它还有其他功能哦。 1、多列资料求...
这边推荐你一款 FonePaw iOS 资料备份及还原 软件,能够一键备份 iPhone Faceb...