此篇文章为进阶知识点HTML5的学习,为本人学习时的笔记记录,同时也适合初学者学习。喜欢的友友可以关注一下,后续会补充JavaScript,TypeScript,vue2.0,vue3.0以及uni框架等等一系列的前端学习文章。(强者不喜请绕道,本人内心脆弱,勿喷)
今天我们来学习一下HTML5新增特性剩下的知识点。这一篇的内容较为重要,而且很常用,面试官也常常会考这些点,所以单独写在一篇文章内详细介绍这些知识点,希望友友们看完后有所收获。
刚刚在整理HTML5知识点的时候发现漏了一个比较重要的知识点,当时金山在一面时就有提过这个问题,叫:iframe框架标签。这个也是HTML5新增的点,而且很容易和跨域问题同时出现,所以在介绍剩下的知识点之前先补上iframe的知识点。
iframe事实上是一个HTML标签,是像这样使用的
这是一个非常有用的标签,初次接触的小伙伴这乍一看会觉得这也就只是个普通的标签啊,里面的属性也看不懂,不知道它是用来干嘛的,它又具体有用在哪呢?别急,我们来慢慢了解这东西。
iframe的标签可以做到在网页中嵌套网页。
可能小伙伴们听不太清楚这句话的意思,什么叫网页嵌套网页啊?如果需要多个网页内容那直接写在一个HTML文件里不就好了吗,为什么要网页嵌套网页呢?
嗯,确实没错,如果是要写多点内容的话确实全部代码写在一起就好了,但是实际开发有时候是会需要引用到其他的网页的,如果我需要引用到他人的网页但没有源码的情况下,那就无法实现这个需求了。所以iframe的出现就完美的解决了这个问题!
我们来实战看一下!
这个页面是我在学习TypeScript的时候写的贪吃蛇HTML文件,随手拿来做演示了。像上面的页面内容只存在一个贪吃蛇界面,但是假设我现在需要在该页面增加一个美团官网的主页面,那怎么实现呢?换做HTML5之前也许面对这个要求就束手无策了,但是现在有iframe标签,就可以实现这个需求了,我们来看看是怎么实现的
贪吃蛇
SCORE:0
LEVEL:1
我在里面加上了这条语句
于是界面就能呈现出美团官网的界面了
这个就是iframe标签的功能,可以在我们的网页内嵌套其他的网页内容,有了这个功能就可以使我们的网页功能更多,界面更丰富了。
常见的iframe属性有以下这些
属性 | 作用 |
frameborder | 是否显示边框 |
width | 呈现页面的宽度 |
height | 呈现页面的高度 |
name | 给页面起个名 |
src | 在iframe标签内显示的目标网址 |
scrolling | 是否显示滚动条 |
sandbox | 安全限制 |
其中sandbox这个属性是用来控制iframe的安全性的,其配置有以下这些
配置项 | 作用 |
allow-scripts | 允许iframe运行脚本 |
allow-downloads | 允许iframe下载 |
allow-same-origin | 同域情况下允许发起ajax请求 |
allow-popups | 允许iframe弹出新窗口 |
allow-forms | 允许iframe提交表单 |
就像我设置目标网址为www.baidu.com时会呈现下面的界面,并且提示报错信息为:Refused to display 'https://www.baidu.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
为什么呢?一开始我也不理解,后来仔细看报错消息发现了问题所在:百度对网站做了来源限制,拒绝所有非同域网站将其嵌套。因为允许被嵌套会引发很多安全性问题,比如点击劫持等操作,于是百度干脆直接禁止非同域网站嵌套它,所以就会出现iframe设置src为www.baidu.com时出现拒绝连接的情况了。
但也不是所有的网站都设置了这种操作,比如刚刚的案例,嵌套美团官网就不会出现这种情况。实际一般在做前端开发的时候都是在自己做的页面内进行iframe操作,我们自己是不会设置这种操作的,所以这种问题仅作了解就可以了,在自己的页面嵌套其他子页面是不会出现这种情况的。
众所周知,不同的域之前互相请求资源即为跨域访问,由于同源策略的限制,会导致不同域名之间的访问受限制,iframe原理上是嵌套了另一个网页,这个网页不一定是和当前页面同源的,所以需要做一些操作解决跨域问题:
第一种,通过domain的方式解决跨域:同源策略的判断判断机制是通过判断两个文档的原始域是否相同来判断是否跨域。这意味着只要把这个值设置成一样就可以解决跨域问题了。假设将domain设置为一级域名的值,a页面url为a.demo.com,a页面中iframe引用的b页面url为b.demo.com,于是乎我们只要这么设置就行了
document.domain = 'demo.com'
这样两个网页就算同域了,就可以互相访问了
第二种,使用中间页面:如果我们需要在a页面调用b页面,可以使用一个与b页面同域名但不同路由的c页面作为中间页面,a页面加载c页面,c页面调用b页面的方法,从而实现a页面调用b页面的方法。
其中在b页面新开一个路由,此路由加载一个c页面作为中间页面,c页面的url为b.demo.com/c。c页面只是一个简单的html页面,在window的onload事件上调用了b页面的方法,然后c页面和a页面就符合同源策略了,在a页面调用c页面,c页面在onload的时候会启动b页面,就解决了a调用b的跨域问题了。
第三种,postmessage:window.postMessage方法可以安全地实现跨源通信,写明目标窗口的协议、主机地址或端口就可以发信息给它。具体操作如下
parent.postMessage(
value,
"http://a.demo.com"
);
(b页面发送数据,其数据内容为value)
window.addEventListener("message", function( event ) {
if (event.origin !== 'http://b.demo.com'){
return
}
toggleFullScreen()
});
为a页面的内容,通过window.addEventListener接收来自b页面的数据,出于安全考虑需对event.origin的值进行判断,以确定是否来自正确窗口。这样的操作也可以解决跨域的问题,相互自由的访问了
拖放API是H5的新特性,说白了就是抓取对象以后拖到另一个位置,最最最常见的用处就是在做某些操作时(如登陆账号)用于做验证,来确定这个操作是来自人而不是机器。就像这样
(光是看着就烦) 元素在拖拽前需要对该元素设置draggable属性为true后,才具备被拖拽的功能
draggable = true
元素在拖放时存在三个状态,分别是:开始拖拽 -> 拖拽中 -> 放置指定区域 每个状态都有它对应的API,通过这些API执行一些业务处理,就能做到类似图片滑动验证的功能了(光是看着就烦),那么就来学习一下拖放时的API吧,我们直接上表
事件 | 描述 |
dragstart | 触发拖动时就会执行 |
drag | 开始拖动后拖动元素的过程触发 |
dragend | 拖动结束后触发 |
dragenter | 当拖动的元素进入绑定的元素区域里就会触发 |
dragover | 当拖动的元素在放置的元素区域里移动就会触发 |
drop | 当拖动的元素在放置的元素区域里释放就会触发 |
需要注意的是判断一个元素是否进入指定区域不是根据元素位置来判断,而是通过鼠标位置判断。
制作一个图片滑动验证的功能还是比较简单的,手上没有现成的代码,在此就不给案例演示了。
以前的电脑是没有现在的电脑这么优秀的,随着多核CPU的出现,以前繁琐的任务也能通过多线程解决了。但是!JavaScript是个单线程语言,根本就没办法使用多核CPU,因此就无法充分发挥电脑的性能。所以为了解决这一问题便有了webworker这个东西的出现。
至于JavaScript为什么是单线程语言呢,在讲解webworker之前先简单介绍一下吧
众所周知,JavaScript是可以操作DOM节点的,而操作的DOM节点又是要展示在用户面前的。假设如果JavaScript是多线程语言,会造成什么结果呢?能想象到的是它将可以对同一个DOM节点进行不同的操作,并且是同时。这样一来就会出现这样的情况:当其中一个线程对某一结点进行删除操作,但另一个线程却在进行修改操作,而且我现在就在屏幕前盯着这个DOM节点看,那请问浏览器该听哪个线程的话呢??因此为了避免DOM节点在同一时间呈现不同的状态导致显示异常,JavaScript就被设计成单线程的了(于是就会引申出之后要讲解的同步异步,事件循环等知识点了。。。之后在JavaScript的文章中会细细讲解)。
说回webworker,这玩意儿的作用就是为了给JavaScript创建一个多线程环境。这时候肯定就有人说了:“啊你刚刚不是才说多线程会导致DOM节点多状态显示异常吗?”啊是的没错,所以webworker的多线程任务也不是随便分配的。首先webworker会允许主线程创建一个worker线程,将一些任务(一般是高延迟或者高计算量的任务)分配给worker线程去做,然后主线程继续运行自己的任务(主要是UI的渲染显示与交互等),分配给worker的任务也会同时在后台执行,两者不会相互干扰,由于高延迟或高计算量的任务都被worker线程分担了,并且与主线程同时处理,这样一来主线程的显示就会更流畅,不会被那些高延迟的任务给阻塞导致页面卡顿了。
关于页面渲染显示的任务还是由主线程单线程执行,所以没问题。
答案是和主线程的全局对象不同,worker所在的全局对象并不是window,因此无法使用document,window等对象,因此比如document.getElementByID啊alert() window.history等等这些操作是无法使用的(所以即使想操作dom节点也没门)。but它可以使用location对象navigatior对象。因此如hostname,文件路径,端口号等等一些数据是可以使用的。
1. 主线程向worker发送数据,worker接收数据
由于worker与主线程不在同个上下文环境,因此无法直接通信,如果想在主线程向worker发送消息,则需要通过这样的方式向worker发送数据
let worker = new Worker('脚本名.js');
worker.postMessage('pencil');
这里有个非常重要,需要注意的点:worker不可以读取本地文件,加载的脚本一定得是来自网络
并且对脚本还有同源的要求,即:Worker 线程运行的脚本文件,必须与主线程的脚本文件同源
那么主线程发送完了数据worker怎么接受呢?其实也需要一个特定的监听函数才能获取到来自主线程发送过来的数据,其获取数据的监听函数是这么写的:
this.onmessage('message', function (e) {
let data = e.data;
console.log("来自主线程的数据:",data.msg)
data = "处理完了,还你数据:" + data.msg
this.postMessage(data)
this.close()
});
一般都是处理来自主线程发过来的数据,因此处理完需要通过postMessage还回去,这里又有一个需要注意的点了:worker是不会被主线程关闭的,你执行完想执行的任务就得通过this.close()方法给它关了,不然会很吃性能。
2. worker向主线程发送数据,主线程接收数据
主线程既然能给worker通讯,那自然worker也就能反向给主线程发数据了,worker线程给主线程发数据的方法已经在上个点讲过了,是通过this.postMessage()的方式返回的。那么主线程如何接收来自worker线程的数据呢?请看
worker.onmessage = function (event) {
console.log('这是来自worker线程的数据:' + event.data);
}
至此webworker的知识点就讲得差不多了,这个东西在面对高延迟高计算量的情况时是相当好用的,唯一不太满意的就是不能执行本地js文件,但是浏览器出于安全方面的考虑确实是应该设计成不能访问本地文件的,不然上个网自己的资料都被偷窃干净了,所以现在唯一能访问本地文件的ie浏览器(activeX)也基本被淘汰,没人敢使用了。。。
初次介绍这个东西可能会觉得很陌生,第一个疑问当然是:
webstorage是HTML5新增的Web存储机制,可以使浏览器安全的存储键值对数据,与cookie相比较 webstorage更简单直观,并且可存储的容量更大(只是比起cookie而言,cookie只能存4kb),能达到5MB左右的数据存储。下面我们就来好好了解一下这个东西并且学习怎么使用吧
webstorage可以分为两种,一种叫做localStorage
localStorage可以用于长久保存整个网站的数据,保存的数据没有过期时间,即使浏览器关闭重新打开后数据仍然存在,除非手动去除。
sessionStorage则是用于临时保存同一窗口的数据,比如当浏览器处于打开状态,就可以实现页面的重新加载和恢复。但是该存储区域只在页面会话期间可用,只要浏览器一关闭就全部莫得了。
实际上localStorage和sessionStorage的API是完全一样的,最常见的api有如下几种
localStorage.setItem(key,value); //保存数据
localStorage.getItem(key); //读取数据
localStorage.removeItem(key); //删除单个数据
localStorage.clear(); //删除所有数据
localStorage.key(index); //得到某个索引的key值
1. 跨页面传值
当时我组长面试我的时候问道关于vue组件传值的问题,我憋出了props(父传子),this.$emit(子传父),eventbus(兄弟组件互传),vuex(全局数据共享)后还被继续追问,实在憋不出来答出了webstorage,哈哈。不过现阶段只学习了HTML5和CSS,在面对跨页面传值的时候WebStorage确实是个很好的办法。
2. 恢复(加载)网页数据
个人觉得webstorage最常用的场景是恢复或加载已经存在过的数据,说到底它就是一个新增的web存储机制,具体怎么使用就看实际开发时遇到的情况来吧。
websocket应该是HTML5的重头戏了,这玩意儿内容比起其他的知识点确实是有点多,而且还涉及到服务端的代码。。说实话这个知识点讲起来比用起来还麻烦,但我们还是耐心来学习一下这个知识点吧orz。。。
看到新知识点还是那个问题:WebSocket 是什么呢?它是HTML5新增的一种在单个TCP连接上进行全双工通信的协议。其实在websocket之前HTML的通讯是通过Ajax与服务器进行通信的,即在XmlHttprequest中通过send方式向服务器发一个请求,然后服务器获取到来自浏览器的请求后再返回一个数据给浏览器。那这也没问题啊,本来好端端就能进行通讯为什么还要多一个websocket呢?这不得不提到websocket的优点了
1. 主动推送
之前的Ajax请求虽然可以实现与服务端通讯,但。。这玩意儿是要浏览器主动提请求才能获取数据的。假设,我做了一个后端实时监测数据但需要前端实时更新显示的一个功能(不用假设,实际开发一定会遇到这种需求,已经做过好几个了),那我总不能通过前端轮询去获取数据吧,这样不仅没达到实时的效果,性能还差。因此WebSocket的出现就很好地解决了这个问题:它可以由服务器主动向浏览器发数据。这样一来它存在的意义瞬间拉满了就
2. 可以跨域传数据
跨域问题已经是老生常谈了,Ajax请求也常常会遇到跨域问题而无法正常请求数据,但是websocket它是基于tcp连接的,它可以无视同源策略,让浏览器和任意服务器两者能顺畅丝滑的进行数据交互。
3. 数据格式比较轻量,性能开销小,通信高效
4. 可以发送文本,也可以发送二进制数据
5. 一次连接,持久化通信
细数的话还有不少的优点,不过这些都是涉及到后端和其他方面的知识点了,比如服务端易于实现啊与 HTTP 协议有着良好的兼容性等等,但是这些在前端不会太常出现因此主要了解前面几个常见的优点就可以了。
那么说完它这么多的优点,它有缺点吗?
有。
缺点:不兼容部分浏览器(没错我还是在针对IE)
至于为什么用灰色写那句话,因为我觉得IE几乎没有人在用了吧,所以我也觉得这个缺点问题不大
服务端代码这么写 nodejs部分我讲不太来,而且知识点又很多,急于使用的小伙伴建议直接复制粘贴,执行代码遇到缺少的依赖就用 npm install 去安装,这里就不细讲了。
var app = require('express')();
var server = require('http').Server(app);
var WebSocket = require('ws');
var wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
console.log('server: receive connection.');
ws.on('message', function incoming(message) {
console.log('server: received: %s', message);
});
ws.send('world');
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
app.listen(3000);
客户端代码这么写(先随便贴份代码给着急用的小伙伴复制粘贴)
这篇文章主要讲解一下在前端如何使用它,所以我们来一起学习一下websocket的各个API使用。
1. 首先在使用时需要先声明一个WebSocket对象作为一个构造函数并实例化
let ws = new WebSocket('ws://localhost:8080');
2. webSocket.readyState的四种状态
console.log(ws.readyState);
3. webSocket.onopen
实例对象的onopen
属性,用于指定连接成功后的回调函数。
ws.onopen = function () {
ws.send('Hello Server!');
}
4. webSocket.onclose
实例对象的onclose
属性,用于指定连接关闭后的回调函数。
ws.onclose = function(event) {
let code = event.code;
let reason = event.reason;
let wasClean = event.wasClean;
};
5. webSocket.onmessage
实例对象的onmessage
属性,用于指定收到服务器数据后的回调函数,主要就是通过这个监听函数做到实时获取服务端推送的数据。
ws.onmessage = function(event) {
let data = event.data;
// 处理数据
};
6. webSocket.send()
实例对象的send()
方法用于向服务器发送数据
ws.send('message');
7. webSocket.onerror
实例对象的onerror
属性,用于指定报错时的回调函数
ws.onerror = function(event) {
console.log(event.message)
};
以上就是websocket的全部知识点内容了(大概吧)。websocket是真正的双向平等对话,不仅解决了Ajax跨域请求的问题,还实现了服务器的主动推送,是一个非常好用的通讯技术。这个知识点的使用并不难,难就难在它背后的原理。。如果有兴趣的小伙伴可以去了解一下websocket背后的实现原理,哈哈
以上就是HTML5我总结的全部知识点了,较于HTML这些新特性的增加真的是大大提升了浏览器的上限。这篇文章知识点很多,并且难度较于前几篇文章更高(当然比起前几篇文章我也花了更多的时间来编写),希望各位小伙伴不仅只是看,理解了但不会使用也是等于不会的。。下篇文章我将更新CSS3的一些新特性,然后就可以开始漫长的JavaScript知识点讲解了orz。喜欢的朋友点个关注,溜溜