一个页面从加载到完成,首先生成DOM树,而后根据DOM节点的几何属性生成render树(渲染树),当渲染树构建完成,页面开始根据DOM树布局,渲染树也会根据设置的样式渲染节点javascript
回流: 当咱们删除或修改元素高度时,页面会从新布局,DOM树发生变化,引发渲染树从新渲染,这个过程叫作回流(回流必定形成重绘)css
重绘: 当修改元素的颜色,渲染树会根据新规则从新渲染,这个过程叫作重绘(重绘不必定形成回流)html
如何减小回流前端
function addDivs(element) {
var div;
// Creates a new empty DocumentFragment.
var fragment = document.createDocumentFragment();
for (var i = 0; i < 20; i ++) {
div = document.createElement('a');
div.innerHTML = 'Heya!';
fragment.appendChild(div);
}
element.appendChild(fragment);
}
复制代码
------ html-------
<ul>
<li>Coffee</li>
<li>Milk</li>
<li>Soda</li>
</ul>
复制代码
let lis = document.getElementsByTagName('li')
for (let i=0; i<lis.length; i++) {
lis[i].index = i
}
document.getElementsByTagName('ul')[0].addEventListener('click', handle, false)
function handle (event) {
if (event.target.tagName === 'LI') {
console.log(event.target.index)
}
}
复制代码
$('li').click(function () {
console.log($(this).index())
})
复制代码
点我ԅ(¯﹃¯ԅ)vue
fixed、relative、absolutejava
相对定位和固定定位,都会使块级元素产生BFC,下面经过步骤检测一下node
设置父元素为固定定位,不设置高度,内部box设置高度和宽度,根据BFC内部box垂直排列的特征,效果以下jquery
<div class="sj">
<div>1</div>
</div>
复制代码
.sj{
position: fixed;
top: 0;
left: 0;
width: 200px;
background-color: #ccc;
}
.sj>div{
height: 20px;
width: 100px;
background-color: #2db7f5;
}
复制代码
.sj>div{
height: 20px;
width: 100px;
position: absolute;
background-color: #2db7f5;
}
复制代码
伪类:向某些选择器设置特殊效果,用于选择器选择不到的元素webpack
伪元素:向某些选择器添加特殊效果web
BFC是一个独立的块级渲染容器,拥有本身的渲染规则,不受外部影响,不影响外部
特征
产生条件
做用
1. 父元素设置伪类:clear:both + zoom:1
设置zomm为了兼容IE
<div class="parent1 clearFloat">
<div class="left"></div>
</div>
<div class="parent2"></div>
.parent1{
border: 1px solid red;
}
.parent2{
height: 100px;
border: 1px solid blue;
}
.left{
width: 200px;
height: 200px;
background-color: #5cadff;
float: left;
}
.clearfloat::after{
display: block;
clear: both;
content: '';
visibility: hidden;
height: 0;
}
.clearfloat {
zoom: 1
}
复制代码
2. 结尾处添加空白标签:claer:both
<div class="parent1">
<div class="left"></div>
<div class="clearfloat"></div>
</div>
<div class="parent2"></div>
.clearfloat{
clear: both;
}
复制代码
3. 父元素产生BFC
BFC内浮动元素高度计算在内
方法1、定位 + transform
.parent{
height: 500px;
width: 500px;
border: 1px solid red;
position: relative;
}
.child{
height: 80px;
width: 80px;
background-color: #515A6E;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
复制代码
方法2、margin + transform
.parent{
height: 500px;
width: 500px;
border: 1px solid red;
}
.child{
height: 80px;
width: 80px;
background-color: #515A6E;
margin: 50% 0 0 50%;
transform: translate(-50%, -50%);
}
复制代码
方法3、定位 + 负margin
.parent{
height: 500px;
width: 500px;
border: 1px solid red;
position: relative;
}
.child{
height: 80px;
width: 80px;
background-color: #515A6E;
position: absolute;
top: 50%;
left: 50%;
margin: -40px 0 0 -40px;
}
复制代码
方法4、flex
.parent{
height: 500px;
width: 500px;
border: 1px solid red;
display: flex;
align-items: center;
justify-content: center;
}
.child{
height: 80px;
width: 80px;
background-color: #515A6E;
}
复制代码
方法5、table-cell
.parent{
height: 500px;
width: 500px;
border: 1px solid red;
display: table-cell;
text-align: center;
vertical-align: middle;
}
.child{
display: inline-block;
height: 80px;
width: 80px;
background-color: #515A6E;
}
复制代码
标准盒子模型
width = content
IE盒子模型
width = border + padding + content
块级元素
行内元素
行内置换元素
浏览器依据元素的标签和属性来决定元素的具体显示内容
img、input、textarea、select、object属于行内置换元素, 具备块级元素的特征(除宽度外)
元素脱离文档流,但由于没有设置属性致使没法具体定位,紧跟在上个元素以后,但下个元素排列时会忽略此元素
<div id="a">
<span class="b">222</span> // 红色
</div>
div span{
color: blue;
}
#a {
color: red;
}
复制代码
!important(10000) > 内联样式(1000) > id(100) > class|伪类|属性选择(10) > 标签|伪元素(1) > 通配符(0) > 继承(无)
假设只走一个台阶,有1种走法;两个台阶,2中走法,三个台阶,3种走法;四个台阶,5种走法...
1->1; 2->2; 3->3; 4->5...能够看出此问题是斐波那契数列,即下个值是前两个值的和
公式为:f(n) = f(n-1) + f(n-2)
方法1、遍历相加
function test (num) {
let num1 = 1, num2 = 2, res = 0
for (let i=2; i<num; i++) {
res = num1 + num2
num1 = num2
num2 = res
}
return res
}
复制代码
方法2、递归 (不推荐)
function test (num) {
if (num === 1)
return 1
else if (num === 2)
return 2
else
return test(num-1) + test(num-2)
}
复制代码
闭包
使用场景
function Cat(){}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
复制代码
function Cat(name){
Animal.call(this)
this.name = name || 'Tom';
}
var cat = new Cat()
复制代码
let newArr = JSON.Parse(JSON.Stringify(oldArr))
复制代码
扩展运算符
<!-- 仅对包含基本数据类型的数组有效 -->
let newArr = [...oldArr]
复制代码
function deepClone (obj) {
let newObj = obj instanceof Array ? [] : {}
for(var i in obj){
newObj[i] = typeof obj[i] == 'object' ? deepClone(obj[i]) : obj[i]
}
return newObj
}
复制代码
function test (num) {
let arr1 = [], arr2 = [],arr = [] // arr1保存小数前, arr2保存小数后
arr = num.toString().split('.')
arr2 = arr[1] ? [...arr[1]] : [] // 判断是否存在小数,并将每项转为数组元素
arr1 = [...arr[0]]
let newArr1 = arr1.map((item, index) => arr1.length === (index+1) && (index+1)%3 === 0 ? item : (index+1)%3 === 0 ? item+',' : item)
let newArr2 = arr2.map((item, index) => arr2.length === (index+1) && (index+1)%3 === 0 ? item : (index+1)%3 === 0 ? item+',' : item) // 数组为空则map()不检测
newArr2.unshift('.')
console.log(newArr1.concat(newArr2).join(''))
}
test(123456789.123)
复制代码
快速排序采用分治法的思想,将一个复杂问题分为两个或多个子问题,直到子问题简单到能够直接求解,那么子问题的解的组合即是原问题的解
function quickSort (arr) {
if (arr.length <= 1) return arr;
//取中间位置的数据做为基准值,并从原数组中删除该基准值
let jzIndex = Math.floor(arr.length/2) // 获取基准值下标
let jzNum = arr.splice(jzIndex, 1) // 删除并获取基准值
let leftArr = [], rightArr = [] // 分别保存小于和大于基准值的数据
arr.forEach(item => {
if (item < jzNum[0]) {
leftArr.push(item)
}
if (item >= jzNum[0]) {
rightArr.push(item)
}
})
//concat()链接两个数组
return quickSort(leftArr).concat(jzNum, quickSort(rightArr))
}
console.log(quickSort([10,5,15,2,4]))
复制代码
防抖: 任务频繁触发状况下,只有两次任务间隔超过指定时间,才会执行。若还未超过却又一次触发,则时间从新开始计算
// 防抖函数
function debounce (fn, time) {
// 新建一个变量保存定时器
let timeout = null;
return function () {
// 每次用户点击、输入时,清空上一个定时器
clearTimeout(timeout)
timeout = setTimeout(() => {
fn.call(this, arguments)
}, time)
}
}
// 处理函数
function handler () {
console.log('防抖成功!')
}
// 触发
debounce(handler, 1000)
复制代码
节流: 频繁触发任务,任务按照必定时间间隔进行执行
// 节流函数
function throttle (fn, time) {
// 利用闭包保存是否可执行的变量
let canRun = true
return function () {
// 若是为false,则终止函数执行
if (!canRun) return;
// 执行前将变量设为false
canRun = false
setTimeout(() => {
fn.call(this, arguments)
canRun = true
}, time)
}
}
// 处理函数
function handler () {
console.log('节流成功!')
}
// 触发
throttle(throttle, 1000)
复制代码
1. 什么是Promise?
2. Promise优缺点?
优势:
缺点:
3. Promise的方法有哪些?做用都是什么?
Promise.prototype.then()
Promise 实例添加状态改变时的回调函数,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。所以能够采用链式写法,即then方法后面再调用另外一个then方法。
Promise.prototype.catch()
.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
Promise.prototype.finally()
不管Promise最后状态如何,都会执行finally内的函数,ES2018引入
Promise.all()
多个Promise同时执行,若所有成功,则以数组形式返回执行结果;如有一个是rejected,则只返回rejected的结果
Promise.race()
多个Promise同时执行,返回最早结束Promise执行任务的结果,不管成功或失败
Promise.resolve()
返回一个新的 Promise 实例,该实例的状态为resolve
Promise.reject()
返回一个新的 Promise 实例,该实例的状态为rejected
4. promise如何使用?
5. 手写一个promise
// 定义Promise构造函数
function Promise (exector) {
let self = this;
this.value = undefined;
this.reason = undefined;
// 定义Promise的状态
this.status = 'pending'
// 存储then中成功的回调函数
this.onResolvedCallbacks = [];
// 存储then中失败的回调函数
this.onRejectedCallbacks = [];
function resolve (value) {
if (self.status === 'pending') {
self.value = value
self.status = 'resolved'
self.onResolvedCallbacks.forEach(fn => fn())
}
}
function reject (reason) {
if (self.status === 'pending') {
self.reason = reason
self.status = 'rejected'
self.onRejectedCallbacks.forEach(fn => fn())
}
}
// 异常处理
try{
exector(resolve, reject)
}catch (e) {
reject(e)
}
}
// 在Promise原型上定义then方法,参数为成功和失败的回调
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
if (this.status === 'resolved') {
onFulfilled(self.value)
}
if (this.status === 'rejected') {
onRejected(self.reason);
}
if (this.status === 'pending') {
this.onResolvedCallbacks.push(() => {
onFulfilled(self.value)
})
this.onRejectedCallbacks.push(() => {
onRejected(self.reason)
})
}
}
let promise = new Promise((resolve, reject)=> {
setTimeout(() => {
resolve('success')
}, 1000)
})
promise.then(data => {
console.log(data)
}, err => {
console.log(err)
})
复制代码
webpack是模块打包工具,对js模块和扩展语言进行打包供浏览器识别运行
Grunt和Gulp属于任务流工具Tast Runner
webpack属于模块打包工具 Bundler
方法1、经过父组件通讯
此方法须要保证兄弟组件A、B都在同一个父组件下;
父组件经过接受子组件A传递过来的事件消息,并调用子组件B
子组件A
this.$emit('transmit', 'msg')
复制代码
父组件
<ChildA @transmit="transmit"></ChildA>
<ChildB :msg="msg"></ChildB>
transmit (data) => {
this.msg = data
}
复制代码
子组件B、须要使用watch来监听父组件props穿过来的数据变化
watch (new, old) {
数据操做...
}
复制代码
方法2、eventBus
经过建立Bus.js注册一个全局实例,通信组件经过调用实例的方法达到通信目的
// eventBus 共享vue实例,用于兄弟组件数据传递
import Vue from 'vue'
const Bus = new Vue({})
export {Bus}
复制代码
import {Bus} from './Bus.js'
Bus.$emit('transmit', 'msg')
复制代码
import {Bus} from './Bus.js'
mounted () {
Bus.$on('transmit', (data) => {
操做...
})
}
因为$on事件没法主动销毁,因此须要根据业务手动进行销毁
在组件销毁前方法中销毁
beforeDestory () {
Bus.$off('transmit')
}
或者在使用前进行销毁
mounted () {
Bus.$off('transmit')
Bus.$on('transmit', (data) => {
操做...
})
}
复制代码
Vue Router 是路由管理器,能够改变url而不向服务器发送请求,页面无需刷新
有hash和history两种路由模式
hash模式
history模式
动态路由匹配中会复用同一组件,这就致使再次访问组件不被从新渲染,声明周期钩子不会执行,这就须要咱们用watch去监听路由的变化
watch: {
$route(to, from) {
······
}
}
复制代码
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
Vuex包含五个属性:state、getter、mutation、action、module
当组件进行数据修改的时候,经过调用dispatch来触发actions里面的方法,actions里每一个方法都有commit方法,经过执行commit方法来触发mutation里的方法进行数据修改,因为mutation里每一个函数都有一个state参数,进而可对state进行修改,当数据修改完毕后,会传导给页面。页面的数据也会发生改变。
watch用来监听并响应数据的变化
data () {
return {
age: 20,
obj: {
age: 24
},
arr: [1,2,3]
}
}
复制代码
1. 监听基本类型
watch: {
age (newd, oldd) {
...
}
}
复制代码
2. 监听对象
watch: {
obj: {
handler (newd, oldd) {
...
},
deep: true, // 开启深度监听
immediate: true // 首次即执行
}
}
复制代码
3. 监听对象某个属性
*** 采用字符串
watch: {
'obj.age': {
handler (newd, oldd) {
...
}
}
}
*** 利用computed计算属性
computed: {
age () {
return this.obj.age
}
}
watch: {
age (newd, oldd) {
...
}
// 也可写为
age: {
handler (newd, oldd) {
...
}
}
}
复制代码
异步更新队列
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的全部数据改变。若是同一个 watcher被屡次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免没必要要的计算和 DOM 操做是很是重要的。而后,在下一个的事件循环“tick”中,Vue刷新队列并执行实际 (已去重的) 工做。Vue 在内部尝试对异步队列使用原生的Promise.then和MessageChannel,若是执行环境不支持,会采用 setTimeout(fn, 0) 代替。
例如,当你设置 vm.someData='newvalue',该组件不会当即从新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新
nextTick
因为DOM是异步执行更新的,有时咱们修改完数据等待DOM更新后进行操做,则此刻可以使用Vue.nextTick(callback)
Vue.component('example', {
template: '<span>{{ message }}</span>',
data: function () {
return {
message: '没有更新'
}
},
methods: {
updateMessage: function () {
this.message = '更新完成'
console.log(this.$el.textContent) // => '没有更新'
this.$nextTick(function () {
console.log(this.$el.textContent) // => '更新完成'
})
}
}
})
复制代码
由于 $nextTick() 返回一个 Promise 对象,因此你可使用新的ES2016async/await语法完成相同的事情:
methods: {
updateMessage: async function () {
this.message = 'updated'
console.log(this.$el.textContent) // => '未更新'
await this.$nextTick()
console.log(this.$el.textContent) // => '已更新'
}
}
复制代码
客户端 ->(创建链接)-> 服务器
客户端 <-(确认接受,创建链接)<- 服务器
客户端 ->(确认接受)-> 服务器
复制代码
客户端 ->(关闭链接)-> 服务器
客户端 <-(确认关闭)<- 服务器
客户端 <-(关闭链接)<- 服务器
客户端 ->(确认关闭)-> 服务器
复制代码
2XX 请求成功
3XX 重定向
4XX 客户端错误
5XX 服务器错误
XSS(跨站脚本攻击)是在网页中注入非法的js脚本,获取cookie达到控制浏览器的目的
危害:
防范方法:
CSRF 跨站点请求伪造,冒充用户发起请求,完成一些违背用户意愿的事情(如修改用户信息等)
危害:
防范方法:
token使用原理
同源策略: 具备相同的协议(http/https)、域名、端口即为同源,不存在跨域,反之亦然
跨域资源共享(CORS)
需后端设置
服务器转发代理
请求同源地址的代理接口,服务器访问跨域接口并返回数据
jsonp
利用script标签不受同源策略限制的特征,在src内写入请求地址,末尾回调处理数据
<script type="text/javascript" src="http://localhost/Service.ashx?callback=jsonpCallback" />
复制代码
cookie
sessionStorage
localStorage
图片大体分为png、jpg、gif三种
优化方案:
当加载图片过大时,会出现局部逐步加载状况,用户体验差;可经过哟图片的onload方法来判断图片是否加载完成,未加载完前先display:none;进行隐藏,当onload后在进行加载。
假设桌子小到只能放下一枚硬币,那么先放者赢;若不肯定桌子大小,则首先在圆心处放硬币,而后在对手放完后的关于圆心的对称点处再放硬币,确保先放者赢