一、什么是重绘和重排
- 重绘:是一个元素外观的改变所触发的浏览器行为
例如改变visibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。 - 重排是更明显的一种改变,可以理解为渲染树需要重新计算。
重绘不会带来重新布局,并不一定伴随重排。
触发重排的操作
- DOM 的几何属性发上变化
DOM元素的属性变化时,浏览器会重新渲染该部分,而且会涉及到子节点/兄弟节点的重新计算。重排一定会引起浏览器的重绘,代价是很大的。 - DOM 树的结构发生变化
DOM树的增 删 移动 ,会出发重排,浏览器引擎布局过程是从上到下的,从左到右的过程。 所以,如果在body最前面插入一个元素,会导致整个文档的重新渲染,而在其后插入一个元素,则不会影响到前面的元素。 - 获取某些属性
当获取一些属性的时候, 为了取得正确的值,会进行重排。 offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。所以,在多次使用这些值时应进行保存。 - 改变元素样式也会引起重排
减少重排的做法
- 将多次改变样式属性的操作合并成一次操作
var changeDiv = document.getElementById(‘changeDiv’);
changeDiv.style.color = ‘#093′;
changeDiv.style.background = ‘#eee’;
changeDiv.style.height = ’200px’;
合并为以下:
div.changeDiv {
background: #eee;
color: #093;
height: 200px;
}
document.getElementById(‘changeDiv’).className = ‘changeDiv’;
-
将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。
-
在内存中多次操作节点,完成后再添加到文档中去。例如要异步获取表格数据,渲染到页面。可以先取得数据后在内存中构建整个表格的html片段,再一次性添加到文档中去,而不是循环添加每一行。
-
由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发2次重排。
-
在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量。
二、cookie、session、localstorage
1. 存储机制上的区别
https://blog.csdn.net/liuchao_sun/article/details/79634162
localStorage、sessionStorage、cookies都可以用来在浏览器进行数据的缓存存储。sessionStorage、cookies这两个存储随着关闭浏览器或者停止对服务器的访问而会消失,并不会永久的存在。
localStorage不会通过这种方式清除,只有当用户手动清除浏览器缓存才能真正的清除掉数据。
session不是用来存储在客户端,而是存储在整个会话当中(即浏览器访问服务器这个过程,关闭浏览器或停止服务器即断开会话),浏览器关闭,session即清除。
localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储。
在以前,这些缓存存储都是由 cookies 完成的。但是cookies不适合大数据量的存储,它们由每个对服务器的请求来传递,这使得 cookie 速度很慢而且效率也不高。
在 HTML5 中,数据不是由每个服务器请求传递的,而是只有在请求时使用数据。它使在不影响网站性能的情况下存储大量数据成为可能。对于不同的网站,数据存储于不同的区域,并且一个网站只能访问其自身的数据。
即当浏览器打开的tab满足同源策略后,可以在各页面之间进行数据的相互存取操作,这样就可以不用反复进行重复的数据请求操作,如登录权限,获取用户信息等等。
2. cookie
https://blog.csdn.net/fifteen718/article/details/81735596
Cookie是用于维持服务端会话状态的,通常由服务端写入,在后续请求中,供服务端读取。
a. HTTP 请求时,cookie 的使用过程
-
server通过HTTP Response中的"Set-Cookie: header"把cookie发送给client
-
client把cookie通过HTTP Request 中的“Cookie: header”发送给server
-
每次HTTP请求,Cookie都会被发送。(浏览器发送请求的实时,cookie会自动携带在请求头里面)
b. HTTP 请求发送cookie 的条件
1、本地已经缓存有cookies
2、根据请求的URL来匹配cookies的domain、path属性,如果都符合才会发送。
2. cookie、session、localstorage哪些可以跨域
- cookie 可以跨域
利用nginx的方向代理来解决cookie跨域问题,其实是通过“欺骗”浏览器来实现的,通过nginx,我们可以将不同工程的cookie放到nginx域下,通过nginx反向代理就可以取到不同工程写入的cookie。
参考文章:
https://www.cnblogs.com/waters/articles/2869855.html
https://blog.csdn.net/chou_out_man/article/details/80664413
- LocalStorage是不能跨域的,但是,可以借助postMessage和iframe来实现跨域的数据读取。
三、跨域
1. 通过script 的src 属性去访问,不受同源策略的影响吗?
为了既保护用户信息安全,又规避跨域(不同源则为跨域)限制,因此需要使用这种特殊的技术–jsonp.
<scripr>
标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件,而并不要求同源。
jsonp利用script标签具有跨域能力的特点,允许用户通过script的src属性向服务器发送请求,并传递一个函数名作为参数,服务端返回数据时会将这个callback函数作为函数名包裹住从服务端接收的json数据,客户端会按照定义好的方式处理数据。举例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP 实例</title>
</head>
<body>
<div id="list"></div>
<script type="text/javascript">
function callbackFunction(result, methodName) {
var html = '<ul>';
for(var i = 0; i < result.length; i++) {
html += '<li>' + result[i] + '</li>';
}
html += '</ul>';
document.getElementById('list').innerHTML = html;
}
</script>
<script type="text/javascript" src="http://www.myweb.com/demo/jsonp.php?jsoncallback=callbackFunction"></script>
</body>
</html>
以上,callbackFunction函数名作为参数传递给服务器,服务器返回数据形式为:callbackFunction([“list1”,“list2”]),显示结果会按照 callbackFunction()函数来处理。
a. 同源策略
协议、端口号、域名相同
b. 同源策略会限制
- cookie、localStorage、indexDB无法读取,
- DOM无法获得,
- Ajax请求不能发送。
这样做的好处在于保护了用户信息安全。为了保护用户信息安全
2. cors 通过什么方式去跨域
本意:cross origin resource share,跨资源共享
场景:服务端的代码在我的控制范围之内,换言之,后台提供的api代码,我是有权限去操作的。只需要在服务端编写代码,浏览器端不用写任何代码。
这种方式最简单,只需要在服务端设置几个头信息即可。
在node中,设置如下:
res.setHeader('Access-Control-Allow-Origin', "*"); //针对哪个域名可以访问,*表示所有
res.setHeader('Access-Control-Allow-Credentials', true); //是否可以携带cookie
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
四、关于js的一些小问题
1. 原型的概念
用我自己的话说:
原型对象:就是通过原型属性指向的那个对象
原型对象的用途:让所有对象实例共享他所包含的属性和方法
原型链:每一个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例有一个指向原型对象的指针,我们让原型对象等于另一个实例,此时,该原型对象内部则有一个指向另一个原型对象的指针
所有的默认原型对象都是object 的实例,因此默认原型对象的内部指针指向object.prototype,自定义类型继承于object ,所以自定义类型都会继承来自object 的toString valueOf 方法
这是我自己理解的,欢迎指点
创建对象的原型模式:我们创建每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定的所有实例共享的属性和方法。从字面意思理解,那么prototype就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。我们可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个与原型实例中同名的属性,那么我们在实例中创建该属性,该属性将会屏蔽原型中的属性。
只要创建一个新函数,就会根据一组特定的规则为函数创建一个prototype(原型)属性,这个属性指向函数的原型对象
2. 原型链的作用
用于实现JS中的实现继承。
原型链的概念:
原型链作为实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另一个引用继承的属性和方法。了解一下构造函数、原型和实例的关系:每个构造函数都是一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。假如我们让原型对象等于另一个类型的实例,那么此时的原型对象将包含一个指向另一个原型的指针,相应的另一个原型中包含着一个指向另一个构造函数的指针。如此层层递进,就构成了实例与原型的链条。
当函数调用时,需查找和获取的变量和元素都会通过原型链机制一层层的往上搜索在原型对象或继承来的对象中获得。
当函数被创建,就有了作用域,当被调用时,就有了作用域链,当被继承时就有了原型链,当需要获取作用域链或原型链上的变量或值时,就有了闭包。
3. object 的原型指向什么?
null
首先要明确一点,原型链是指对象的原型链,所以原型链上的所有节点都是对象,不能是字符串、数字、布尔值等原始类型。
规范要求原型链必须是有限长度的(从任一节点出发,经过有限步骤后必须到达一个终点。显然也不能有环。)
所有的引用类型默认都继承了object (这个继承通过原型链实现的)
所有函数的默认原型都是 object 的实例,因此默认原型都会包含一个默认指针,指向object.prototype ,这也是所有自定义类型会继承toString valueOf 等默认方法的根本原因
当我们去取object 的原型时,应该返回什么?
即:Object.prototype.proto;
- 如果属性存在,那么返回属性的值。
- 如果属性不存在,那么返回undefined。
- 不管属性存在还是不存在,有可能抛异常。
2和3都不行,因为返回undefined一种解释是原型不存在,但是也相当于原型就是undefined。这样,在原型链上就会存在一个非对象的值。同时,抛出异常也不是一个好的设计
所以最佳选择就是 null ,一方面,你没法访问null的属性,所以起到了终止原型链的作用;另一方面,null在某种意义上也是一种对象,即空对象,因为null一开始就是为表示一个“空”的对象存在的。这样一来,就不会违反“原型链上只能有对象”的约定。
所以,“原型链的终点是null”虽然不是必须不可的,但是却是最合理的。
4. sort 是怎么排序的?
https://www.cnblogs.com/saifei/p/9043821.html
w3school上的原话是:sort() 方法用于对数组的元素进行排序,
arrayObject.sort(sortby)
(记住sort方法排序改变的是原有的数组不生成副本)如果调用该方法时没有使用参数,将按字母顺序
(Ascall编码)对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。
如果要想进行升序或是降序排序的话,要提供比较函数。
- 不传参数,可以直接按照字母顺序排序
- 是按照升序还是降序,指定一个函数
- 按照数组对象中某个属性值进行排序
- 根据参数来确定是升序还是降序
5. 字符串和数组之间的转换
1. 数组转字符串(join)
var a, b,c;
a = new Array(a,b,c,d,e);
b = a.join('-'); //a-b-c-d-e 使用-拼接数组元素
c = a.join(''); //abcde
2. 字符串转数组(split)
var str = 'ab+c+de';
var a = str.split('+'); // [ab, c, de]
var b = str.split(''); //[a, b, +, c, +, d, e]
6. startwith的用法
这个方法来自ES6 里
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。(从左往右)
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。 (从右往左)
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
这三个方法都支持第二个参数,表示开始搜索的位置:
var s= 'Hello world!'
s.startWith('world', 6) //true
s.endsWith('Hello', 5) //true
s.includes('Hello', 6) //false
使用第二个参数时,endsWith 的行为与其他两个方法有所不同。它针对前n 个字符,而其他方法针对从第n 个位置到字符串结束位置之间的字符
7. 使用正则
1. 抽离字符串中的字符
var a = "jknsaj454554afaFa4551gas5g"
var c = /\d/g;
console.log(a.replace(/\d/g, ''))//jknsajafaFagasg
console.log(a.replace(/[0-9]/g, ''))//jknsajafaFagasg
2. 抽离字符串中的数字
console.log(a.replace(/[^0-9]/g, ''))//45455445515
console.log(a.replace(/[^\d]/g, ''))//45455445515
五、协议
1. DNS的作用是什么?
DNS(Domain Name System) 域名系统。
作用是域名解析
它会在你上网输入网址后,把它转换成IP,然后去访问对方服务器,没有它,你想上百度就要记住百度的IP,上163就要记住163的IP,有了DNS的处理,你只需要记住对应网站的域名–也就是网址就可以了。
2. tcp三次握手
SYN:同步序列编号,是tcp建立连接时的握手信号
ACK:确认字符
ESTABLISHED:已建立的状态
- 客户端首先发送一个SYN 给服务器,表明发送一个标有SYN 的数据包
- 服务端接收到SYN 并进入到SYN_RCVD 状态,同时向客户端发送标有SYN/ACK 的数据包
- 客户端接收到SYN/ACK 后进入到ESTABLISHED状态,并向服务器端发送标有ACK 的数据包
3. tcp 为什么需要三次握手?
因为第一次表示是客户端发到服务端建立了连接,第二次表示服务端到客户端建立了连接,每次连接时独立的,需要确认双方都建立连接成功后才能进行数据的传输。
4. 状态码
详情:https://blog.csdn.net/Welkin_qing/article/details/88751801#3_HTTP_Status_code_Status_text_65
- 1xx: 表示临时回应
- 2xx:表示成功
- 200
- 3xx:表示请求目标有变化
- 301
- 302
- 4xx:客户端错误
- 404
- 5xx:服务端错误
六、css
1. icon-font 字体图标以及用法
2. 响应式布局
- 设置meta标签
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="HandheldFriendly" content="true">
- 通过媒体查询设置样式media query
media query 是响应式设计的核心,它能够和浏览器进行沟通,告诉浏览器页面如何呈现,假如一个终端的分辨率小于980px,那么可以这样写
@media screen and (max-width:980px){
#head { … }
#content { … }
#footer { … }
} /*这里面的样式会覆盖掉之前所定义的样式。*/
3. 前端性能优化方案
1、尽量减少 HTTP 请求
2、使用浏览器缓存
3、使用压缩组件
4、图片、JS 的预载入
5、将脚本放在底部
6、将样式文件放在页面顶部
7、使用外部的 JS 和 CSS
8、精简代码
(1) 减少 http 请求次数:CSS Sprites, JS、CSS 源码压缩、图片大小控制合适;网页
Gzip,CDN 托管,data 缓存 ,图片服务器。
(2) 前端模板 JS+数据,减少由于 HTML 标签导致的带宽浪费,前端用变量保存 AJAX
请求结果,每次操作本地变量,不用请求,减少请求次数
(3) 用 innerHTML 代替 DOM 操作,减少 DOM 操作次数,优化 javascript 性能。
(4) 当需要设置的样式很多时设置 className 而不是直接操作 style。
(5) 少用全局变量、缓存 DOM 节点查找的结果。减少 IO 读取操作。
(6) 避免使用 CSS Expression(css 表达式)又称 Dynamic properties(动态属性)。
(7) 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。
(8) 避免在页面的主体布局中使用 table,table 要等其中的内容完全下载之后才会显
示出来,显示比 div+css 布局慢。
七、vue
1. vue的指令
指令的职责是,当表达式的值改变时,产生的影响作用于DOM(v-for是例外情况)
- v-html 双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令
内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译 。如果试图使用 v-html 组合模板,可以重新考虑是否通过使用组件来替代。
<body>
<div id="app">
{{ message }}
<p v-html="htmlmessage"></p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
htmlmessage: '<div style="width:100px;height:100px;border:1px solid black"></div>'
}
})
</script>
</body>
因为我是这样写的,所以结果是在p 标签里有一个div盒子,也就是p的内容被替换成了一个html 标签
注意:
- 在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html,永不用在用户提交的内容上。
- 在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局
-
v-text
用于解决插值表达式({{}})闪烁的问题
可以看到结果,插值表达式上并没有指定标签,而v-text 指定了标签,同时也解决了插值表达式闪烁的问题 -
v-show
根据表达式之真假值,切换元素的 display CSS 属性,当条件变化时该指令触发过渡效果
元素会被渲染,只是简单的进行css 样式切换(可以频繁切换)
我有设置改变我的条件
0/false 元素会被隐藏
1/true 元素会出现
字符串的false 元素也会出现
-
v-if
会根据条件进行渲染不渲染(true 渲染dom,false不渲染dom)
0/false 元素不渲染
1/true 元素会被渲染
字符串的false 元素也会被渲染
还有 v-else v-else-if -
v-for
基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression ,为当前遍历的元素提供别名
<div v-for="item in items">
{{ item.text }}
</div>
注意:当和 v-if 一起使用时,v-for 的优先级比 v-if 更高。详见列表渲染教程
- v-on(简写@)注册事件(用于监听dom事件)
on 的函数写在methods 里
绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。
用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。
在监听原生 DOM 事件时,方法以事件为唯一的参数。如果使用内联语句,语句可以访问一个 $event 属性:v-on:click=“handle(‘ok’, $event)”。
<div id="app">
{{ message }}
<p v-text="message"></p>
<div v-if="message" style="width:100px;height:100px;border:1px solid black"></div>
<!-- <p v-html="htmlmessage"></p> -->
<button @click="todoThis">button</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'false',
htmlmessage: '<div style="width:100px;height:100px;border:1px solid black"></div>'
},
methods: {
todoThis(){
alert('hello')
}
},
})
</script>
- v-bind 属性绑定(缩写:)
绑定class(常常和data,computed里的数据一起用)
v-bind不触发dom事件,也就是将上边的代码改成v-bind 再点击不会触发函数
通常用来父子传值的时候使用
<div id="app">
{{ message }}
<p v-text="message"></p>
<div :class="{box:message}" style="width:100px;height:100px;border:1px solid black"></div>
<!-- <p v-html="htmlmessage"></p> -->
<!-- <button :click="todoThis">button</button> -->
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'false',
htmlmessage: '<div style="width:100px;height:100px;border:1px solid black"></div>'
},
methods: {
todoThis(){
alert('hello')
}
},
})
</script>
8. v-model
表单控件双向绑定
<input>
<select>
<textarea>
- components
- v-slot
限用于
<template>
- 组件 (对于一个单独的带 prop 的默认插槽)
提供具名插槽或需要接收 prop 的插槽。
- v-pre
不解析这个节点的内容,跳过编译
<span v-pre>{{hhhhhhhhhhhhh}}</span>
- v-cloak
这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如
[v-cloak] { display: none }
一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
用我自己的话说:用于{[}} 插值表达式使用比较多,若都是用v-text 比较麻烦。则在vue 管理的模板入口节点作用v-cloak 指令,有v-cloak{display:none}时,浏览器在解析的过程中,发现具有v-cloak 的属性隐藏不显示,所以就看不见闪烁的问题,当vue 解析替换完成之后,vue会自动把v-cloak 样式移出
- v-once
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
下面的那个0 就是使用v-once 绑定的元素
2. vue 组件的生命周期
https://www.cnblogs.com/webbest/p/6722780.html
vue 使用component定义组件
3. 生命周期函数(钩子函数)
一共分为8个阶段
- 创建前后
- 在beforeCreated阶段,vue实例的挂载元素$el和数据对象data都 为undefined,还未初始化。
- 在created阶段,vue实例的数据对象data有了, $el还没有。
- 载入前/后
- 在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂 载之前为虚拟的dom节点,data.message还未替换
- 在mounted阶段,vue实 例挂载完成,data.message成功渲染。
- 更新前/后
- 当data变化时,会触发beforeUpdate和updated方法
- 销毁前/后
- 在执行destroy方法后,对data的改变不会再触发周期函数,说明 此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
4. 父子组件相互通信
https://blog.csdn.net/Welkin_qing/article/details/88572264#3__298
- 父向子
prop - 子向父
($emit)
webpack
基于整个项目进行构建得
gulp 是基于task 任务构建的
1.什么是webpack
是前端的一个构建工具,是基于node.js 开发的前端工具
2. webpack能干什么?
- 网页加载速度慢,因为要发起很多二次请求
- 要处理错综复杂的关系
SSR
https://www.jianshu.com/p/fcb98533bc18
前端前沿技术
https://blog.csdn.net/itwangyang520/article/details/81150795
前端离线方案(ServiceWorker)
https://www.jianshu.com/p/2fde65f0182d
xss sql
- XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。
- 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。 [1] 比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.
SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。
根据相关技术原理,SQL注入可以分为平台层注入和代码层注入。前者由不安全的数据库配置或数据库平台的漏洞所致;后者主要是由于程序员对输入未进行细致地过滤,从而执行了非法的数据查询。基于此,SQL注入的产生原因通常表现在以下几方面:①不当的类型处理;②不安全的数据库配置;③不合理的查询集处理;④不当的错误处理;⑤转义字符处理不合适;⑥多个提交处理不当。