赞
踩
前端性能优化:减少消耗,提高用户体验。
例如一些基础数据。应用懒加载技术,按需加载,缩短首屏或页面首次加载发起的请求数量,缩短等待和渲染时间。
打包压缩文件,压缩 js 和 css 文件,减小文件体积,缩短加载时间。
script 有 defer 和 async 属性(延迟和异步),这可以改变脚本的执行方式。
css 加载。合理规划 css 的加载引入方式,减少 @import 的使用 页面被加载时,link 会同时被加载, 而 @import 引用的 CSS 会等到页面被加载完再加载。css 尽量放在 head 中会先加载,减少首次渲染时间。
一些用户操作行为用到的资源,可不在初始化时加载,合理延迟或有需要才请求。
减少不必要的 DOM 深度,例如不必要的嵌套结构。在 DOM 树中的一个级别进行更改可能会致使该树的所有级别(上至根节点,下至所修改节点的子级)都随之变化。这会导致花费更多的时间来执行重排。
尽可能减少 CSS 规则的数量,并删除未使用到的 CSS 规则。一些默认就有的 CSS 规则,就不必写了,具有继承性的样式,也不必每级节点都写。calc() 之类的计算方法应该少用。
如果您想进行复杂的渲染更改(例如动画),请在流程外执行此操作。您可以使用 position-absolute 或 position-fixed 来实现此目的。
避免使用不必要且复杂的 CSS 选择器(尤其是后代选择器),因为此类选择器需要耗用更多的 CPU 处理能力来执行选择器匹配。总之不必要的深度,不管是 css 还是 dom 都不是好的选择,这对人和机器都是同样的道理,因为读和理解起来都同样的“费力”。
合理使用虚拟列表技术,降低消耗。
使用函数节流(throttle)或函数去抖(debounce),限制某些不必要的行为的的频繁触发。
使用性能更好的 api,优化网络连接等
合理使用标签:
常见语义化标签:h1-h6,header,footer,main,nav,title,article,time,progress,aside,strong,ul,ol 等。
label 有两种使用方式,一是嵌套,二是通过 id 绑定。它可以用于关联绑定表单组件, 浏览器会将用户对 label 关联范围的焦点转移到绑定的表单组件上。
title 是在悬浮时展示的提示文字,alt 是在图像无法正常显示时展示的提示文字, 此外 title 是许多 html 标签都有的属性,而 alt 是 img 标签的特殊属性。 当然在低版本ie浏览器中,鼠标悬浮也会显示alt的文字。
这个问题,在印象里面似乎 hr 问得比较多。实事求是回答完事, 例如会坚持技术路线,往资深架构方向走,也希望拓阔方向,向大前端靠近。
tips:讲个笑话,跟着 JavaScript 走,当它一t天下的时候,也跟着...
结合自身经历,概括用到的知识技术点,以及解决思路。
加载 script 脚本资源;script 脚本的执行只在默认的情况下是同步和阻塞的。 script 标签可以有 defer 和 async 属性(延迟和异步),这可以改变脚本的执行方式(在支持他们的浏览器)
继续解析后面的标签,文档内容
title 标签用于定义文档的标题,它是 head 标签中唯一必需的元素。
head 标签用于定义文档的头部。 充当头部容器,script 脚本,link 资源,mete 标签。
可用在 head 中的标签:, , , , , , , 。
readonly:元素的只读属性,可以防止用户对值进行修改。 但用户仍然可以使用 tab 键切换到该字段,还可以选中或拷贝其文本。 在表单组件 input 中使用 readonly,内容会随着表单提交。
disabled:禁用属性,使元素无法使用和无法操作,无法被选中。 在表单组件 input 中使用 disabled,内容不会再随着表单提交。
二者都可以通过 js 修改其值,从而恢复编辑状态和被选中能力。
- <!--
- 搜索引擎,用于禁止搜索引擎索引本页内容
- 谷歌、必应、雅虎都支持的 meta robots 标签如下,他们会禁止搜索引擎进行相应的操作:
- noindex:不索引本页面。
- nofollow:不跟踪本页面上的链接。
- nosnippet:不在搜索结果中显示说明文字。
- noarchive:不显示快照。
- noodp:不使用开放目录中的标题和说明。
- -->
- <meta name="robots" content="noindex,nofollow"/>
-
-
- <!-- 关键词,填写网页关键词,优化SEO的重要标签 -->
- <meta name="keywords" content="请输入网页关键字,例如:程序员;写代码;高薪;加班严重"/>
- <!-- 声明优先使用的浏览器,例如下面是优先使用的是edge和chrome -->
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
- <!-- 网页概述,优化SEO的重要标签 -->
- <meta name="description" content="请输入网页概述,例如:知识社区,前端技术"/>
利用的是 canvas 标签。
是一个可以使用脚本(通常为JavaScript)来绘制图形的 HTML 元素。 例如,它可以用于绘制图表、制作图片构图或者制作简单的(以及不那么简单的)动画。
这是一道笔试题。要求写一个获取年月日时分秒的函数,返回的格式如下:2022-01-07 08:08:08
- /**
- * 要求返回的格式如下:2022-01-07 08:08:08
- * @returns {string}
- */
- function getDateTime () {
- let data = new Date(),
- year = data.getFullYear(),
- month = data.getMonth() + 1,
- day = data.getDate(),
- hour = data.getHours(),
- min = data.getMinutes(),
- second = data.getSeconds()
-
- // 当月、日、时、分、秒数字小于10时,补0。
- if (month < 10) {
- month = '0' + month
- }
- if (day < 10) {
- day = '0' + day
- }
- if (hour < 10) {
- hour = '0' + hour
- }
- if (min < 10) {
- min = '0' + min
- }
- if (second < 10) {
- second = '0' + second
- }
-
- return year + '-' + month + '-' + day + ' ' + hour + ':' + min + ':' + second
- }
①TDK:title 标题标签、description 描述标签、keywords 关键词标签,这三个标签的首字母合体。
②SEO:
title 标题,description 描述,keywords 关键词的搜索影响权重是逐渐减小的。
title 和 description 的内容应能代表网页内容,不能乱用不被普遍认可的词汇, 不同页面 title、description、keywords应不同, keywords 的关键词,重要的靠前排放。
语义化的 HTML 代码:符合 W3C 规范,语义化代码让搜索引擎容易理解网页。
少用 iframe:搜索引擎不会抓取 iframe 中的内容。
网速:网站网速是搜索引擎排序的一个重要指标
这是一道笔试题。
- for(let i=0;i<4;i++){
- i++
- console.log(i) // 打印了 1 和 3
- }
重排是在网络浏览器中执行的一个流程,用于重新计算文档中各元素的位置和几何形状,以便重新呈现该文档的部分内容或全部内容。 会改变文档布局,会引发元素的位置、尺寸发生改变的行为可称为重排。重排比起重绘,在视觉效果上会更明显, 每当操作 DOM 树、更改影响布局的样式、更改元素的 className 属性或更改浏览器窗口大小时,都会发生重排现象。
在不改变文档布局的情况下,文档元素发生的例如背景颜色等外观改变的行为可称为重绘。 根据 Opera 的说法,重绘的成本也很高,但在处理能力较高的现代设备中,可能感觉不明显。
- git rm 删除工作区文件,并将这次删除放入暂存区
- git add 增加指定文件到暂存区
- git init 新建初始化 git 代码库
- git status 显示有变更的文件
- git branch 列出所有分支
- git commit -m [message] 提交暂存区到仓库区,可选填备注信息 message
- git checkout -b [branch] 新建分支,并切换到该分支
可以通过 prop 和 emit()通信。在子组件通过prop接受父组件传递下来的信息。父组件可以根据约定的事件名,接受子组件通过emit() 通信。在子组件通过 prop 接受父组件传递下来的信息。 父组件可以根据约定的事件名,接受子组件通过 emit()通信。在子组件通过prop接受父组件传递下来的信息。父组件可以根据约定的事件名,接受子组件通过emit(name,data) 向上派发的事件和传递的信息。
refs和ref。ref绑定,refs 和 ref。ref 绑定,refs和ref。ref绑定,refs 获取组件实例,进而获取组件的属性、方法等信息。
Vuex,可以通过 vuex 进行数据交互,状态管理。
Bus (中央事件总线)
当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。
- <li v-for="todo in todos" v-if="!todo.isComplete">
- {{ todo }}
- </li>
es6 又称 es2015,是 js 的标准,它包含了许多新的语言特性和库,是比较大的一次升级。
新增了:
这题应该是想问虚拟列表,嘿,谁还不会点虚拟列表。 10万数据同时渲染的假如太假了,不管啥技术都得是往【时空错位】方向考虑吧?
认真的讲,分页获取分页渲染,也是一个朴素的好方法。初次和面试官见面不好认真,还是虚拟列表吧。
什么是虚拟列表:只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染,以实现减少消耗,提高用户体验的技术。
为啥要用虚拟列表:一是性能优,二是体验丝滑。渲染生成过多的节点,可能会造成页面卡顿,甚至卡死浏览器。 而常规分页的展示效果可能不是想要的,尤其在移动端,用户习惯和偏好,更倾向于上下滑动。
虚拟列表的实现思路:
git 和 svn 最大的区别在于 git 是分布式的,而 svn 是集中式的。因此我们不能再离线的情况下使用 svn。
git 分支上的变更不会影响其他人,svn 分支上的变更会影响到其他人。
svn 的指令相对于 git 来说要简单一些,比 git 更容易上手。
svn 中的分支是整个版本库复制的一份完整目录,而 git 的分支是指针指向某次提交,因此 git 的分支创建开销更小。
然后把被复制对象的所有可枚举的属性方法一一复制过来。
①JSON.parse(JSON.stringify(data)),但对于 function 有缺陷。
②Object.assign() 实现一层深拷贝。
③解构赋值法实现一层拷贝
④创建新对象 for 循环拷贝,有需要可结合递归。
大都数场景,还是 JSON.parse(JSON.stringify(data)) 实用, 有的人说有性能担忧,但讲真,每个字节所到之处都涉及性能问题吧?
状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理请求,还是出现了错误。
- 204 No Content,表示请求处理成功,但没有资源可返回。该状态码代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。
-
- 206 Partial Content ,该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET 请求。响应报文中包含由 Content-Range 指定范围的实体内容。
-
- 301 Moved Permanently ,永久性重定向。该状态码表示请求的资源已被分配了新的 URI,以后应使用资源现在所指的 URI。
-
- 302 Found ,临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。
-
- 303 See Other ,该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。
-
- 304 Not Modified ,该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。304 状态码返回时,不包含任何响应的主体部分。304 虽然被划分在 3XX 类别中,但是和重定向没有关系。(资源已找到,但不符合请求所附带的添加。好像是说已经找到钱包,但你的请求附带了一个钱包里应有10k金额的条件,所以不好意思,无法把钱包返回给你。)
-
- 307 Temporary Redirect ,临时重定向。该状态码与 302 Found 有着相同的含义。尽管 302 标准禁止 POST 变换成 GET,但实际使用时大家并不遵守。
-
- 400 Bad Request ,该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。
-
- 401 Unauthorized ,该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。另外若之前已进行过 1 次请求,则表示用户认证失败。
-
- 403 Forbidden ,该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由,但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。 未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源 IP 地址试图访问)等列举的情况都可能是发生 403 的原因。
-
- 404 Not Found,该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。
-
- 500 Internal Server Error,该状态码表明服务器端在执行请求时发生了错误。也有可能是 Web 应用存在的 bug 或某些临时的故障。
-
- 503 Service Unavailable,该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入RetryAfter 首部字段再返回给客户端。
函数防抖动(debounce):防止在短时间内过于频繁的执行相同的任务。 当短时间内的频繁是不必要的时候,就可以考虑去抖动,避免资源浪费,或造成不好体验。
函数防抖动的原理,主要是利用一次性定时器,延迟任务的执行,在延迟这段时间内, 如果任务再次被触发,则通过 clearTimeout 销毁上一次产生的定时器, 因为定时器的被销毁,之前被延迟执行的任务也会随之被取消执行。 这样就实现了在一定时间内,只执行一次任务。这一次的执行通常是最后一次的触发, 因为此前的触发因为定时器的销毁而被取消了。
多次触发只执行最后一次或许就是和“节流”概念的区别?它两在作用上挺像的,在具体实现上略有不同。 函数防抖(debounce)是短时间内连续多次触发,但只执行最后一次,即是说将多次执行变成了只执行最后一次,执行次数减少。 而节流(throttle)是将短时间的多次执行,变成每隔一段时间执行一次。
序号 | 单位 | 相对于 |
---|---|---|
1 | em | 元素的字号,在 font-size 中使用是相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如 width |
2 | ex | 字体的X字高(x-height) |
3 | cap | 字体 中 大 写 的 标 称 高度 |
4 | ch | 数字“0”的宽度,元素字体中窄字形的平均字符前进,由“0”(零,U+0030)字形表示。 |
5 | ic | 元素字体中全宽字形的平均字符前进,由“水”(CJK 水象形文字,U+6C34)字形表示。 |
6 | rem | 根元素的字体大小。 |
7 | lh | 元素的行高line-height 。 |
8 | rlh | 根元素的行高。 |
9 | vw | 视口宽度的 1%。 |
10 | vh | 视口高度的 1%。 |
11 | vi | 根元素内联轴上视口大小的 1%。 |
12 | vb | 根元素块轴上视口大小的 1%。 |
13 | vmin | 视口较小尺寸的 1%。 |
14 | vmax | 视口较大尺寸的 1%。 |
- px 是 css 中的绝对单位,也是web前端最为常见的单位,它表示像素,他的值不会受其他元素或其他值的影响,
- 我们可以理解为10px所表示的意义,总是相同的。
-
- em 是相对单位,相对于元素的字号,在 font-size 中使用是相对于父元素的字体大小,
- 在其他属性中使用是相对于自身的字体大小,如 width。
-
- 相对单位的值的表示的大小,受其他东西的影响,比如1em,可能相当于10px的大小,
- 也可能相当于100px,甚至更高,因为em的实际表示大小是根据父元素而定,
- 1em表示的是父元素字体大小的一倍,要注意的是虽然只是受父元素的影响,
- 但父元素也会受它的父元素的影响。
Mozilla 上这样解释闭包:一个函数和对其周围状态(lexical environment,词法环境)
的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。
我对闭包的理解:闭包就是函数内部嵌套了函数。闭包使得可以模拟私有项, 可以使得内部函数可以访问外部函数的属性。非必要不用闭包。
javaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻, 还会搜寻该对象的原型,以及该对象的原型的原型, 依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
这种依次层层向上搜索中,遇到的每层的原型所组成的链条就是原型链。
下面通过一个示例来理解继承与原型链
- // 使用语法结构创建的对象
- let obj = {
- a: 'hello',
- fc: function () {
- return this.a + 1
- }
- }
- // obj 这个对象继承了 Object.prototype 上面的所有属性
- // obj 自身没有名为 hasOwnProperty 的属性
- // hasOwnProperty 是 Object.prototype 的属性
- // 因此 obj 继承了 Object.prototype 的 hasOwnProperty
- // Object.prototype 的原型为 null
-
- // 原型链如下:
- // obj ---> Object.prototype ---> null
- console.log(obj)
- console.log(obj.__proto__)
- console.log(obj.__proto__.__proto__) // null,这就是原型链的终点
-
- let subObj = Object.create(obj); // 创建的 subObj 本身没有自身的属性,但它继承有 obj 的属性。
- console.log(subObj.fc()); // 3,fc() 继承自 obj
- // 那么此时,我们就说 subObj 是一个继承自 obj 的对象,因为继承,obj 的一些属性被传递给了 subObj,
- // 例如 fc() 就继承自 obj
- // subObj 的原型链是 // subObj ---> obj ---> Object.prototype ---> null
- console.log(subObj)
这是一张打印上面 obj 对象的原型链截图, 打印结果也符合上面关于 obj 对象原型链的结论:obj ---> Object.prototype ---> null
下面是一张打印 subObj 的原型连截图: 打印结果也符合上面关于 subObj 对象原型链的结论:subObj ---> obj ---> Object.prototype ---> null
display: 隐藏元素,不会占据该元素原来的空间。视觉上相对于该元素被移除了,不占有空间位置。 设置 display:none后,元素的宽高等属性会”失效“
visibility: 隐藏元素,仍然占据该元素原来的空间。可能会呈现一部分空白区域。 设置 visibility:hidden 后,然占据空间位置,视觉上相当于完全透明。
①通过 box-sizing 来改变盒子模型,它有两个选项 border-box 和 content-box。
②盒模型:分为内容(content)、填充(padding)、边界(margin)、边框(border)四个部分
③与 css 盒模型有关的一个值得注意属性是 box-sizing。通常 box-sizing 的默认值是 content-box, 而他还有另一个值 border-box。content-box 中,属性 width,height 只包含内容content, 不包含 border 和 padding。border-box 中,属性 width,height 则包含 content、border和padding。
有关计算公式
- /** content-box 的宽高计算 **/
- box-sizing:content-box
- width = width;
- height = height
- /** border-box 的宽高计算 **/
- box-sizing:border-box
- width = width + padding + border;
- height = height + padding + border
①来源区别。@import 是 css 的语法,而 link 是 html 的标签。
②加载区别。在加载的时候,@import 引用的 CSS 会在页面加载完成后才会加载 @import 引入的 CSS 样式表, 而 link 是在页面加载的同时被加载。
③权重区别。可比较环境下,@import 引用的样式,权重小于 link 引入的样式。
④兼容区别。兼容性上,link 几乎所有浏览器的支持,例如 ie、Firefox、chrome、safari、opera 全版本支持。 而 @import 是 ie 5.5 开始支持。
①块的上外边距(margin-top)和下外边距(margin-bottom)有时合并(折叠)为单个边距, 其大小为单个边距的最大值(或如果它们相等,则仅为其中一个),这种行为称为外边距折叠。
②外边距折叠(也被翻译为重叠或塌陷)有关的计算:折叠后其大小为单个边距的最大值(或如果它们相等,则仅为其中一个)。
tips:这里说的单个边距的最大值,不是指数学比较上的最大,而是指单个边距距离范围的大小。
比如 -50px 和 -70px 发生折叠,那么折叠后的值是 70px,因为 -70 的绝对值最大嘛,要是 -50px 和 -50px, 当然此时绝对值最大也是 50px 嘛,所以你只有一个选择 50px。
比如 50px 和 70px 发生折叠,那么折叠后的值是 70px,因为 70 的绝对值最大嘛, 要是 50px 和 50px,当然也选绝对值最大的 50px。
例如 70px、-50px、20px 发生折叠,那么边界范围就是 70px + (-50px)= 20px。
①css3 以后,为了区分伪类和为元素,规范伪类使用单冒号,伪元素使用双冒号表示。 (但css2 的伪元素单冒号的写法,仍被许多现代浏览器兼容支持)
②伪类会给页面中已经存在的元素添加一个类(class),伪元素则是添加了一个页面中没有的元素(element), 但需注意这个被添加的元素不会添加到文档树中,只是一种视觉效果。
常见伪元素
常见伪类
来自 Mozilla 的关于 @media 的解释:
@media CSS 规则可用于基于一个或多个媒体查询的结果来应用样式表的一部分。
使用它,您可以指定一个媒体查询和一个CSS块,当且仅当该媒体查询与正在使用其内容 的设备匹配时,该CSS块才能应用于该文档。
媒体查询(Media queries)非常实用,尤其是当你想要根据设备的大致类型(如打印设备与带屏幕的设备) 或者特定的特征和设备参数(例如屏幕分辨率和浏览器视窗宽度)来修改网站或应用程序时。
我对 @media 的理解:
因为现实中存在许多不同的设备,不同的设备可能分辨率不同,可能屏幕可见区域也不同。
为了能让同一份网页在不同的设备中,表现的更友好,适配程度更高,于是 css3 设计了 @media。
使得无需修改内容便可以使样式应用于某些特定的设备范围。
例如为打印机、智能手机、阅读器、电脑等不同设备,编写不同的样式表, 通过 @media 识别适配应用对应的样式表。
@media 可以针对不同的屏幕尺寸设置不同的样式,这在设计响应式的页面会非常有用。 例如,媒体查询可以缩小小型设备上的字体大小,在纵向模式下查看页面时增加段落之间的填充, 或者增加触摸屏上按钮的大小,甚至改变布局方式。
当媒体查询返回为真时,对应的样式表会按照正常的规则被应用生效; 当媒体查询返回为假时,以 link 标签上带有媒体查询的样式表为例,对应的样式表不会被应用,但仍会被下载。
用法示例:
- /* 可以放在 style 的顶部,或其他位置 */
- @media screen and (min-width: 900px) {
- article {
- padding: 1rem 3rem;
- }
- }
-
- /* 嵌套在一组 css 规则中 */
- @supports (display: flex) {
- @media screen and (min-width: 900px) {
- article {
- display: flex;
- }
- }
- }
这是一道笔试选择题,其他选项不记得了。
navigator.geolocation.getCurrentPosition()
下面是一个使用示例:
- getGeolocation(){
- if ('geolocation' in navigator) {
- /* 地理位置服务可用 */
- console.log('地理位置服务可用')
- navigator.geolocation.getCurrentPosition(function (position) {
- console.dir('回调成功')
- console.dir(position) // 没有输出
- console.dir(position.coords.latitude, position.coords.longitude)
- }, function (error) {
- console.error(error)
- })
- } else {
- /* 地理位置服务不可用 */
- console.error('地理位置服务可用')
- }
- }
@font-face 的 CSS 规则 ,它允许网页开发者为其网页指定在线字体或加载指定的本地字体。
下面是一个示例
- @font-face {
- /* 字体名称,可自定义,就像定义一个class名称一样。*/
- font-family: 'hdjx';
- /* 字体文件的路径,除了 url()加载字体,也可以通过 local() 加载本地字体 */
- src: url('./HDJXYT.ttf');
- /* 字重,就像在普通css中使用它一样,可以选择bold等值 */
- font-weight: normal; /* 字重 */
- /* 字体样式 */
- font-style: normal; /* 字体样式 */
- }
在使用 https 的访问页面中,引入 http 资源会被浏览器报警告,不同浏览器警告信息可能展现形式不同。
为了解决这个问题,我们可以省略 URL 的协议声明,省略后浏览器照样可以正常引用相应的资源, 这项解决方案称为 protocol-relative URL。
协议相对URl,是指在编写URL时不携带具体的协议类型,URL被访问执行时,根绝一定规则自动使用相对的协议类型。 例如,当人们通过https浏览页面时候,那么不写明具体协议类型的的图片资源URL,就会以https协议访问图片资源; 使用http浏览页面时,使用相对协议URL的资源就会以http请求资源。
使用相对协议URL,可能会是一个好的选择。因为使用相对协议URL,在用http或https浏览页面时, 浏览器都会以相同的协议请求对应的资源,这能较好地避免浏览器关于使用混合协议的警告。 在SSL证书是后面使用的场景中,资源URL也不用更换,意思是说存储起来的资源地址(例如图片地址), 可以不是绝对地址,可以不携带协议类型,甚至连域名都不带也是一种具有可行的方案。
FOUC(文档样式短暂失效(Flash of Unstyled Content)),主要指的是样式闪烁的问题, 由于浏览器渲染机制(比如firefox),在 CSS 加载之前,先呈现了 HTML, 就会导致展示出无样式内容,然后样式突然呈现的现象。会出现这个问题的原因主要是 css 加载时间过长, 或者 css 被放在了文档底部。
①减少使用@import导入样式表。
②不在文档尾部引入样式。
③尽量使用link标签在head中引入。(当然link标签是一个只能在head中使用的标签,因此使用link必然是在head中的)
11 种样式选择器
优先级是如何计算的?
当同一个元素有多个声明的时候,优先级才会有意义。因为每一个直接作用于元素的 CSS 规则总是会接管/覆盖(take over)该元素从祖先元素继承而来的规则。
下面列表中,选择器类型的优先级是递增的:
1.类型选择器(标签选择器)(例如,h1)和伪元素(例如,::before)
2.类选择器 (例如,.example),属性选择器(例如,[type="radio"])和伪类(例如,:hover)
3.ID 选择器(例如,#example)。
嵌套组合选择器
多种选择器嵌套组合的优先级,往往比单一的样式选择器优先级更高。 例如 #id > div > p{} 的优先级会比 p{} 和 div > p{} 的优先级更高。
给元素添加的内联样式 (例如,style="font-weight:bold") 几乎总会覆盖外部样式表的任何样式 , 因此可看作是具有更高的优先级。
当在一个样式声明中使用一个 !important 规则时,此声明将覆盖任何其他声明。 当然 !important 可以覆盖 !important,此时需要比较权重。
一个选择器的优先级可以说是由四个部分相加 (分量),可以认为是个十百千 — 四位数的四个位数:
千位: 如果声明在 style 的属性(内联样式)则该位得一分。这样的声明没有选择器,所以它得分总是1000。 百位: 选择器中包含ID选择器则该位得一分。 十位: 选择器中包含类选择器、属性选择器或者伪类则该位得一分。 个位:选择器中包含元素、伪元素选择器则该位得一分。
下面是一个示例表:
选择器 | 千位 | 百位 | 十位 | 个位 | 优先级 |
---|---|---|---|---|---|
h1 | 0 | 0 | 0 | 1 | 0001 |
h1 + p::first-letter | 0 | 0 | 0 | 3 | 0003 |
li > a[href*="en-US"] > .inline-warning | 0 | 0 | 2 | 2 | 0022 |
#identifier | 0 | 1 | 0 | 0 | 0100 |
内联样式 | 1 | 0 | 0 | 0 | 1000 |
tips:可比条件下,写在后面优先级高于写在前面的
tips:可比条件下,同为载入样式,后面载入的优先级更高。
var 关键字用于声明全局变量,存在”变量提升“现象,不会抛出异常,默认值会被设置为 undefined。 “变量提升”的存在,使得变量像是声明提前,声明语句被移动到环境的顶部似得。
let 和 const 是 es6 新增的关键字,用于声明局部变量。 const 用于声明常量,它声明的变量只读不可被修改。 let 声明的局部变量可以被修改。
在 ECMAScript 6 中,let 和 const 同样会被提升变量到代码块的顶部但是不会被赋予初始值。 在变量声明之前引用这个变量, 将抛出引用错误(ReferenceError)。 这个变量将从代码块一开始的时候就处在一个“暂时性死区”,直到这个变量被声明为止。
vue 环境的推荐指令版做法
常规做法一:纯 css 样式
- /** 单行的处理 **/
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-
- /** 多行的处理,不兼容 ie **/
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 3; /** 最多显示几行 **/
- overflow: hidden;
截取固定字符数的方式,例如截取120字,超出部分使用省略号替代,不超出则不截取。 这种方式相比方案一,兼容性更好,也有两个缺点: 一是排版效果不够美观,因为英文和数字的单字符占的实际宽度要比中文小, 这会产生省略号可能在行中间甚至行首,而不是统一的在行位。 二是对html字符串不友好,有时接口返回的会是包含html代码的字符串, 截取可能会破坏html字符串的代码结构,例如一个标签被截取部分。
①height 不会被继承。
②可继承与不可继承的样式小结
可继承:
不可继承 :
③控制继承
CSS 为控制继承提供了四个特殊的通用属性值。每个css属性都接收这些值。 这意味着,就像 css 盒子模型可以通过改变 box-sizing 的值 (border-box 和 content-box)来改变。 css 属性的继承情况也是可以控制的,例如通过设置值 inherit、initial、unset 和 revert 来控制。
- inherit:设置该属性会使子元素属性和父元素相同。实际上,就是 "开启继承".
-
- initial:设置属性值和浏览器默认样式相同。如果浏览器默认样式中未设置且该属性是自然继承的,那么会设置为 inherit。
-
- unset:将属性重置为自然值,也就是如果属性是自然继承那么就是 inherit,否则和 initial一样。
-
- revert:目前仅被很少浏览器支持。
④重设几乎所有属性值
CSS 的 shorthand 属性 all 可以用于同时将这些继承值中的一个应用于(几乎)所有属性。 它的值可以是其中任意一个(inherit, initial, unset, or revert)。 这是一种撤销对样式所做更改的简便方法,以便回到之前已知的起点。
例如像下面这样:例子中有两个 div,第一个 div 应用了样式选择器 div 的样式, 第二个通过 类选择器 unset-all 设置 all 为 unset,重置了几乎所有样式。
- <div>
- <p>这是一段文字</p>
- </div>
- <div class="unset-all">
- <p>这是另一段文字,它将被充值样式</p>
- </div>
- div {
- background-color: red;
- border: 2px solid green;
- }
-
- .unset-all {
- all: unset;
- }
下面是一张效果图
这是一道笔试题,也许是不好意思当面问出来?
①兼容性更好,因为纯 div + css 的布局设计,会被几乎所有浏览器支持,且效果表现一致性高。
②设备扩展性较好,尤其是在不同的设备上,例如 PowerPoint,手机浏览器,其他终端设备等。
③灵活性较高...
④更有利于搜索引擎SEO?
不是。 浏览器会从最右边的样式选择器开始,依次向左匹配。最右边的选择器相当于关键选择器(key selector), 浏览器会根据关键选择器从 dom 中筛选出对应的元素,然后再向上遍历相关的父元素,判断是否匹配。
所以组合嵌套选择器时,匹配语句越短越简单,浏览器消耗的时间越短, 同时也应该减少像标签选择器,这样的大范围命中的通配选择器出现在组合嵌套选择器链中, 因为那样会让浏览器做大量的筛选,从而去判断选出匹配的元素。
元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。 元素的位置在屏幕滚动时不会改变。 (一种有趣的划分,fixed 和 absolute 所作用的元素一样,被划为绝对定位元素(absolutely positioned element))
元素会被移出正常文档流,并不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移, 来确定元素位置。绝对定位的元素可以设置外边距(margins), 且不会与其他边距合并即不会发生外边距折叠(margin collapsing)。
该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置 (因此会在此元素未添加定位时所在位置留下空白)。 position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。
该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。 此时 top, right, bottom, left 和 z-index 属性无效。
来自 Vue Router 官网
hash 模式是用 createWebHashHistory() 创建的,它在内部传递的实际 URL 之前使用了一个哈希字符(#)。 由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。 不过,它在 SEO 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。
来自 Vue Router 官网
当使用这种历史模式时,URL 会看起来很 "正常",例如 example.com/user/id。漂亮
!不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置, 用户在浏览器中直接访问 example.com/user/id,就会得…
404 错误。这就丑了。
不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。 如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!
这是一道简单的基础笔试题。
js:// 单行注释,/* 多行注释 */
html:<!- -" 注释内容"- ->
css:/* 注释内容 */ ,在一些 css 预处理语言环境中,// 也有注释效果
数据驱动和组件化思想
数据驱动是vuejs的核心思想之一,有人称其为vuejs最大的特点。所谓数据驱动就是指数据状态变化时, 自主得去更新与其有依赖的视图。数据驱动的关键在于驱动,这里的驱动是自主的, 生活中有一个词叫做自动化,我简单的认为数据驱动思想,是自动化思想在前端编程自动化上的一种应用, 数据驱动是将对dom的手动操作,自动化了,它根据数据状态的变化,自动更新操作视图。 使用过jQuery的同学应该有体会,数据驱动带来的“自动化”,其实省去了许多操作dom的工作,维护也更加方便。
我对数据驱动的定义,简单总结为以下三点:
①数据驱动是指根据数据状态变化,自主更新视图。
②数据驱动是自动化思想,在前端编程自动化上的应用。
③数据驱动使得操作dom,从手动操作,变成了自动操作,是一种自动化表现。
vue组件是一种拓展HTML元素,将要展示的内容分成相对独立的拓展HTML元素, 即分成不同组件的过程,或在设计构建视图的编码时,将相对独立的可视区域, 以独立组件的形式构建的过程,就是组件化。
组件化的优点: 每一个组件,可以对一个viewModel(简写vm,可以是vue实例)。视图页面是组件的容器, 组件化之后,我们可以任意根据需求自由嵌套组合组件,最后形成一个个完整页面。 组件具有高内聚低耦合的特性,那么复用性更好,维护成本更低,提高开发效率,这些优点就呼之欲出了。
Vue2 实现双向数据绑定,object 类型数据是通过 Object 的 defineProperty() 实现的, array 类型数据,是通过拦截重写数组的 7 个可操作且会改变数组自身的方法实现的。
Vue3 则是利用了 Proxy 代替了 Object.defineProperty 和 重写数组。
tips:vue2
从官网的生命周期图和源码看,可以大致将vue的生命周期分为4个阶段,分别是初始化阶段,模板编译阶段,挂载阶段,销毁阶段。
初始化阶段:为vue实例初始化属性、事件、数据观测等。
模板编译阶段:将模板字符串编译成渲染函数。(该阶段在runtime版本中不存在,因为已经编译好了。)
挂载阶段:将vue实例挂载到指定dom上,即将模板渲染到真实dom中。
销毁阶段:解绑指令,移除事件监听器,销毁子实例。
与vue生命周期密切相关的钩子函数有beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed。 vue的api文档上,一共有11个和生命周期有关的钩子函数,另外三个分别是activated,deactivated,最后一个是vue2.5.0新增的,叫errorCaptured。
v-show 是通过改变 css display 属性值实现切换效果, v-if 则是通过直接销毁或创建 dom 元素来达到显示和隐藏的效果。 v-if是真正的条件渲染,当一开始的值为true时才会编译渲染,而v-show不管怎样都会编译,只是简单地css属性切换。
v-if适合条件不经常改变的场景,因为它的切换会重新编译渲染,会创建或销毁 dom 节点,开销较大。 v-show适合切换较为频繁的场景,开销较小。
computed 是计算属性,对于任何复杂逻辑,你都应当使用计算属性,这就是它的应用场景,虽然通过 methods 或 watch 也能完成, 但是 computed 在处理复杂逻辑时更有优势:计算属性是基于它们的响应式依赖进行缓存的。
watch 是侦听属性,虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法, 来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时, 你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。
- .lazy - 取代 input 监听 change 事件
-
- .number - 输入字符串转为有效的数字
-
- .trim - 输入首尾空格过滤
.stop - 调用 event.stopPropagation()。 .prevent - 调用 event.preventDefault()。 .capture - 添加事件侦听器时使用 capture 模式。 .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。 .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。 .native - 监听组件根元素的原生事件。 .once - 只触发一次回调。 .left - (2.2.0) 只当点击鼠标左键时触发。 .right - (2.2.0) 只当点击鼠标右键时触发。 .middle - (2.2.0) 只当点击鼠标中键时触发。 .passive - (2.3.0) 以 { passive: true } 模式添加侦听器
- .prop - 作为一个 DOM property 绑定而不是作为 attribute 绑定。(差别在哪里?)
-
- .camel - (2.1.0+) 将 kebab-case attribute 名转换为 camelCase。(从 2.1.0 开始支持)
-
- .sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
主要是利用 window 这个全局对象,在上面注册全局方法(函数),并监听来实现的,当然安卓和iOS略有不同。 下面是一个 h5 通知原生支付,并接受原生支付结果回调的示例。
- // 通知原生发起支付
- function notifyPay(payType, data) {
- const params = JSON.stringify(data);
- window.acceptPayInfo = function (payResult) {//接收原生支付结果
- if (payResult) {
- store.commit("setPayResult", JSON.parse(payResult));
- localStorage.setItem('setPayResult', JSON.parse(payResult));
- Toast.clear();
- Toast('支付结果:' + payResult)
- }
- };
- //安卓
- if (window.PKAndroid) {
- //支付宝
- if (payType === 1) {
- window.PKAndroid.alipay(params);
- return
- }
- //微信
- window.PKAndroid.wxpay(params);
- return
- }
- //ios
- if (window.webkit) {
- //支付宝
- if (payType === 1) {
- window.webkit.messageHandlers.alipay.postMessage(params);
- return
- }
-
- //微信
- window.webkit.messageHandlers.wxpay.postMessage(params)
- }
- }
key 的特殊 attribute 主要作用在于给节点做唯一标识,以便高效的更新虚拟 DOM。 在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。 而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
父子组件中几个钩子的执行顺序。父组件是子组件的容器,从这角度理解,那么应当是父组件先创建,然后才能容纳子组件创建。 而挂载渲染,子组件作为父组件一部分,父组件的挂载渲染完成,应当以子组件为前提。(特例除外)
所以 子mounted 先于父mounted执行,父created 先于 子created执行。
- 加载渲染:
- 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate
- -> 子created -> 子beforeMount -> 子mounted -> 父mounted
-
- 子组件更新:
- 父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
-
- 父组件更新:
- 父beforeUpdate -> 父updated
-
- 销毁:
- 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
-
几个内置属性的执行顺序依次是 props,methods,data ,computed,watch。
'keep-alive' 用于缓存不活动的组件实例。
'' 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 '' 相似,'' 是一个抽象组件: 它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
当组件在 '' 内被切换,它的 'activated' 和 'deactivated' 这两个生命周期钩子函数将会被对应执行。
$router 是包括了路由的钩子函数和跳转方法等的路由实例对象,常用于跳转,例如一个携带参数的跳转:
this.$router.push({name: 'detail', query: { id: "12306" }})
route可用于获取router.push 携带过来的参数,是路由信息对象,包括 name,query,params 等路由信息。例如下面这样使用:
this.id = this.$route.query.id;
- <style lang="scss" scoped>
- ::v-deep .el-input {
- width: 120px;
- }
- </style>
- <style lang="scss" scoped>
- /deep/ .el-input {
- width: 120px;
- }
- </style>
-3. >>> 仅对 css 有效,对于 css 预处理语言,例如 scss、less 不生效。
对于 vue 中 div#app 节点外的元素样式,如果 '' 加上了 scoped,那么此时样式穿透符是不能穿透修改 div#app 节点外的元素样式的。 这是因为 scoped 的作用域仅局限在 div#app 容器内部,所以此时只能修改 div#app 容器内的样式。 例如 el 组件的下拉选的弹出层是 div#app 的兄弟元素,body的子元素,在 '' 中使用样式穿透符修改该弹出层的样式是无效的。
全局后置守卫钩子先执行,组件内的 beforeRouteEnter 钩子后执行。
- 完整的导航解析流程(来自 vue-router 官网)
-
- 1.导航被触发。
-
- 2.在失活的组件里调用 beforeRouteLeave 守卫。
-
- 3.调用全局的 beforeEach 守卫。
-
- 4.在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
-
- 5.在路由配置里调用 beforeEnter。
-
- 6.解析异步路由组件。
-
- 7.在被激活的组件里调用 beforeRouteEnter。
-
- 8.调用全局的 beforeResolve 守卫(2.5+)。
-
- 9.导航被确认。
-
- 10.调用全局的 afterEach 钩子。
-
- 11.触发 DOM 更新。
-
- 12.调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
①使用clear属性清除浮动。
②创建BFC环境,利用BFC的特性,BFC具有排除外部浮动和包含内部浮动的特性。
html 规范上说可以被视为替换元素的有:audio, canvas, embed, iframe, img, input, object, 和video。
developer.mozilla 上列明的典型的可替换元素只有下面几个:
而其他元素仅在特定情况下作为可替换元素处理:
HTML 规范也说了 元素可替换,因为 "image" 类型的 元素就像一样被替换。 但是其他形式的控制元素,包括其他类型的 元素,被明确地列为非可替换元素(non-replaced elements)。
所以,如果强调典型的可替换元素,那么 iframe,video,embed,img 更合适作为代表。
行内元素: b, big, i, small, tt ,abbr, acronym, cite, code, dfn, em, kbd, strong, samp, var, a, bdo, br, img, map, object, q, script, span, sub, sup, button, input, label, select, textarea
以下是 HTML 中所有的块级元素列表(虽然”块级“在新的 HTML5 元素中没有明确定义):
address, article, aside, blockquote, dd, div, dl, fieldset, figcaption, figure, footer, form, h1-h6, header, hgroup, hr, ol, p, pre, section, table, ul
所以 img 是行业元素,也是典型的可替换元素(replaced element)。
以 span 为例的行内元素的宽高边距有效性: width:无效。 height:无效。 margin:left和right有效,top和bottom无效。 padding:left和right有效,top会覆盖前面的元素,bottom会和后面的元素重叠。
因为 img 还是可替换元素(replaced element)又称置换元素,所以与 span 不同可设置宽高。
push(),pop(),shift(),unshift(),splice(),sort(),reverse()是7个可改变自身的数组的方法。 它们主要是通过对数组添加或删除或排序元素,来改变原数组本身。
用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
应用场景:因为 vue 是异步执行 dom 更新的,所以当你希望在更新数据之后,操作新的视图, 那么你的操作逻辑应写在 Vue.nextTick(callback) 的回调中,而这个回调会在dom 更新循环结束之后执行。 否则,因为异步更新 dom 的原因,如果你不是在 Vue.nextTick(callback) 的回调中执行操作新视图, 那么可能会发生意外。例如你在 created()钩子 是不能操作 dom 的,但你可以在此调接口更新数据, 如果你此时希望接口更新完毕数据后,接着调用操作 dom 的逻辑,那么最后将这部分操作 dom 的逻辑, 放置在Vue.nextTick(callback) 的回调函数中。
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。 Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的.
我用到 nginx 的地方是,一是作为 http 服务器,为我做测试实验,以及一些静态资源提供 http 服务。二通过 nginx 代理实现跨域。 三是利用 nginx 的代理转发,实现同一域名下部署多个项目。
优点: 在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能, 这些拓展令 CSS 更加强大与优雅。提高样式的可维护性,一定程度上可以提高工作效率。
缺点:浏览器“不认识” css 预处理语言,需要预处理工具转换才能在浏览器上生效,重新编译的耗时可能略微大于原生 css。
官网:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
vuex 核心:
State。共享的的全局的的属性或状态,主要在 state 中声明存放。
Getter。Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
注意从 Vue 3.0 开始,getter 的结果不再像计算属性一样会被缓存起来。
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。 这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
Action。 Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。
Module。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
CSS非标准属性。厂商在实现非标准的CSS属性时,通常会加上前缀,甚至在将来会实现的标准也加。当标准被发布后,厂商会将前缀移除。
Firefox:-moz-,
Chrome和Safari:
-webkit-,IE:-ms-,
Opera:-o-。
书写建议私有属性(非标准)放在前面,标准属性写在后面
下面是一个示例:
- -webkit-transform:rotate(-3deg); /* Chrome/Safari */
- -moz-transform:rotate(-3deg); /* Firefox */
- -ms-transform:rotate(-3deg); /* IE */
- -o-transform:rotate(-3deg); /* Opera */
- transform:rotate(-3deg); /* 标准属性写在后面 */
不一定。
浏览器解析器遇到script脚本的解析逻辑:
1.情形一:页面中引入的script脚本会阻塞浏览器解析渲染文档。
浏览器解析文档时,默认是按照排列顺序向下解析的,当遇到script标签时,和其他标签元素一样(例如一个div), 会先解析该元素(脚本),解析完成后再继续向下走完成剩余文档的解析和渲染。也就是说默认情况下,script脚本会阻塞文档的解析渲染。
注意,如果我们的script脚本是放在页面底部的内联脚本,那么它对文档的解析渲染,在结果上影响不大。
但如果script脚本是外部脚本(通过网址引入的那种),那么这个脚本需要下载和解析执行, 这期间会阻塞浏览器对文档的向下解析渲染,直至脚本下载执行完成,才会继续向下解析渲染。如果这个脚本出错了, 可能还会导致整个页面永远无法正常渲染呈现。
注意,DOM树的生成是受JavaScript代码执行影响的,JavaScript代码会“阻塞”页面UI的渲染。
2.情形二:页面中引入的script脚本不会阻塞浏览器解析渲染文档。
情形一中提到的脚本执行的同步和阻塞的情形,是指默认情况下的script脚本加载方式。script标签有两个属性,一个是defer(翻译为延迟), 二是asyn(翻译为异步,没错,和我们的常见的ajax和axios的异步是一个意思), 这两个属性都可以改变脚本的加载执行方式(在浏览器支持的情况下,这两的兼容性,后面会补充)。
延迟:延迟是指当浏览器解析到script脚本时,会继续向下载入和解析文档,等到文档载入解析完成且可以操作文档时,才开始执行脚本。
异步:异步是指当浏览器解析到script脚本时,会立刻下载和执行脚本,但同时浏览器解析器也会继续向下解析渲染文档, 不会造成阻塞的现象。这使得脚本可以尽快的被载入执行,这很想我们前端调用post异步接口,并不影响文档的正常解析渲染。
ps:defer和async属性像是在告诉浏览器,链接进来的脚本不会使用document.write(),也不会生成文档内容, 因此浏览器在下载脚本时可以继续解析和渲染文档。
值得注意的是,使用defer属性的脚本,当有多个的时候, 这些脚本会按照他们在文档中排列的顺序载入执行。而使用asyn属性的脚本,当有多个的时候,会顺序开始触发载入, 但谁先完成载入就谁先执行,这就是说,他们的执行顺序可能是无序不确定的。在有的时候知道这点很重要,因为这可能涉及一些有强制顺序的逻辑处理。
关注+持续更新中~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。