一:什么是BFC?什么时候触发BFC?
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
** BFC布局规则:**
内部的Box会在垂直方向,一个接一个地放置。
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
BFC的区域不会与float box重叠。
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
计算BFC的高度时,浮动元素也参与计算
哪些元素会生成BFC:
1.根元素
2.float属性不为none
3.position为absolute或fixed
4.display为inline-block, table-cell, table-caption, flex, inline-flex
5.overflow不为visible
二:在地址栏输入网址敲回车发生了什么?
总的来说分为以下几个过程:
1、DNS解析:将域名解析为IP地址;根据IP地址找到对应的服务器;
2、TCP连接:TCP三次握手;
3、发生HTTP请求;
4、服务器处理请求并返回HTTP报文;
5、浏览器解析渲染页面;
6、断开连接:TCP四次挥手;
TCP三次握手的过程:
TCP就是通信协议
1、第一次握手由浏览器发起,告诉服务器我要发送请求;
2、第二次握手由服务器发起,告诉浏览器我准备接收了,你发送吧;
3、第三次握手由浏览器发起,告诉服务器,我马上发送,准备接收;
为什么要发起三次握手:
为了防止已失效的连接请求报文段突然又传送到服务端,因而产生错误
在TCP三次握手结束后,开始发送HTTP请求报文
请求报文由请求行、请求头、请求体三部分组成:
1.请求行包含请求方法、URL、协议版本
请求方法包含 8 种:
GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。
URL 即请求地址,由 <协议>://<主机>:<端口>/<路径>?<参数> 组成
协议版本即 http 版本号
2.请求头包含请求的附加信息,由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。
请求头部通知服务器有关于客户端请求的信息。它包含许多有关的客户端环境和请求正文的有用信息。其中比如:Host,表示主机名,虚拟主机;Connection,HTTP/1.1 增加的,使用 keepalive,即持久连接,一个连接可以发多个请求;User-Agent,请求发出者,兼容性以及定制化需求。
3.请求体,可以承载多个请求参数的数据,包含回车符、换行符和请求数据,并不是所有请求都具有请求数据。
断开连接:TCP四次挥手;
当数据传送完毕,需要断开 TCP连接,此时发起 TCP 四次挥手。
1、第一次挥手:由浏览器发起,发送给服务器,我请求报文发送完了,你准备关闭吧;
2、第二次挥手:由服务器发起,告诉浏览器,我接收完请求报文,我准备关闭,你也准备吧;
3、第三次挥手:由服务器发起,告诉浏览器,我响应报文发送完毕,你准备关闭吧;
4、第四次挥手:由浏览器发起,告诉服务器,我响应报文接收完毕,我准备关闭,你也准备吧;
大概就是这样吧
三:什么是重绘什么是重流
重流: reflow, 重绘: repaint
重流必定导致重绘, 重绘不一定重流
布局改变,浏览器的尺寸,字体大小,元素的尺寸,元素的位置变化,CSS伪类激活,DOM操作会发生重流, 元素颜色等改变只会发生重绘
**下面是通过减少重流/重绘次数而优化页面性能的一些手段: **
减少js中的dom操作, 若必须, 则尽量将读取dom和写入dom的操作放在一起, 便于浏览器累积dom变动, 一次执行, 减少重绘.
缓存dom信息, 多次使用, 不要重复读取dom节点.
不要一项一项地改变样式, 尽量用 css class一次性改变样式.
使用documentFragment操作DOM
动画使用absolute或fixed定位. 不然重流会很严重.
只有在必要时才显示或隐藏元素, 这个操作必定会导致重流
使用window.requestAnimationFrame()可以把代码推迟到下一次重流时执行.
使用Virtual DOM(如 React / Vue)
四:函数防抖和函数节流
概念
函数防抖
当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间
函数节流
预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期
函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
比如如下的情况:
window对象的resize、scroll事件
拖拽时的mousemove事件
文字输入、自动完成的keyup事件
**区别举个列子 **
函数防抖:如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时如果又有人进电梯了(在10秒内再次触发该事件),我们又得等10秒再出发(重新计时)。
函数节流 :保证如果电梯第一个人进来后,10秒后准时运送一次,这个时间从第一个人上电梯开始计时,不等待,如果没有人,则不运行
五:Vue中assets和static的区别
相同点:
assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点
不相同点:
assets中存放的静态资源文件在项目打包时,也就是运行npm run build时会将assets中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在static文件中跟着index.html一同上传至服务器
static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中就会占据更大的空间。所以简单点使用建议如下:
将项目中template需要的样式文件js文件等都可以放置在assets中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。
当然具体情况,具体分析,在不同的开发环境,不同的需求下,大家应针对不同具体情况采用合适方式。对两者的理解就简单总结这些。记录这些,只为记录自己的开发点击,望对大家有帮助。
六:computed与method的区别
上篇文章说了 computed与watch的区别 这里在补充一下computed与method的区别
computed是属性调用,而methods是函数调用
computed带有缓存功能,而methods不是
六:mvc,mvp和mvvm介绍及三大框架对比
上篇文章详细介绍了 MVVM 这里补充下mvc,mvp和mvvm的区别
mvc
View 传送指令到 Controller
Controller 完成业务逻辑后,要求 Model 改变状态
Model 将新的数据发送到 View,用户得到反馈
所有通信都是单向的。
mvp
MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。
各部分之间的通信,都是双向的。
View 与 Model 不发生联系,都通过 Presenter 传递。
View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
mvvm
MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。
唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。
这里面使用的设计模式有:观察者模式(发布订阅模式)、代理模式、工厂模式、单例模式。
七:SPA路由为history 刷新404 为什么 ?如何解决
原因:当路由模式为history的时候,服务器端会根据浏览器中的请求地址去匹配资源,此时服务器端没有对应的接口地址,因此返回404
解决办法:第一种:使用connect-history-api-fallback中间件
安装connect-history-api-fallback中间件
npm install --save connect-history-api-fallback
在app.js文件中增加以下代码:
const history = require('connect-history-api-fallback')
app.use('/', history());
重新启动服务
第二种方法:Internet Information Services (IIS)
1.安装 IIS UrlRewrite
在你的网站根目录中创建一个 web.config 文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Handle History Mode and custom 404/500" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
八:手写promise封装ajax请求
上代码:
// 使用promise实现一个简单的ajax
/**
* 首先,可能会使用到的xhr方法或者说属性
* onloadstart // 开始发送时触发
* onloadend // 发送结束时触发,无论成功不成功
* onload // 得到响应
* onprogress // 从服务器上下载数据,每50ms触发一次
* onuploadprogress // 上传到服务器的回调
* onerror // 请求错误时触发
* onabort // 调用abort时候触发
* status // 返回状态码
* setRequestHeader // 设置请求头
* responseType // 请求传入的数据
*/
// 默认的ajax参数
let ajaxDefaultOptions = {
url: '#', // 请求地址,默认为空
method: 'GET', // 请求方式,默认为GET请求
async: true, // 请求同步还是异步,默认异步
timeout: 0, // 请求的超时时间
dataType: 'text', // 请求的数据格式,默认为text
data: null, // 请求的参数,默认为空
headers: {}, // 请求头,默认为空
onprogress: function () {}, // 从服务器下载数据的回调
onuploadprogress: function () {}, // 处理上传文件到服务器的回调
xhr: null // 允许函数外部创建xhr传入,但是必须不能是使用过的
};
function _ajax(paramOptions) {
let options = {};
for (const key in ajaxDefaultOptions) {
options[key] = ajaxDefaultOptions[key];
}
// 如果传入的是否异步与默认值相同,就使用默认值,否则使用传入的参数
options.async = paramOptions.async === ajaxDefaultOptions.async ? ajaxDefaultOptions.async : paramOptions.async;
// 判断传入的method是否为GET或者POST,否则传入GET 或者可将判断写在promise内部,reject出去
options.method = paramOptions.method ? ("GET" || "POST") : "GET";
// 如果外部传入xhr,否则创建一个
let xhr = options.xhr || new XMLHttpRequest();
// return promise对象
return new Promise(function (resolve, reject) {
xhr.open(options.method, options.url, options.async);
xhr.timeout = options.timeout;
// 设置请求头
for (const key in options.headers) {
xhr.setRequestHeader(key, options.headers[key]);
}
// 注册xhr对象事件
xhr.responseType = options.dataType;
xhr.onprogress = options.onprogress;
xhr.onuploadprogress = options.onuploadprogress;
// 开始注册事件
// 请求成功
xhr.onloadend = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
resolve(xhr);
} else {
reject({
errorType: "status_error",
xhr: xhr
});
}
};
// 请求超时
xhr.ontimeout = function () {
reject({
errorType: "timeout_error",
xhr: xhr
});
}
// 请求错误
xhr.onerror = function () {
reject({
errorType: "onerror",
xhr: xhr
});
}
// abort错误(未明白,只知道是三种异常中的一种)
xhr.onabort = function () {
reject({
errorType: "onabort",
xhr: xhr
});
}
// 捕获异常
try {
xhr.send(options.data);
} catch (error) {
reject({
errorType: "send_error",
error: error
});
}
});
}
// 调用示例
_ajax({
url: 'http://localhost:3000/suc',
async: true,
onprogress: function (evt) {
console.log(evt.position / evt.total);
},
dataType: 'text/json'
}).then(
function (xhr) {
console.log(xhr.response);
},
function (e) {
console.log(JSON.stringify(e))
});
|
|