自学JavaScript第三天- JS 进阶:BOM DOM 事件 表单 文件操作 数据存储
浏览器中的 js 包含三个内容
- ECMAScript : ES6 ,即核心语法规范
- BOM : 浏览器对象模型
- DOM : 文档对象模型
浏览器对象模型 BOM
JavaScript可以获取浏览器提供的很多对象,并进行操作
window 对象
window 对象不但充当全局作用域,而且表示浏览器窗口。需注意的是,如果文档(页面)中包含 <iframe> 标签,则浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外的 window 对象。其常用的属性及方法有
属性 | 描述 |
---|---|
closed | 返回窗口是否已被关闭。 |
defaultStatus | 设置或返回窗口状态栏中的默认文本。 |
document | 对 Document 对象的只读引用。(请参阅对象) |
frames | 返回窗口中所有命名的框架。该集合是 Window 对象的数组,每个 Window 对象在窗口中含有一个框架。 |
history | 对 History 对象的只读引用。请参数 History 对象。 |
innerHeight | 返回窗口的文档显示区的高度。 |
innerWidth | 返回窗口的文档显示区的宽度。 |
localStorage | 在浏览器中存储 key/value 对。没有过期时间。 |
length | 设置或返回窗口中的框架数量。 |
location | 用于窗口或框架的 Location 对象。请参阅 Location 对象。 |
name | 设置或返回窗口的名称。 |
navigator | 对 Navigator 对象的只读引用。请参数 Navigator 对象。 |
opener | 返回对创建此窗口的窗口的引用。 |
outerHeight | 返回窗口的外部高度,包含工具条与滚动条。 |
outerWidth | 返回窗口的外部宽度,包含工具条与滚动条。 |
pageXOffset | 设置或返回当前页面相对于窗口显示区左上角的 X 位置。 |
pageYOffset | 设置或返回当前页面相对于窗口显示区左上角的 Y 位置。 |
parent | 返回父窗口。 |
screen | 对 Screen 对象的只读引用。请参数 Screen 对象。 |
screenLeft | 返回相对于屏幕窗口的x坐标 |
screenTop | 返回相对于屏幕窗口的y坐标 |
screenX | 返回相对于屏幕窗口的x坐标 |
sessionStorage | 在浏览器中存储 key/value 对。 在关闭窗口或标签页之后将会删除这些数据。 |
screenY | 返回相对于屏幕窗口的y坐标 |
self | 返回对当前窗口的引用。等价于 Window 属性。 |
status | 设置窗口状态栏的文本。 |
top | 返回最顶层的父窗口。 |
方法 | 描述 |
---|---|
alert() | 显示带有一段消息和一个确认按钮的警告框。 |
atob() | 解码一个 base-64 编码的字符串。 |
btoa() | 创建一个 base-64 编码的字符串。 |
blur() | 把键盘焦点从顶层窗口移开。 |
clearInterval() | 取消由 setInterval() 设置的 timeout。 |
clearTimeout() | 取消由 setTimeout() 方法设置的 timeout。 |
close() | 关闭浏览器窗口。 |
confirm() | 显示带有一段消息以及确认按钮和取消按钮的对话框。 |
createPopup() | 创建一个 pop-up 窗口。 |
focus() | 把键盘焦点给予一个窗口。 |
getSelection() | 返回一个 Selection 对象,表示用户选择的文本范围或光标的当前位置。 |
getComputedStyle() | 获取指定元素的 CSS 样式。 |
matchMedia() | 该方法用来检查 media query 语句,它返回一个 MediaQueryList对象。 |
moveBy() | 可相对窗口的当前坐标把它移动指定的像素。 |
moveTo() | 把窗口的左上角移动到一个指定的坐标。 |
open() | 打开一个新的浏览器窗口或查找一个已命名的窗口。 |
print() | 打印当前窗口的内容。 |
prompt() | 显示可提示用户输入的对话框。 |
resizeBy() | 按照指定的像素调整窗口的大小。 |
resizeTo() | 把窗口的大小调整到指定的宽度和高度。 |
scrollBy() | 按照指定的像素值来滚动内容。 |
scrollTo() | 把内容滚动到指定的坐标。 |
setInterval() | 按照指定的周期(以毫秒计)来调用函数或计算表达式。 |
setTimeout() | 在指定的毫秒数后调用函数或计算表达式。 |
stop() | 停止页面载入。 |
postMessage() | 安全地实现跨源通信。 |
navigator 对象
navigator 对象表示浏览器的信息,常用的属性和方法包括
属性 | 说明 |
---|---|
appCodeName | 返回浏览器的代码名 |
appName | 返回浏览器的名称 |
appVersion | 返回浏览器的平台和版本信息 |
cookieEnabled | 返回指明浏览器中是否启用 cookie 的布尔值 |
platform | 返回运行浏览器的操作系统平台 |
userAgent | 返回由客户机发送服务器的user-agent 头部的值 |
方法 | 描述 |
---|---|
javaEnabled() | 指定是否在浏览器中启用Java |
taintEnabled() | 规定浏览器是否启用数据污点(data tainting) |
需注意的是,navigator 的信息可以很容易地被用户修改,所以JavaScript读取的值不一定是正确的。
screen 对象
screen 对象表示屏幕的信息,其常用属性有
属性 | 说明 |
---|---|
availHeight | 返回屏幕的高度(不包括Windows任务栏) |
availWidth | 返回屏幕的宽度(不包括Windows任务栏) |
colorDepth | 返回目标设备或缓冲器上的调色板的比特深度 |
height | 返回屏幕的总高度 |
pixelDepth | 返回屏幕的颜色分辨率(每象素的位数) |
width | 返回屏幕的总宽度 |
location 对象
location 对象包含有关当前 URL 的信息,它是 window 对象的一部分,可通过 window.location.xxx 格式的相关属性对其进行访问。location 对象的常用属性和方法有
属性 | 描述 |
---|---|
hash | 返回一个URL的锚部分 |
host | 返回一个URL的主机名和端口 |
hostname | 返回URL的主机名 |
href | 返回完整的URL |
pathname | 返回的URL路径名。 |
port | 返回一个URL服务器使用的端口号 |
protocol | 返回一个URL协议 |
search | 返回一个URL的查询部分 |
方法 | 说明 |
---|---|
assign() | 载入一个新的文档 |
reload() | 重新载入当前文档 |
replace() | 用新的文档替换当前文档 |
history 对象
history 对象包含用户(在浏览器窗口中)访问过的 URL,它是 window 对象的一部分,可通过 window.history 属性对其进行访问。其常用的属性和方法有
属性 | 说明 |
---|---|
length | 返回历史列表中的网址数 |
方法 | 说明 |
---|---|
back() | 加载 history 列表中的前一个 URL |
forward() | 加载 history 列表中的下一个 URL |
go() | 加载 history 列表中的某个具体页面 |
文档对象模型 DOM
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。DOM是一个树形结构。
节点的概念
根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:
- 整个文档是一个文档节点
- 每个 HTML 元素是元素节点
- HTML 元素内的文本是文本节点
- 每个 HTML 属性是属性节点
- 注释是注释节点
节点树中的节点彼此拥有层级关系,常用父(parent)、子(child)和同胞(sibling)等术语来描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)
- 在节点树中,顶端节点被称为根(root)
- 每个节点都有父节点、除了根(它没有父节点)
- 一个节点可拥有任意数量的子节点
- 同胞是拥有相同父节点的节点
document 对象
document 对象表示当前页面。由于HTML在浏览器中以DOM形式表示为树形结构, document 对象就是整个DOM树的根节点(root)。要查找DOM树的某个节点,需要从 document 对象开始查找。最常用的查找是根据ID和Tag Name。
DOM 节点(元素对象)
DOM 方法是我们可以在节点(HTML 元素)上执行的动作。DOM 属性是我们可以在节点(HTML 元素)设置和修改的值。因为 DOM 节点就是 HTML 元素,所以拥有相应的属性。比较常用的有
方法 | 描述 |
---|---|
getElementById() | 返回带有指定 ID 的元素。 |
getElementsByTagName() | 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。 |
getElementsByClassName() | 返回包含带有指定类名的所有元素的节点列表。 |
querySelector() | 使用 CSS 选择器返回指定的元素 |
querySelectorAll() | 使用 CSS 选择器返回指定的指定元素列表 |
closest() | 向上查找元素,例如 document.querySelector("li").closest("#nav"); |
appendChild() | 把新的子节点添加到指定节点。 |
addEventListener() | 向指定元素添加事件句柄 |
removeChild() | 删除子节点。 |
removeAttribute() | 从元素中删除指定的属性 |
removeEventListener() | 移除由 addEventListener() 方法添加的事件句柄 |
replaceChild() | 替换子节点。 |
insertBefore() | 在指定的子节点前面插入新的子节点。 |
createAttribute() | 创建属性节点。 |
createElement() | 创建元素节点。 |
createTextNode() | 创建文本节点。 |
cloneNode() | 克隆某个元素 |
getAttribute() | 返回指定的属性值。 |
setAttribute() | 把指定属性设置或修改为指定的值。 |
focus() | 设置文档或元素获取焦点 |
hasAttribute() | 如果元素中存在指定的属性返回 true,否则返回false。 |
hasAttributes() | 如果元素有任何属性返回true,否则返回false。 |
hasChildNodes() | 返回一个元素是否具有任何子元素 |
contains | 返回一个元素是否包含有目标子元素,例如document.querySelector("div").contains(document.querySelector("p")); |
hasFocus() | 返回布尔值,检测文档或元素是否获取焦点 |
insertBefore() | 现有的子元素之前插入一个新的子元素 |
属性 | 描述 |
---|---|
attributes | 返回一个元素的属性数组 |
childNodes | 返回元素的一个子节点的数组 |
children | 返回元素的子元素的集合 |
className | 设置或返回元素的class属性 |
clientTop | 表示一个元素的顶部边框的宽度,以像素表示。 |
clientLeft | 表示一个元素的左边框的宽度,以像素表示。 |
dir | 设置或返回一个元素中的文本方向 |
firstElementChild | 返回元素的第一个子元素 |
firstChild | 返回元素的第一个子节点 |
id | 设置或者返回元素的 id |
innerHTML | 设置或者返回元素的内容(不仅是文本,也可以包含HTML结构) |
innerText | 节点所包含的文本内容,不包含隐藏元素的文本 |
lastChild | 返回最后一个子节点 |
lastElementChild | 返回指定元素的最后一个子元素 |
nextSibling | 返回该元素紧跟的一个节点 |
nextElementSibling | 返回指定元素之后的下一个兄弟元素(相同节点树层中的下一个元素节点) |
parentNode | 返回元素的父节点 |
previousSibling | 返回某个元素紧接之前元素 |
previousElementSibling | 返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。 |
style | 设置或返回元素的样式属性 |
tagName | 作为一个字符串返回某个元素的标记名(大写) |
textContent | 设置或返回一个节点和它的文本内容 |
需注意的是,获取的节点、元素在 JS 中均是一个 DOM 对象。另外,严格的讲,这里的DOM节点是指 Element,即元素,但是 DOM 节点实际上是 Node。Node 包括 Element、Comment、CDATA_SECTION 等很多种,以及根节点 Document 类型。但是因为大多数时候我们只关心 Element,也就是实际控制页面结构的 Node,其他类型的 Node 忽略即可。根节点 Document 已经自动绑定为全局变量 document 。
操作 DOM
操作一个DOM节点实际上就是这么几个操作:
- 获取:获取某个或某些特定节点。
- 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
- 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
- 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。
操作 DOM 是通过使用节点的方法或修改节点属性实现
获取
一般使用 getElementById()
、getElementsByTagName()
和 getElementsByClassName()
方法来获取节点。也可以使用 CSS 选择器,通过 querySelector()
和 querySelectorAll()
方法获取节点。这些方法都是节点方法,即从当先节点开始在其子节点中查找。
更新
拿到一个DOM节点后,我们可以对它进行更新。更新方法有两种,一种是修改 innerHTML 属性,这个方式非常强大,不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树。用 innerHTML 时要注意,是否需要写入HTML。如果写入的字符串是通过网络拿到了,要注意对字符编码来避免XSS攻击。第二种是修改 innerText 或 textContent 属性,这样可以自动对字符串进行HTML编码,保证无法设置任何HTML标签。两者的区别在于读取属性时, innerText 不返回隐藏元素的文本,而 textContent 返回所有文
本。
修改CSS也是经常需要的操作。DOM节点的 style 属性对应所有的CSS,可以直接获取或设置。因为CSS允许 font-size 这样的名称,但它并非JavaScript有效的属性名,所以需要在JavaScript中改写为驼峰式命名 fontSize。
添加
当获取了一个节点后,如果这个DOM节点是空的,例如, <div></div> ,那么,直接使用 innerHTML = '<span>child</span>'
就可以修改DOM节点的内容,相当于“插入”了新的DOM节点。如果这个DOM节点不是空的,那就不能这么做,因为 innerHTML 属性会直接替换掉原来的所有子节点。
有两个办法可以插入新的节点。一个是使用 appendChild()
方法 ,把一个子节点(或使用 creatElement()
方法创建的新节点)添加到父节点的最后一个子节点(如果添加的是一个已存在的节点,则相当于移动了节点)。
如果要插入到指定位置,可以使用 parentElement.insertBefore(newElement, referenceElement)
,子节点会插入到 referenceElement 之前。
删除
要删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的 removeChild()
方法把目标节点删掉。注意到删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。
iframe 元素
有一个 DOM 节点与其他的不一样,就是 <iframe>
元素,因为它嵌套了另一个页面,此外最好等待 iframe 加载完成再操作。
父级操作 iframe 内元素
如果需要操作 iframe 内的元素,或需要先获取 iframe 窗口文档进行操作。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body leftmargin="0" topmargin="0" style="background: #fafafa;">
<div leftmargin="0" topmargin="0">
<iframe id='ifr' src="http://111.111.111.111/index.html" frameBorder=0 scrolling=no width="100%" height="440px" style="margin-top:0px; margin:0px; padding:0px"></iframe>
</div>
</body>
<script type="text/javascript">
$(() => {
var iframe = document.getElementById('ifr');
iframe.onload = () => {
var ifrDocument = ifr.contentWindow.document;
// 使用 ifrDocument 作为子页面的 document 进行使用
};
})
</script>
</html>
子级操作 iframe 外元素
获取父级窗口文档
var parentDocument = window.parent.document;
跨域
由于浏览器的安全性, js 是无法跨域操作 iframe 元素的。
事件
HTML 事件是发生在 HTML 元素上的事情,下面是一些常用的 HTML 事件。
事件 | 描述 |
---|---|
onchange | HTML 元素改变 |
onclick | 用户点击 HTML 元素 |
onmouseover | 鼠标指针移动到指定的元素上时发生 |
onmouseout | 用户从一个 HTML 元素上移开鼠标时发生 |
onkeydown | 用户按下键盘按键 |
onload | 浏览器已完成页面的加载 |
事件的触发
HTML 事件触发时通常会调用一个 js 函数或一些执行代码。通常有三种处理方法:
- 使用 HTML 事件属性
<!DOCTYPE html>
<html>
<body>
<h1 onclick="this.innerHTML='Ooops!'">点击文本!</h1>
</body>
</html>
- 使用 js 向 HTML DOM 分配事件
<!DOCTYPE html>
<html>
<body>
<button id="myBtn">点这里</button>
<script>
document.getElementById("myBtn").onclick=function(){displayDate()};
function displayDate(){
document.getElementById("demo").innerHTML=Date();
}
</script>
<p id="demo"></p>
</body>
</html>
- 使用 js 添加事件监听
使用addEventListener()
方法给元素添加事件监听,第一个参数是事件类型,第二个参数是触发后调用的函数,第三个参数指定传递方式。
addEventListener(event, function, useCapture);
<!DOCTYPE html>
<html>
<body>
<button id="myBtn">点这里</button>
<script>
document.getElementById("myBtn").addEventListener("click" ,displayDate);
// 如果要传递参数,则函数名称参数部分可以写成 function(){displayDate(p1,p2);} 即使用匿名函数调用带参数的函数的方式
function displayDate(){
document.getElementById("demo").innerHTML=Date();
}
</script>
<p id="demo"></p>
</body>
</html>
也可以对一个元素添加多个监听以绑定多个事件。
使用 addEventListener()
添加的事件可以使用 removeEventListener()
方法移除。
事件的传递
事件的传递有两种方式:冒泡和捕获。
事件传递定义了元素事件触发的顺序。在冒泡中,内部元素的事件先被触发,然后触发外部元素的事件。在捕获中,外部元素的事件先被触发,然后触发内部元素的事件。addEventListener()
方法可以指定 “useCapture” 参数来设置传递类型。
addEventListener(event, function, useCapture);
默认值为 false,即冒泡传递,当值为 true 时,使用捕获传递。
事件对象
addEventListener()
方法所绑定的回调函数有一个参数(通常为 evt),即触发事件的对象。事件对象有一个属性 target,指向了触发事件的节点。所以在回调函数内部,可以使用 evt.target 来获取触发事件的节点。事件对象还有一些其他的常用的属性和方法
属性 | 描述 |
---|---|
currentTarget | 返回其事件监听器触发该事件的元素(当前元素) |
target | 返回触发此事件的元素(事件的目标节点) |
timeStamp | 返回事件生成的日期和时间 |
type | 返回当前 Event 对象表示的事件名称 |
方法 | 描述 |
---|---|
preventDefault() | 通知浏览器不要执行与事件关联的默认行为,例如 a 标签的跳转(刷新行为) |
stopPropagation() | 不再派发事件(阻止传播) |
另外一些特定的事件对象有特定的属性和方法,例如按键事件(keypress),就会有 keyCode 属性表示按了哪个键。具体的可以查看文档。
表单
HTML 里输入数据大部分都是通过 form 表单完成的,js 也可以处理表单数据。用JavaScript操作表单和操作DOM是类似的,因为表单本身也是DOM树。
获取表单数据
可以通过获取相应控件节点元素的 value 属性获取用户输入的数据
// <input type="text" id="email">
var input = document.getElementById('email');
input.value; // '用户输入的值'
这种方式可以应用于 text 、 password 、 hidden 以及 select 。但是,对于单选框和复选框, value 属性返回的永远是HTML预设的值,而我们需要获得的实际是用户是否“勾上了”选项,所以应该用 checked 判断
// <label><input type="radio" name="weekday" id="monday" value="1">Monday</label>
// <label><input type="radio" name="weekday" id="tuesday" value="2">Tuesday</label>
var mon = document.getElementById('monday');
var tue = document.getElementById('tuesday');
mon.value; // '1'
tue.value; // '2'
mon.checked; // true或者false
tue.checked; // true或者false
设置值和获取值类似,直接设置 value 属性的值或 checked 属性为 true / false 即可。
提交表单
通常 HTML 中使用 submit 类型的 button 按钮来提交表单,使用 js 也有两种方法可以处理表单的提交
- 通过
<form>
元素的submit()
方法提交表单
<!-- html -->
<form id="test-form">
<input type="text" name="test">
<button type="button onclick="doSubmit()">submit</button>
</form>
<script>
function doSubmit() {
var form = document.getElementById('test-form');
// 可以在此修改表单的 input ...
// 提交表单:
form.submit();
}
</script>
这种方式的缺点是扰乱了浏览器对form的正常提交。浏览器默认点击 <button type="submit">
时提交表单,或者用户在最后一个输入框按回车键。
- 响应
<form>
本身的onsubmit
事件,在提交form时作修改
<!-- HTML -->
<form id="test-form" onsubmit="return checkForm()">
<input type="text" name="test">
<button type="submit">Submit</button>
</form>
<script>
function checkForm() {
var form = document.getElementById('test-form');
// 可以在此修改form的input...
// 继续下一步:
return true;
}
</script>
注意要 return true 来告诉浏览器继续提交,如果 return false ,浏览器将不会继续提交 form,这种情况通常对应用户输入有误,提示用户错误信息后终止提交form。
数据处理后传递
在提交表单之前,可以将数据进行处理和校验。
利用 <input type="hidden">
来传递处理后的数据(例如将用户输入的密码进行 md5 加密)
<!-- HTML -->
<form id="login-form" method="post" onsubmit="return checkForm()">
<input type="text" id="username" name="username">
<input type="password" id="input-password">
<input type="hidden" id="md5-password" name="password">
<button type="submit">Submit</button>
</form>
<script>
function checkForm() {
var input_pwd = document.getElementById('input-password');
var md5_pwd = document.getElementById('md5-password');
// 把用户输入的明文变为MD5:
md5_pwd.value = toMD5(input_pwd.value);
// 继续下一步:
return true;
}
</script>
注意到 id 为 md5-password 的 <input>
标记了 name=“password” ,而用户输入的 id 为 input-password 的 <input>
没有 name 属性。没有 name 属性的 <input>
的数据不会被提交。
操作文件
在HTML表单中,可以上传文件的唯一控件就是 <input type="file">
。
注意:当一个表单包含 <input type="file">
时,表单的 enctype 必须指定为 multipart/form-data , method 必须指定为 post ,浏览器才能正确编码并以 multipart/form-data 格式发送表单的数据。
出于安全考虑,浏览器只允许用户点击 <input type="file">
来选择本地文件,用JavaScript对 <input type="file">
的 value 赋值是没有任何效果的。当用户选择了上传某个文件后,JavaScript 也无法获得该文件的真实路径。通常,上传的文件都由后台服务器处理,JavaScript 可以在提交表单时对文件扩展名做检查,以便防止用户上传无效格式的文件。
var f = document.getElementById('test-file-upload');
var filename = f.value; // 'C:\fakepath\test.png'
if (!filename || !(filename.endsWith('.jpg') || filename.endsWith('.png') || filename.endsWith('.gif'))) {
alert('只能上传图片文件');
return false;
}
File API
由于JavaScript对用户上传的文件操作非常有限,尤其是无法读取文件内容,使得很多需要操作文件的网页不得不用Flash这样的第三方插件来实现。随着HTML5的普及,新增的File API允许JavaScript读取文件内容,获得更多的文件信息。HTML5 的 File API 提供了 File 和 FileReader 两个主要对象,可以获得文件信息并读取文件。
var
fileInput = document.getElementById('test-image-file'), // 文件上传
info = document.getElementById('test-file-info'), // 文件信息
preview = document.getElementById('test-image-preview'); // 图像预览
// 监听change事件:
fileInput.addEventListener('change', function () {
// 清除背景图片:
preview.style.backgroundImage = '';
// 检查文件是否选择:
if (!fileInput.value) {
info.innerHTML = '没有选择文件';
return;
}
// 获取File引用:
var file = fileInput.files[0];
// 获取File信息:
info.innerHTML = '文件: ' + file.name + '<br>' +
'大小: ' + file.size + '<br>' +
'修改: ' + file.lastModifiedDate;
if (file.type !== 'image/jpeg' && file.type !== 'image/png' && file.type !== 'image/gif') {
alert('不是有效的图片文件!');
return;
}
// 读取文件:
var reader = new FileReader();
reader.onload = function(e) {
// 获取文件内容
var data = e.target.result; // 'data:image/jpeg;base64,/9j/4AAQSk...(base64编码)...'
// 呈现文件
preview.style.backgroundImage = 'url(' + data + ')';
};
// 以DataURL的形式读取文件:
reader.readAsDataURL(file);
});
这段代码演示了如何通过HTML5的File API读取文件内容。以DataURL的形式读取到的文件是一个字符串,类似于 data:image/jpeg;base64,/9j/4AAQSk…(base64编码)… ,常用于设置图像。如果需要服务器端处理,把字符串 base64, 后面的字符发送给服务器并用Base64解码就可以得到原始文件的二进制内容。
回调
在JavaScript中,浏览器的JavaScript执行引擎在执行JavaScript代码时,总是以单线程模式执行,也就是说,任何时候,JavaScript代码都不可能同时有多于1个线程在执行。所以 js 对于多任务都是进行异步调用。
例如在上个例子中, reader.readAsDataURL(file);
就发起了一个异步操作。reader.onload = function(e) {};
就是其回调函数。当文件读取完毕就执行回调函数进行处理。
数据存储
前端存储数据一般使用 cookie、sessionStorage 和 localStorage。cookie的大小是受限的,且只能保存文本内容。另外每次请求一个新页面cookie都会跟随请求一起发送,这无形中浪费了带宽。cookie的这些限制催生了 sessionStorage 和 localStorage 这两种本地保存方式。
cookie
cookie 会保存在本地,作用范围默认为网站,生命周期可以设置。
创建、存储 cookie
cookie 是以键值对形式存储的
document.cookie = 'key=value';
也可以设置过期时间,默认情况下是关闭时删除。
document.cookie = 'key=value; expires=Thu, 18 Dec 2043 12:00:00 GMT';
也可以使用 path 告诉浏览器cookie的路径,默认属于当前页面
document.cookie = 'key=value;path=/';
读取 cookie
let c = document.cookie;
document.cookie
将以字符串形式返回所有的cookie,类似于url的查询字符。
修改 cookie
修改 cookie 和创建一样,只要 key 一致就能够修改了
删除 cookie
删除 cookie 只要设置 expires
为当期时间即可。
cookie 字符串
document.cookie
属性看起来是一个普通的文本字符串,但其实不是。例如创建新的 cookie 或修改旧有的 cookie 时,并不覆盖其他的 cookie。
应用实例
// 创建、修改、删除 cookie
const setCookie = (key, val, days, path) => {
const exp = new Date(new Date().getTime() + days*24*60*60*1000);
path = path? `;path=${path}` : '';
document.cookie = `${key}=${JSON.stringify(val)};expires=${exp.toGMTString()}${path}`;
}
// 获取 cookie
const getCookie = key => {
let cookies = document.cookie.split(';');
let name = key + '=';
for(let i=0; i<cookies.length; i++){
let cookie = cookies[i].trim();
if (cookie.indexOf(name) === 0) return JSON.parse(cookie.substring(name.length, cookie.length));
}
return '';
}
sessionStorage 和 localStorage
sessionStorage 生存在浏览器窗口中,关闭浏览器窗口就会失效。在同一个窗口(页面)下数据可以共享。
localStorage 的生命周期是永久生效,除非手动删除。在同一个浏览器中,多窗口(页面)可以共享一个 localStorage
需注意的是,同cookie,sessionStorage 和 localStorage 一样只能存储文本字符串,所以如果需要存储数组、对象等,需要使用 JSON.stringify()
和 JSON.parse()
方法进行序列化和反序列化。
存储数据
sessionStorage.setItem(key, value);
localStorage.setItem(key, value);
获取数据
sessionStorage.getItem(key);
localStorage.getItem(key);
删除数据
// 删除目标数据
sessionStorage.removeItem(key);
localStorage.removeItem(key);
// 删除全部数据
sessionStorage.clear();
localStorage.clear();