HTML:
通常来说,一段HTML代码,最终在浏览器中会生成一堆DOM节点树,这不一定是最终的结果,还可以:
1、通过css样式,例如display:none来让其中某个节点消失
2、通过js代码1操作DOM,例如使用document.getElementId获取到某个节点元素,然后再通过设置.inneHTML来改变元素的内容
CSS:
这个主要是给HTML元素添加样式,可通过几个方式匹配:
1、DOM元素匹配:例如p{color:red}会让所有<p>元素的文字变成红色
2、class匹配:类的匹配,例如.xxxx{}
3、id匹配:id标识符匹配,例如#xxxx{}
javascript:html是简单的页面静态信息,而javascript可以在网页上实现复杂的功能
常用这个做:1、处理事件(点击、输入等)
2、改变html内容、位置和样式
3、处理Http请求、各种业务逻辑的执行
4、很多其他的事情也可以做
这个是单线程的,更多因为对页面交互的同步处理,作为浏览器脚本语言,javascript的主要用途是与用户互动,以及操作DOM,若是多线程会导致严重的同步问题
页面渲染:浏览器的渲染机制:
一次浏览器的页面渲染过程中,浏览器会解析三种文件: -解析HTML/SVG/XHTML ,会生成一个DOM结构树
-解析css,会生成一个css规则树
-解析js,可通过DOM API和CSS API来操作DOM结构树和CSS规则树
CSS规则树与DOM结构树结合,最终生成一个Render树(即最终呈现的页面,例如其中会移除DOM结构树中匹配到CSS里面display:none的DOM节点)。 一般来说浏览器绘制页面的过程是:
1、计算CSS规则树
2、生成Render树
3、计算各个节点的大小/position/z-index(消耗最大)
4、绘制
页面的局部刷新: 目前来说前端一般分为两种方式: 1、绑定映射表方式(适用于绑定变量的元素比较少时) 原因:绑定变量的元素很多,每次要更新某块的页面数据,可能会需要保存很多的元素映射,同时需要调用很多很多的上述方法
2、直接替换内容方式(相反) 1中是经常使用到的一种方式:var a = document.getElementById("a);
这里拿到了id为a的一个元素映射,在更新内容、处理节点的时候就可以用这个映射来直接操作,如:
//更改元素里面内容
a.innerHTML = "<p>测试</p>";
//2、插入一个<a>元素
a.appendChild(document.createElement('a'));
//3、删除第一个元素,在这里是前面的<p>测试</p>
a.removeChild(a.firstChild); 2中直接替换内容方式
每次更新页面数据和状态,可通过innerHTTML方法来用新的HTML String替换旧的,简单而言就是将各种节点使用字符串的方式拼接起来
例://1、更改元素里面内容
a.innerHTML = "<p>测试</p>";
//2、插入一个<a>元素
a.innerHTML = "<p>测试</p><a></a>"
//3、删除第一个元素,在这里是前面的<p>测试</p>
a.innerHTML = "<a></a>"
不好处是若是更新的节点范围比较大,需要我们替换掉很大一片的HTML String。这样会导致更多的浏览器计算 页面回流、重绘
浏览器绘制页面的过程是:1、计算css规则树 =》2、生成Render树 =》3、计算各个节点的大小/position/z-index =》4.绘制
使用DOM API 和 CSS API的时候,通常会触发浏览器的两种操作:Repaint(重绘)和 Reflow(回流):
Repoint:页面部分重画,通常不涉及尺寸的改变,常见于颜色的变化。只触发过程4
Reflow:意味着节点需要重新计算和绘制,常见于尺寸的改变.会触发3和4过程。
浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成Reflow后,浏览器会重新绘制受影响的部分到屏幕中。
回流的花销更render tree有多少节点需要重新构建有关系,这也是为什么前面说使用innerHTML会导致更多的开销,所以到底使使用绑定映射表方式,还是使用直接替换内容方式,都是需要具体问题具体分析
事件驱动:是前端开发中最容易理解的编码方式,例如写一个提交表单的页面,用事件驱动的方式来写的话,会是这样一个过程
1、编写静态页面
<form>
Name:
<p id="name-value"></p>
<input type="text" name="name" id="name-input" />
Email:
<p id="email-value"></p>
<input type="email" name="email" id="email-input" />
<input type="submit" />
</form>
2、给对应的元素绑定对应的事件,例如给input输入框绑定一个输入事件
var nameInputEl = document.getElementById("name-input");
var emailInputEl = document.getElementById("email-input");// 监听输入事件,此时 updateValue 函数未定义
nameInputEl.addEventListener("input", updateNameValue);
emailInputEl.addEventListener("input", updateEmailValue);
3、事件触发时,更新页面内容
var nameValueEl = document.getElementById("name-value");
var emailValueEl = document.getElementById("email-value");
// 定义 updateValue 函数,用来更新页面内容
function updateNameValue(e) {
nameValueEl.innerText = e.srcElement.value;
}
function updateEmailValue(e) {
emailValueEl.innerText = e.srcElement.value;
}
前端框架:
Vue:
数据绑定的实现:使用双大括号绑定变量的方式, 过程: 1、解析语法生成AST
2、根据AST结果生成DOM
3、将数据绑定更新至模板
虚拟DOM:
大概过程:(1)用JS对象模拟DOM树,得到一颗虚拟DOM树
(2)当页面数据变更时,生成新的虚拟DOM树,比较新旧两颗虚拟DOM树的差异
(3)把差异应用到真正的DOM树上
用虚拟DOM的原因:一个DOM中包含太多太多属性、元素、事件对象,但这些并不会全部用到,通常包括节点内容、元素位置、样式、节点的添加删除等方式,我们通过用js对象表示DOM元素的方式,大大降低了比较差异的计算量
XSS漏洞:模板引擎还可以预防下XSS相关漏洞,而XSS的整个攻击过程大概为:
1、通常页面中包含的用户输入内容都在固定的容器或者属性内,以文本的形式展示
2、攻击者利用这些页面的用户输入片段,拼接特殊格式的字符串,突破原有位置的限制,形成了代码片段
3、攻击者1通过在目标网站上注入脚本,使之在用户的浏览器上运行,从而引发潜在风险
避免XSS的方法之一主要是将用户所提供的内容过滤,而大多数模板引擎会自带HTML转义功能。在Vue中,默认的数据绑定方式(双大括号、v-bind等)会进行HTML转义,将数据解释为普通文本,而非HTML代码
Vue简介
模板引擎都做了什么?本就是一个div,经过AST生成一个对象,最终还是生成一个div,多余的步骤吗?不是的,这个过程中我们可以实现一些功能:
排除无效的DOM元素,并在构建过程可进行报错
使用自定义组件的时候,可匹配出来
可方便地实现数据绑定、事件绑定等,具备自动更新页面功能
为虚拟DOM Diff过程打下铺垫
HTML转义(预防XSS漏洞)