当前位置: 首页 > news >正文

做火情监控网站需要用什么系统150m网站空间

做火情监控网站需要用什么系统,150m网站空间,廊坊网站排名方案,h5页面制作案例开放性的题目 自我介绍 突出学习能力 我想换工作的主要原因是 介绍项目 平时是如何学习前端开发的 主要就是两个途径#xff0c;一个是查阅官方文档#xff0c;然后就是在网上查找技术资料或者视频去学习。平时没事的时候也会看看github#xff0c;同时关注一些社区和IT网…开放性的题目 自我介绍 突出学习能力 我想换工作的主要原因是 介绍项目 平时是如何学习前端开发的 主要就是两个途径一个是查阅官方文档然后就是在网上查找技术资料或者视频去学习。平时没事的时候也会看看github同时关注一些社区和IT网站我经常看的就是掘金CSDN开源中国这些。通过一些大牛们的分享接触到新的技术和知识然后就自己感兴趣或者好用的前沿技术就会深入的去学习。 未来三到五年的规划是怎样的 在未来的三到五年之内我希望自己能够在这个前端这个领域能有自己的技术沉淀可能产出的是技术文档或者开源框架或者组件库并且能够得到稳定的提升现在的在前端岗位上我拥有丰富的前端项目研发经验和一些大公司的项目开发经验但还有管理方面例如管理代码管理项目成员上是我稍有欠缺的这将是后期我需要去学习和提升的地方最后可以在岗位上做到独挡一面更好地为公司服务。 网络协议和浏览器相关 讲一下cookie 我的理解是 cookie 是服务器提供的一种用于维护会话状态信息的数据通过服务器发送到浏览器浏览器保存在本地的一种纯文本文件当下一次有同源的请求时将保存的 cookie 值添加到请求头部发送给服务端。这可以用来实现记录用户登录状态等功能。cookie 一般可以存储 4k 大小的数据并且只能够被同源的网页所共享访问。 服务器端可以使用 Set-Cookie 的响应头部来配置 cookie 信息。一条cookie 包括了5个属性值 expires、domain、path、secure、HttpOnly。其中 expires 指定了 cookie 失效的时间domain 是域名、path是路径domain 和 path 一起限制了 cookie 能够被哪些 url 访问。secure 规定了 cookie 只能在确保安全的情况下传输HttpOnly 规定了这个 cookie 只能被服务器访问不能在客户端使用js 脚本访问。 客户端可以通过JS脚本,例如document.cookiekeyvalue形式设置cookie 在发生 xhr 的跨域请求的时候即使是同源下的 cookie也不会被自动添加到请求头部除非显示地规定。 session是什么? session是服务器为了保存用户状态而创建的一个特殊的对象 在浏览器第一次访问服务器时,服务器会创建一个session对象,该对象有一个唯一的id,即sessionid,服务器会把sessionid以cookie的形式发送给浏览器,当浏览器再次访问服务器时,会携带cookie在请求头,可以通过cookie中的sessionid来访问session对象 可以实现在http无状态基础上实现用户状态管理(即两个页面之间的用户状态,我可以保存在session中) sessionstorage和localstorage sessionstorage:是一种会话存储当关闭浏览器页面之后相应的数据会被删除localstorage:本地存储存储持久数据没有时间限制保存之后会永久存在除非手动清除解决cookie读写困难存储容量有限的问题 可以通过window. sessionstorage window. localstorage在js中操作这两个对象localstorage.setItem()/.getItem()/removeItem()sessionstorage.setItem()/getItem()/removeItem()来实现对存储的操作 完全存储在客户端大小有5M ,localstorage有XSS注入的风险 重绘和回流重排是什么什么情况下会触发区别在哪里怎么优化回流) 在HTML中每个元素都可以理解成一个盒子在浏览器解析过程中会涉及到回流与重绘 回流布局或者几何属性需要改变就称为回流。当render树的一部分或全部的元素因改变了自身的宽高布局显示或隐藏或者元素内部的文字结构发生变化 导致需要重新构建页面的时候回流就产生了重绘重绘是当节点需要更改外观而不会影响布局的比如改变 color 就叫称为重绘 回流一定是重绘重绘不一定是回流 回流的成本比重绘的成本高得多的多。DOM树里的每个结点都会有reflow方法一个节点的reflow很有可能导致子结点甚至父点以及同级结点的reflow。 造成影响 浏览器渲染一个网页的时候会启用两条线程 一条渲染javascript 脚本另一条渲染 ui 即css 样式的渲染。 但这两条线程是互斥的。当javascript 线程运行的时候 ui 线程则会中止暂停反之亦然。 因为当ui 线程运行对页面进行渲染的时候 js 脚本难免会涉及到页面视图上的一些样式的改变为了使这个改变更加准确 js 脚本只好等待ui 线程渲染完成的时候才去执行。 所以当一个页面的元素样式改动频繁的时候ui 线程就会持续渲染造成js 代码反应慢半拍卡顿的情况。 回流触发时机 添加或删除可见的 DOM 元素元素的位置发生变化元素的尺寸发生变化包括外边距、内边框、边框大小、高度和宽度等内容发生变化比如文本变化或图片被另一个不同尺寸的图片所替代页面一开始渲染的时候这避免不了浏览器的窗口尺寸变化因为回流是根据视口的大小来计算元素的位置和大小的 重绘触发时机 颜色的修改文本方向的修改阴影的修改 如何减少 如果想设定元素的样式通过改变元素的 class 类名 (尽可能在 DOM 树的最里层)避免设置多项内联样式应用元素的动画使用 position 属性的 fixed 值或 absolute 值(如前文示例所提)避免使用 table 布局table 中每个元素的大小以及内容的改动都会导致整个 table 的重新计算对于那些复杂的动画对其设置 position: fixed/absolute尽可能地使元素脱离文档流从而减少对其他元素的影响使用 css3 硬件加速可以让transform、opacity、filters这些动画不会引起回流重绘避免使用 CSS 的 JavaScript 表达式 http和https的区别对称加密非对称加密数字签名数字证书都必须懂 1.安全性上HTTP 是超文本传输协议信息是明文传输存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议使得报文能够加密传输 2.申请证书上HTTPS 协议需要向 CA证书权威机构申请数字证书来保证服务器的身份是可信的 3.传输协议上, HTTP是超文本传输协议明文传输HTTPS是具有安全性的 SSL 加密传输协议 4.连接方式与端口上http的连接简单是无状态的端口是 80 https 在http的基础上使用了ssl协议进行加密传输端口是 443 浏览器输入url后发生了什么 浏览器的地址栏输入URL并按下回车。浏览器查找当前URL是否存在缓存并比较缓存是否过期。DNS解析URL对应的IP。根据IP建立TCP连接三次握手。HTTP发起请求。服务器处理请求浏览器接收HTTP响应。渲染页面构建DOM树。 解析HTML构建DOM树解析CSS生成CSS规则树合并DOM树和CSS规则生成render树布局render树重绘/回流负责各元素尺寸、位置的计算绘制render树paint绘制页面像素信息浏览器会将各层的信息发送给GPUGPU会将各层合成composite显示在屏幕上 关闭TCP连接四次挥手。 https三次握手四次挥手 1三次握手 1.客户端TCP向服务端TCP发送一个请求报文SYN1SYN就表示这是一个连接请求,seqxseq为随机数 2.服务端的TCP接受到请求报文后如果同意建立连接就向客户端发回确认并为该TCP的连接分配TCP缓存和变量。这个确认报文中SYN和ACK都被置为1确认号ack的值为x1然后服务器产生起始序列号seqy 3.客户端收到服务端的确认报文后也向服务端给出确认并给连接分配缓存和变量。ACK置为1seqx1,acky1 2四次挥手 1.客户机打算关闭连接就会向服务端TCP发送FIN1终止位以及seq序列号 2.服务器收到关闭请求之后返回ACK1 确认关闭以及seq序列号v 确认号u1。 3.向客户端发起自己这一方的终止请求FIN1,ACK1seqw,acku1 4.客户机收到请求之后返回ACK1,sequ1,ackw1 TIME_WAIT:如果客户机收到服务器的终止请求后返回确认断开的请求后里面关闭连接的话如果这个确认 请求没有被传达那么服务器可能要重新请求而这个时候客户机已经关闭了 收不到请求了。那么服务器可能会响应RST(表示目标服务器崩溃了必须释放再重新连接)。 3TCP如何保证可靠连接 比如当发送方向接收方发送序号为12345的报文段二号报文在传输过程中丢失了接受收到了1345接收方期望收到的是2号报文段那么345就是冗余报文这个时候接收方就会向发送方发三个对1号报文的冗余ACK。这时发送方就知道了2号报文没有传达立马重传 4两次握手不行吗为什么TCP客户端最后还要发送一次确认呢 主要防止已经失效的连接请求报文突然又传送到了服务器从而产生错误。 经典场景客户端发送了第一个请求连接并且没有丢失只是因为在网络结点中滞留的时间太长了 由于TCP的客户端迟迟没有收到确认报文以为服务器没有收到此时重新向服务器发送这条报文此后客户端和服务器经过两次握手完成连接传输数据然后关闭连接。此时此前滞留的那一次请求连接网络通畅了到达服务器这个报文本该是失效的但是两次握手的机制将会让客户端和服务器再次建立连接这将导致不必要的错误和资源的浪费。如果采用的是三次握手就算是那一次失效的报文传送过来了服务端接受到了那条失效报文并且回复了确认报文但是客户端不会再次发出确认。由于服务器收不到确认就知道客户端并没有请求连接。 5为什么要四次挥手 由于 TCP 的半关闭half-close特性TCP 提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。 任何一方都可以在数据传送结束后发出连接释放的通知待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候则发出连接释放通知对方确认后就完全关闭了TCP连接。 通俗的来说两次握手就可以释放一端到另一端的 TCP 连接完全释放连接一共需要四次握手。 浏览器的同源策略不做限制会造成什么影响 同源是指域名协议端口三个都相同。 不同源同源策略对于js脚本有限制。主要表现在3点 1 无法用js读取非同源的Cookie、LocalStorage 和 IndexDB 无法读取。【为了防止恶意网站通过js获取用户其他网站的cookie】 2 无法用js获取非同源的DOM 。【如果没有这一条恶意网站可以通过iframe打开银行页面可以获取dom就相当于可以获取整个银行页面的信息。】 3 无法用js发送非同源的AJAX请求 。更准确的说js可以向非同源的服务器发请求但是服务器返回的数据会被浏览器拦截。 跨域的方式重点  cors跨域 跨域问题来自于浏览器的同源策略即当协议、域名、端口号任意一个不同时都会引发跨域问题。 jsonp、CORS可以用来解决跨域问题 CORS是一个W3C标准全称是跨域资源共享 CORS分简单请求和非简单请求同时满足下面两个条件的就是简单请求否则就是非简单请求 (1) 请求方法是以下三种方法之一 HEAD GET POST(2) HTTP的头信息不超出以下几种字段 Accept Accept-Language Content-Language Last-Event-ID Content-Type只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain 简单请求请求头通过Origin字段用来说明本次请求来自哪个源协议 域名 端口。服务器根据这个值决定是否同意这次请求。 后端设置Access-Control-Allow-Origin字段为*表示接受任意Origin的请求就可以了。 前端代码简单的ajax即可 非简单请求的CORS请求会在正式通信之前增加一次HTTP查询请求称为预检请求preflight。 CORS与JSONP比较 CORS与JSONP的使用目的相同但是比JSONP更强大。 JSONP只支持GET请求CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器以及可以向不支持CORS的网站请求数据。 状态码有哪些 1xx 类状态码属于提示信息是协议处理中的一种中间状态实际用到的比较少。2xx 类状态码表示服务器成功处理了客户端的请求也是我们最愿意看到的状态。 「200 OK」是最常见的成功状态码表示一切正常。如果是非 HEAD 请求服务器返回的响应头都会有 body 数据。 「204 No Content」也是常见的成功状态码与 200 OK 基本相同但响应头没有 body 数据。 「206 Partial Content」是应用于 HTTP 分块下载或断电续传表示响应返回的 body 数据并不是资源的全部而是其中的一部分也是服务器处理成功的状态。 3xx 类状态码表示客户端请求的资源发送了变动需要客户端用新的 URL 重新发送请求获取资源也就是重定向。 「301 Moved Permanently」表示永久重定向说明请求的资源已经不存在了需改用新的 URL 再次访问。 「302 Moved Permanently」表示临时重定向说明请求的资源还在但暂时需要用另一个 URL 来访问。 「304 Not Modified」不具有跳转的含义表示资源未修改重定向已存在的缓冲文件也称缓存重定向用于缓存控制。 4xx 类状态码表示客户端发送的报文有误服务器无法处理也就是错误码的含义。 「400 Bad Request」表示客户端请求的报文有错误但只是个笼统的错误。 「401」请求要求用户认证 「403 Forbidden」表示服务器禁止访问资源并不是客户端的请求出错。 「404 Not Found」表示请求的资源在服务器上不存在或未找到所以无法提供给客户端。 「426 Not Found」表示http版本不匹配,在nigix需要指定版本proxy_http_version 1.1默认1.0 5xx 类状态码表示客户端请求报文正确但是服务器处理时内部发生了错误属于服务器端的错误码。 「500 Internal Server Error」与 400 类型是个笼统通用的错误码服务器发生了什么错误我们并不知道。 「501 Not Implemented」表示客户端请求的功能还不支持类似“即将开业敬请期待”的意思。 「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码表示服务器自身工作正常访问后端服务器发生了错误。 「503 Service Unavailable」表示服务器当前很忙暂时无法响应服务器类似“网络服务正忙请稍后重试”的意思。 HTTP缓存 HTTP缓存机制是根据HTTP报文的缓存标识进行的。HTTP缓存分为强缓存和协商缓存。优先级最高的是强缓存在命中强缓存失败的情况下才会走协商缓存。 问什么时候命中强缓存 判断该资源是否命中强缓存就看 response 中 Cache-Control 的值如果有max-agexxx秒则命中强缓存。如果Cache-Control的值是no-cache说明没命中强缓存走协商缓存。 强缓存 强缓存是利用http头中的Expires和Cache-Control两个字段来控制的。强缓存中当请求再次发出时浏览器会根据其中的Expires和Cache-Control判断目标资源是否“命中”强缓存如果命中则直接从缓存中获取资源不会再与服务端发生通信。 当浏览器去请求某个文件的时候服务端就在respone header里面对该文件做了缓存配置。缓存的时间、缓存类型都由服务端控制具体表现为respone header 的cache-control常见的设置是max-age public private no-cache no-store等 1Expires基本淘汰 2Cache-control Cache-control里面有如下字段 - s-maxage仅在代理服务器中生效客户端只需要考虑max-age。 - public 表示任何能被任何对象进行缓存 - private 仅表示能被客服端缓存 - no-cache 表示直接进入协商缓存 - no-store 表示不进行缓存 - max-age 设置缓存的最大周期单位为s超过这个时间会被认为过期 - s-maxage 覆盖max-age或者Expires头。如果s-maxage未过期则向代理服务器请求其缓存内容。 - s-maxage仅在代理服务器中生效客户端只需要考虑max-age。 强缓存总结 cache-control: max-agexxxxpublic 客户端和代理服务器都可以缓存该资源 客户端在xxx秒的有效期内如果有请求该资源的需求的话就直接读取缓存,statu code:200 如果用户做了刷新操作就向服务器发起http请求cache-control: max-agexxxxprivate 只让客户端可以缓存该资源代理服务器不缓存 客户端在xxx秒内直接读取缓存,statu code:200cache-control: max-agexxxximmutable 客户端在xxx秒的有效期内如果有请求该资源的需求的话就直接读取缓存,statu code:200 即使用户做了刷新操作也不向服务器发起http请求cache-control: no-cache 跳过设置强缓存但是不妨碍设置协商缓存一般如果你做了强缓存只有在强缓存失效了才走协商缓存的设置了no-cache就不会走强缓存了每次请求都回询问服务端。cache-control: no-store 不缓存这个会让客户端、服务器都不缓存也就没有所谓的强缓存、协商缓存了。 协商缓存 强缓存就是为了给客户端自给自足用的。而当某天客户端请求该资源时发现其过期了这是就会去请求服务器了而这时候去请求服务器的这过程就可以设置协商缓存。这时候协商缓存就是需要客户端和服务器两端进行交互的。协商缓存机制下浏览器需要向服务器去询问缓存的相关信息进而判断是重新发起请求、下载完整的响应还是从本地获取缓存的资源。如果服务端提示缓存资源未改动Not Modified资源会被重定向到浏览器缓存这种情况下网络请求对应的状态码是 304。同样协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的控制协商缓存的字段分别有Last-Modified和Etag其中Etag的优先级比Last-Modified高。 触发条件 Cache-Control 的值为 no-cache 不强缓存或者 max-age 过期了 强缓存但总有过期的时候 协商缓存步骤总结 请求资源时把用户本地该资源的 ETag 同时带到服务端服务端和最新资源做对比。如果资源没更改返回304浏览器读取本地缓存。如果资源有更改返回200返回最新的资源。 Etag: 5c20abbd-e2e8 Last-Modified: Mon, 24 Dec 2018 09:49:49 GMTETag每个文件有一个改动文件了就变了可以看似md5 Last-Modified文件的修改时间 问为什么要有etag HTTP1.1中etag的出现也就是说etag是新增的为了解决之前只有If-Modified的缺点主要是为了解决几个last-modified比较难解决的问题 一些文件也许会周期性的更改但是他的内容并不改变(仅仅改变的修改时间)这个时候我们并不希望客户端认为这个文件被修改了而重新get某些文件修改非常频繁比如在秒以下的时间内进行修改(比方说1s内修改了N次)if-modified-since能检查到的粒度是秒级的这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)某些服务器不能精确的得到文件的最后修改时间。 如何设置一个可靠的缓存规则? - 如果资源不可复用直接为Cache-Control设置no-store拒绝一切形式的缓存 - 如果资源可复用考虑是否每次都需要向服务器进行缓存确认如果是设置Cache-Control的值为no-cache - 如果不需要每次都向服务器确认考虑资源是否可以被代理服务器缓存根据其结果决定是设置为private还是public - 接下来考虑资源的过期时间设置对应的max-age - 最后配置协商缓存需要用到的Etag、Last-Modified等参数。 怎么设置缓存? 后端服务器nodejs: res.setHeader(max-age: 3600 public) res.setHeader(etag: 5c20abbd-e2e8) res.setHeader(last-modified: Mon, 24 Dec 2018 09:49:49 GMT) nginx配置: JS相关 数据类型相关 数据类型 基本类型 1、undefined 类型表示不存在定义声明变量但没有初始化这个变量的值就是undefined 注意在任何一个引用变量值设置为undefined都是错误的 2、null 类型表示一个值被定义了定义为空值 使用场景为 定义变量准备在将来用于保存对象所以引用值可以是null而不会是undefined 3、Boolean类型字面值为true和false 4、number类型字面量格式可以是十进制、八进制八进制第一位必须是0、十六进制前两位必须是0x 5、String类型 由零个或多个16位Unicode字符组成的字符序列 6、symbol类型ES5 的对象属性名都是字符串这容易造成属性名的冲突。比如你使用了一个他人提供的对象但又想为这个对象添加新的方法mixin 模式新方法的名字就有可能与现有方法产生冲突。如果有一种机制保证每个属性的名字都是独一无二的就好了这样就从根本上防止属性名的冲突。这就是ES6 引入Symbol的原因 引用类型 引用类型统称为object类型细分的话有Object 类型、Array 类型、Date 类型、RegExp 类型、Function 类型 等。 nullundefined 的区别 null 表示一个对象是“没有值”的值也就是值为“空”undefined 表示一个变量声明了没有初始化(赋值)undefined不是一个有效的JSON而null是undefined的类型(typeof)是undefinednull的类型(typeof)是objectJavascript将未赋值的变量默认值设为undefinedJavascript从来不会将变量设为null。它是用来让程序员表明某个用var声明的变量时没有值的。 堆和栈的概念 栈(stack): 由操作系统自动分配内存空间自动释放存储的是基础变量以及一些对象的引用变量占据固定大小的空间。堆(heap) 由操作系统动态分配的内存大小不定也不会自动释放一般由程序员分配释放也可由垃圾回收机制回收。 区别 1、栈基础变量的值是存储在栈中而引用变量存储在栈中的是指向堆中的数组或者对象的地址这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。线性结构后进先出 优点 1栈中的内容是操作系统自动创建、自动回收占据固定大小的空间因此内存可以及时得到回收相对于堆来说更加容易管理内存空间。 2相比于堆来说存取速度会快并且栈内存中的数据是可以共享的例如同时声明了var a 1和var b 1会先处理a然后在栈中查找有没有值为1的地址如果没有就开辟一个值为1的地址然后a指向这个地址当处理b时因为值为1的地址已经开辟好了所以b也会同样指向同一个地址。 缺点 相比于堆来说的缺点是存在栈中的数据大小与生存期必须是确定的缺乏灵活性。 2、堆堆内存中的对象不会随方法的结束而销毁就算方法结束了这个对象也可能会被其他引用变量所引用(参数传递)。创建对象是为了反复利用因为对象的创建成本通常较大这个对象将被保存到运行时数据区也就是堆内存。只有当一个对象没有任何引用变量引用它时系统的垃圾回收机制才会在核实的时候回收它。 优点 1 堆是操作系统动态分配的大小不定的内存因此方便存储和开辟内存空间。 2堆中保存的对象不会自动释放一般由程序员分配释放也可由垃圾回收机制回收因此生存周期比较灵活。 缺点 相比于栈来说的缺点是存在堆中的数据大小与生存期是不确定的比较混乱杂乱无章。 怎么判断数据类型各有什么区别 instanceof typeof constructor Object.prototype.toString.call() 1、typeof 检测不出null 和 数组结果都为object所以typeof常用于检测基本类型 NaN Not a Number表示非数字但是 typeof NaN number 返回为true 2、instanceof 不能检测出number、boolean、string、undefined、null、symbol类型所以instancof常用于检测复杂类型以及级成关系 3、constructor null、undefined没有construstor方法因此constructor不能判断undefined和null。 但是contructor的指向是可以被改变所以不安全 4.Object.prototype.toString.call() 对于 Object.prototype.toString() 方法会返回一个形如 [object XXX] 的字符串能判断所有类型 This指向 this总是指向函数的直接调用者而非间接调用者 如果有new关键字this指向new出来的那个对象 在事件中this指向触发这个事件的对象特殊的是IE中的attachEvent中的this总是指向全局对象Window call和bind有什么区别 call、apply、bind都是改变this指向的方法 apply和call基本上一致唯一区别在于传参方式 apply把需要传递给fnction的参数放到一个数组或者类数组中传递进去虽然写的是一个数组但是也相当于给fnction一个个的传递 bind语法和call一模一样区别在于立即执行还是等待执行bind不兼容IE6~8 两者的区别就在于apply方法的参数只有两个第一个是替换后的对象而第一个参数是一个数组用于存放调用方式所引用的若干个参数而call方法的参数按照顺序是替换后的对象调用方法的参数1以及如果有的话还有参数2……也就是将所要传的参数排列在第一个参数之后总的参数的数目是不一定的。如果call的传递这个函数处于非严格模式下则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象)严格模式下指向nulundefined 变量提升 在JavaScript中变量声明与函数声明都会被提升到作用域顶部优先级依次为变量声明 函数声明 变量赋值。 变量提升需要注意两点 1.提升的部分只是变量声明赋值语句和可执行的代码逻辑还保持在原地不动 2.提升只是将变量声明提升到变量所在的变量范围的顶端并不是提升到全局范围 函数作用域和作用域链 作用域就是变量与函数的可访问范围即作用域控制着变量与函数的可见性和生命周期。 1. 全局作用域 任何地方都能访问到的对象拥有全局作用域。 2. 局部作用域 局部作用域一般只在固定的代码片段内可访问到最常见的例如函数内部所以在一些地方会把这种作用域称为函数作用域。局部作用域的特性外部无法访问 3. ES6的块级作用域 ES6引入了块级作用域明确允许在块级作用域中声明函数let和const命令都涉及块级作用域。 作用域链 通俗地讲当声明一个函数时局部作用域一级一级向上包起来就是作用域链。 1.当执行函数时总是先从函数内部找寻局部变量 2.如果内部找不到函数的局部作用域没有则会向创建函数的作用域声明函数的作用域寻找依次向上 闭包 提到作用域就不得不提到闭包简单来讲闭包外部函数能够读取内部函数的变量。 优点闭包可以形成独立的空间永久的保存局部变量。 缺点保存中间值的状态缺点是容易造成内存泄漏因为闭包中的局部变量永远不会被回收 谈谈闭包 定义:当一个嵌套的内部函数引用了外部函数的变量或者函数时外部函数在执行时就产生了闭包产生一个闭包创建闭包最常见方式就是在一个函数内部创建另一个函数。 闭包特点:函数嵌套函数,内部函数引用外部函数的变量 闭包的作用: 1.闭包可以延长外部函数的局部变量的生命周期,可以实现计数器,累加器这类 2.可以形成变量的局部作用域,实现函数封装 缺点函数定义的变量和数据会一直存在内部函数中不会被及时释放这样会导致内存泄漏 解决尽量不使用闭包用完后及时释放 Array数组 1. 判断数组的方式 instanceof Object.prototype.tostring.call Array.isArray arr.__proto__ Array.prototype arr.constructor Array 2. 数组常用的API 数组操作方法push、pop、shift、unshift、reverse倒置、sort、toString、join、concat、slice数组截取、splice删除 / 插入 数组位置方法(indexOf、lastIndexOf) 数组迭代方法forEach、map、filter、some、every 其它方法toString、join、indexOf、lastIndexOf、includesflat (降维) js 数组操作 会修改原数组的 方法 1.pop() 删除 数组 最后一个元素 2.shift() 删除 数组 第一个元素 3.push() 数组 最后 添加 一个 元素 4.unshift() 数组 开头 添加 一个 元素 5.sort() 数组 排序 6.splice() 数组 删除 替换 插入 元素 7.reverse() 数组 反转 slice和splice的区别 splice改变原数组,slice不改变原数组。 splice除了可以删除之外,还可以插入。 reduce和map的区别 map函数的第一个参数是函数函数的参数可以是1个或者多个而reduce只能接受2个参数。 map()是将传入的函数依次作用到序列的每个元素每个元素都是独自被函数“作用”一次 。 reduce()是将传人的函数作用在序列的第一个元素得到结果后把这个结果继续与下一个元素作用累积计算 3.数组去重 let arr [1, 2, 3, 1, 2, 1, 2, 3, 2, 1, 2, 3];// ES6方法去重 // console.log([...new Set(arr)]);// 1 迭代数组当前项拿其后面的每一项和当前项做对比如果和当项一样则把这一项从数组中干掉 // O(n^2) for (let i 0; i arr.length - 1; i) {let item arr[i];for (let j i 1; j arr.length; j) {let compare arr[j];if (compare item) {// 这一项重复了我们从原始数组中把其干掉即可arr.splice(j, 1);j--;}} } console.log(arr); Object对象 1.对象的API valueOf // 返回当前对象对应的值。 toString // 返回当前对象对应的字符串形式。 toLocaleString // 返回当前对象对应的本地字符串形式。 hasOwnProperty // 判断某个属性是否为当前对象自身的属性还是继承自原型对象的属性。 isPrototypeOf // 判断当前对象是否为另一个对象的原型。 propertyIsEnumerable // 判断某个属性是否可枚举。 Object.keys(o) //遍历对象的可枚举属性 Object.getOwnPropertyName(o) //遍历对象不可枚举的属性 2.描述new一个对象过程 创建一个空对象作为将要返回的对象实例。将这个空对象的原型指向构造函数的prototype属性。将这个空对象赋值给函数内部的this关键字。开始执行构造函数内部的代码。 也就是说构造函数内部this指的是一个新生成的空对象所有针对this的操作都会发生在这个空对象上。 构造函数构造函数之所以叫“构造函数”就是说这个函数的目的就是操作一个空对象即this对象将其“构造”为需要的样子。 如果忘了使用new命令直接调用构造函数会发生什么事 这种情况下构造函数就变成了普通函数并不会生成实例对象。 var Vehicle function (){this.price 1000; };var v Vehicle(); v // undefined price // 1000// 变量v变成了undefined而price属性变成了全局变量 (1)为了保证构造函数必须与new命令一起使用一个解决办法是构造函数内部使用严格模式即第一行加上use strict。这样的话一旦忘了使用new命令直接调用构造函数就会报错。 由于严格模式中函数内部的this不能指向全局对象默认等于undefined导致不加new调用会报错JavaScript 不允许对undefined添加属性 (2)另一个解决办法构造函数内部判断是否使用new命令如果发现没有使用则直接返回一个实例对象 function Fubar(foo, bar) {if (!(this instanceof Fubar)) {return new Fubar(foo, bar);}this._foo foo;this._bar bar; }Fubar(1, 2)._foo // 1 (new Fubar(1, 2))._foo // 1 3 new.target 函数内部可以使用new.target属性。如果当前函数是new命令调用new.target指向当前函数否则为undefined。 function f() {console.log(new.target f); }f() // false new f() // true//使用这个属性可以判断函数调用的时候是否使用new命令。 function f() {if (!new.target) {throw new Error(请使用 new 命令调用);}// ... }f() // Uncaught Error: 请使用 new 命令调用 3.自己实现一个new function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {// 将 arguments 对象转为数组var args [].slice.call(arguments);// 取出构造函数var constructor args.shift();// 创建一个空对象继承构造函数的 prototype 属性var context Object.create(constructor.prototype);// 执行构造函数var result constructor.apply(context, args);// 如果返回结果是对象就直接返回否则返回 context 对象return (typeof result object result ! null) ? result : context; }// 实例 var actor _new(Person, 张三, 28); 其它 字符串幂运算 Math.pow(x,y) // x的y次幂 x——底数y——幂数 x,y必须为数字 原型链以及会产生的问题 每个对象都拥有一个原型对象类是以函数的形式来定义的。prototype表示该函数的原型当我们访问一个对象的属性时如果这个对象内部不存在这个属性那么他就会去prototype里找这个属性这个prototype又会有自己的prototype于是就这样一 直找下去也就是我们平时所说的原型链的概念。关系instance.constructor.prototype instance.__proto__特点JavaScript对象是通过引用来传递的我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时与之相关的对象也会继承这一改变。每个对象拥有一个原型对象通过 __proto__ 指针指向上一个原型 并从中继承方法和属性同时原型对象也可能拥有原型这样一层一层最终指向 null。 这种关系被称为原型链 (prototype chain) JSON序列化和反序列化 JSON.stringfy()把一个JavaScript对象序列成一个JSON字符串JSON.parse()把JSON字符串解析为原生Javascript对象 JSON.stringfy()除了要序列化js对象外还可以接收两个参数。第一个参数是过滤器可以是一个数组也可是一个函数第二个蚕食是一个选项表示是否在JSON字符串中保留缩进 1.过滤器比如我要将某个属性过滤掉 JSON.stringify(book,function(key,value){if(keyeditor) return undefined;//通过undefine删除该属性return value }) 2.字符串缩进 :如果是一个树枝那么表示的是每个级别缩进的空个数最大为10。如果是一个字符串而非数值则这个字符串将在JSON字符串中被用做缩进字符替换空格 深浅拷贝 深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的浅拷贝只复制指向某个对象的指针而不复制对象本身新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象新对象跟原对象不共享内存修改新对象不会改到原对象 深拷贝方法 JSON.parse(JSON.stringify(obj))//深拷贝对象 原理 用JSON.stringify将对象转成JSON字符串再用JSON.parse()把字符串解析成对象一去一来新的对象产生了而且对象会开辟新的栈实现深拷贝。 递归方法实现深度克隆原理遍历对象、数组直到里边都是基本数据类型然后再去复制就是深度拷贝 防抖和节流 1为什么要防抖 高频的函数操作可能产生不好的影响如resize、scroll、mousedown、mousemove、keyup、keydown…… 这种在一瞬间短时间内对浏览器或服务器造成了过多压力的交互就需要进行优化了为了解决这个问题一般有两种解决方案 debounce 防抖throttle 节流 2目的降低一个函数的触发频率以提高性能或避免资源浪费 3防抖的原理就是你尽管触发事件但是我一定在事件触发n秒无操作后才执行。 function debounce(func, wait) {var timer;return function () {clearTimeout(timer)timer setTimeout(func, wait);} } 4节流的原理很简单如果你持续触发某个事件特定的时间间隔内只执行一次。 // 创建定时器timer记录当前是否在周期内 // 判断定时器是否存在若存在则直接结束否则执行事件 // wait时间之后再次执行并清掉定时器//当触发事件的时候我们设置一个定时器再触发事件的时候如果定时器存在就不执行直到定时器执行然后执行函数清空定时器这样就可以设置下个定时器。function throttle(func, wait) {var _this, arg;var timer; // 初始化return function () {_this this; // 记录thisarg arguments; // 记录参数数组if (timer) return; // 时候未到timer setTimeout(() {func.apply(_this, arg); // 允许传入参数并修正thistimer null;}, wait);} } 继承的方式有哪些优缺? 原型链继承构造继承组合继承原型式继承寄生式继承寄生组合式继承 1、原型链继承 将父类的实例作为子类的原型 function Cat(){ } Cat.prototype new Animal(); 1非常纯粹的继承关系实例是子类的实例也是父类的实例。 2父类新增原型方法/原型属性子类都能访问到 3简单易于实现 2、构造继承 使用父类的构造函数来增强子类实例等于是复制父类的实例属性给子类没用到原型 function Cat(name){ Animal.call(this); this.name name || Tom; } 1解决了原型链继承子类实例共享父类引用属性的问题 2创建子类实例时可以向父类传递参数 3可以实现多继承多个父类对象 3.组合继承 原型链继承和经典继承双剑合璧。 function Parent (name) {this.name name;this.colors [red, blue, green]; }Parent.prototype.getName function () {console.log(this.name) }function Child (name, age) {Parent.call(this, name);this.age age;}Child.prototype new Parent();var child1 new Child(kevin, 18);child1.colors.push(black);console.log(child1.name); // kevin console.log(child1.age); // 18 console.log(child1.colors); // [red, blue, green, black]var child2 new Child(daisy, 20); console.log(child2.name); // daisy console.log(child2.age); // 20 console.log(child2.colors); // [red, blue, green] 优点融合原型链继承和构造函数的优点是 JavaScript 中最常用的继承模式。 4.原型式继承 function createObj(o) {function F(){}F.prototype o;return new F(); } 就是 ES5 Object.create 的模拟实现将传入的对象作为创建的对象的原型。 缺点 包含引用类型的属性值始终都会共享相应的值这点跟原型链继承一样 5. 寄生式继承 创建一个仅用于封装继承过程的函数该函数在内部以某种形式来做增强对象最后返回对象。 function createObj (o) {var clone object.create(o);clone.sayName function () {console.log(hi);}return clone; } 缺点跟借用构造函数模式一样每次创建对象都会创建一遍方法。 6. 寄生组合式继承 这种方式的高效率体现它只调用了一次Parent构造函数并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时原型链还能保持不变因此还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。 Promise解决的问题和存在的问题async和await 1.promise 解决了回调函数的回调地域的问题有时候我们的请求需要上一个请求返回的结果会造成相互间回调函数的嵌套使得代码的可读性和可维护性很低 - promise让代码变得扁平可读性更好then返回一个promise我们可以把then串起来then返回的promise装载了由调用返回的值。 - 在异步回调中函数的执行栈与原函数分离开导致外部无法抓住异常。在promise中我们可以使用reject捕获是失败情况和catch捕获执行异常。 //Promise 只不过是一种更良好的编程风格 2.存在的缺点无法取消一旦开始执行中途无法取消 不设置回调函数promise内部抛出的错误无法返回到外部 处于pendding状态时无法得知进展到哪一个阶段。 3.async 和 await async 函数返回的是一个 Promise 对象,在没有 await 的情况下执行 async 函数,他会立即返回一个promise对象并且绝对不会注意后面语句的执行await关键字只能用在aync定义的函数内 await 可以用于等待一个 async 函数的返回值如果它等到的是一个 Promise 对象await 就忙起来了它会阻塞后面的代码等着 Promise 对象 resolve然后得到 resolve 的值作为 await 表达式的运算结果。 async/await使得异步代码看起来像同步代码使代码简洁可读性更好避免嵌套。 宏任务微任务事件循环 宏任务是由宿主发起的而微任务由JavaScript自身发起。 在ES3以及以前的版本中JavaScript本身没有发起异步请求的能力也就没有微任务的存在。在ES5之后JavaScript引入了Promise这样不需要浏览器JavaScript引擎自身也能够发起异步任务了。 所以总结一下两者区别为 宏任务macrotask 微任务microtask 谁发 起的 宿主Node、浏览器 JS引擎 具体事件 1. script (可以理解为外层同步代码) 主js 2. setTimeout/setInterval 3. UI rendering/UI事件 UI渲染 4. postMessageMessageChannel 5. setImmediateI/ONode.js 1. promise.then()new Promise不算 2. MutaionObserver 3. Object.observe已废弃Proxy对象替代 4. process.nextTickNode.js 谁先运行 后运行 先运行 会触发新一轮Tick吗 会 不会 其中比较注意的是promise的内部既包含宏任务也包含微任务promise内部执行为宏任务then执行为微任务 事件冒泡 IE的事件流叫做事件冒泡即事件开始时有最具体的元素接收然后逐级向上传播到较为不具体的节点直至传播到document对象。 事件对象 DOM中事件对象btn.addEventListener(click, function(event){ event.preventDefault() }) 属性方法 说明 preventDefault( ) 阻止事件冒泡cancelable为true可以使用 cancelable 表明是否可以取消事件的默认行为 stopImmediatePropagation( ) 取消事件的进一步捕获或冒泡同时阻止任何事件处理程序被调用DOM3新增 stopPropagation( ) 取消事件的进一步捕获或冒泡。如果bunbbles为true则可以使用这个方法 bubbles 表名事件是否冒泡 type 被触发的事件类型 target 事件的目标 事件类型 1UI事件当用户与页面上的元素交互式触发。常用load(页面完全加载后在window上触发)、unload(页面完全卸载后触发)、select(当用户选择文本框inputh或texterea中的一个或多个字符触发)、resize(窗口发生变化时)、scroll(页面带滚动条的元素发生滚动时) 2焦点事件在页面获得或失去焦点时触发。常用blur(不冒失去焦点)、focus(不冒获得焦点)、focusin(冒泡获得焦点)、focusout(冒泡失去焦点) 3鼠标事件click、mouseDown、mouseEnter、mouseLeave、mouseMove、mouseOut、mouseOver、mouseUp 4键盘事件keydown(按下键盘人意键触发)、keypress(回车键会触发)、keyup键盘弹起 5触摸事件touchstart、touchmove、touchend、thouchcancle 事件委托又称为事件代理 对事件处理程序过多问题的解决方案就是事件委托。事件委托利用了事件冒泡只指定一个事件处理程序就可以管理某一类型的所有事件。例如在一个复杂的web应用中对所有的元素添加单击事件那门结果就会有数不清的添加事件处理程序利用事件委托可以有效解决只需要在DOM树的最高层次上天际一个事件处理程序。就可以冒泡到下面各个子元素 这样做优点1.document对象很快就可以访问而且可以在页面生命周期任何时间点上为他添加事件处理。换句话说只要可以单击的元素呈现在页面上门就可以立即具备相应功能 2.在页面中设置事件处理的所需的时间更少。只添加一个事件处理程序所需的DOM引用更少所花的时间也更少 3.整个页面占用的内存空间更少能够提升整体性能 ES新特性相关 ES6的新特性 1.let和const 问const申明的变量一定不能改变吗 const实际上保证的并不是变量的值不得改动而是变量指向的那个内存地址所保存的数据不得改动。 对于简单类型的数据数值、字符串、布尔值值就保存在变量指向的那个内存地址因此等同于常量。 但对于复合类型的数据主要是对象和数组变量指向的内存地址保存的只是一个指向实际数据的指针const只能保证这个指针是固定的即总是指向另一个固定的地址至于它指向的数据结构是不是可变的就完全不能控制了。因此将一个对象声明为常量必须非常小心。 2.箭头函数 问箭头函数和普通函数的区别 1.this 2.箭头函数是匿名函数,不能作为构造函数,不能使用new 3.箭头函数不绑定arguments参数,虽然有name属性但是是空字符串,取而代之用...扩展运算符 4.箭头函数通过 call() 或 apply() 方法调用一个函数时只传入了一个参数对 this 并没有影响 5.箭头函数没有原型属性 prototype 3.函数参数默认值 4.模版字符串 5.解构复值 6.扩展操作符 [..., arr] {...,obj} 7.promise 8.Array.prototype.includes() ES7 9.async/await (ES8) HTML和CSS相关 css3有哪些新特性 1CSS3 实现圆角border-radius:8px; 2阴影box-shadow:10px, 3对文字加特效text-shadow, 4线性渐变gradient 5transform:rotate(9deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);//旋转缩放定位倾斜 , 6增加了更多的 css 选择器 , 7多背景 rgba css选择符有哪些哪些属性可以继承 1、!important加在样式属性值后权重值为 10000 2、内联样式如style””权重值为1000 3、ID选择器如#content权重值为100 4、类伪类和属性选择器如 content、:hover 权重值为10 5、标签选择器和伪元素选择器如div、p、:before 权重值为1 6、通用选择器*、子选择器、相邻选择器、同胞选择器~、权重值为0 1.id选择器 # myid 2.类选择器.myclassname 3.标签选择器div, h1, p 4.相邻选择器h1 p 5.子选择器ul li 6.后代选择器li a 7.通配符选择器 * 8.属性选择器a[rel “external”] 9.伪类选择器a:hover, li:nth-child 低等级的选择器个数再多也不会越等级超过高等级的选择器的优先级的; 介绍一下 CSS 的盒子模型 1有两种IE 盒子模型box-sizing:border-box、标准 W3C 盒子模型box-sizing:content-box IE 的 content 部分包含了 border 和 padding 2盒模型内容content、填充padding、边界margin、边框border 3flex弹性伸缩盒模型 4多列布局column CSS盒模型和IE盒模型的区别 在 标准盒子模型中width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边框会影响盒子的总尺寸。IE盒子模型中width 和 height 指的是内容区域borderpadding的宽度和高度。 标准回答其实我们常用的盒模型就是标准盒模型他写的宽高是指内容的宽高并不是我们盒子的宽高其实最终盒子的宽高是加上了我们的padding和margin还有border最终组成的但是这种东西在我们真实项目可能就会遇到一个问题假设我想构建一个100*100的的盒子我发现只要我给他加border,我不改width和height的话他就会变大了这样就和我们的UI不符所以每改一次border和padding都要手动改width和height值还要去做一系列计算我认为这种方式特别的麻烦后来CSS3里提供了box-sizing就可以通修改box-sizing:border-box来修改盒模型为IE盒模型IE盒模型宽高是指内容border-padding的宽和高不管我怎么调padding和border它都会自动缩放内容来实现宽高不变这样我写样式比较方便所以现在真实项目中大部分都是用box-sizingborder-box包括我在看了bootstap以及各大UI组件它的源码里他们公共样式里面大部分都是让盒子默认采用box-sizingborder-box所以我认为这是我们开发中的一种规范和方式。 box-sizing有那些值有什么区别 box-sizing是CSS3新增属性可调整盒子模型的样式。 box-sizing: border-box 表示盒模型基于IE的盒模型width和height决定盒模型的content区、padding区和border区。 box-sizing: content-box 表示盒模型基于标准盒模型width和height只决定盒模型的content区 box-sizing: inherit 表示继承自父元素。 两列布局的实现方式 1.浮动 2.flex布局 3.绝对定位 /*1.采用浮动*/ .outer{height:100px; } .left{float:left;height:100px;width:200px;background:yellow; } .right{margin left:200px;height:100px;width:auto;//撑满background:red; }/*2.flex布局*/ .outer{display:flex;height:100px; } .left{height:100px;flex shrink:0;flex grow:0;flex basic:200px } .right{height:100px;flex1 }/*3.绝对定位左边的绝对定位或者右边的绝对定位 .....*/水平垂直居中的方式掌握三种 /*1已知容器的宽高 设置层的外边距*/ div {position: relative; /* 相对定位或绝对定位均可 */width:500px;height:300px;top: 50%;left: 50%;margin-top: -150px;margin-left: -250px; /* 外边距为自身宽高的一半 */ }/*2让绝对定位的div居中 不需要考虑宽高但是一定要有宽高*/ div {position: absolute;width: 300px;height: 300px;margin: auto;top: 0;left: 0;bottom: 0;right: 0; }/*3不需要知道具体宽高-水平垂直居中 利用 transform 属性但是有个问题就是兼容性不好*/ div {position: absolute; /* 相对定位或绝对定位均可 */width:500px;height:300px;top: 50%;left: 50%;transform: translate(-50%, -50%); }/*123这三个方案都是基于定位*//*利用flex布局控制主轴和交叉轴 不兼容 移动端都用这种方式*/ .container {display: flex;align-items: center; /* 垂直居中 */justify-content: center; /* 水平居中 */ }/*table-cell 缺点父元素必须有固定宽高不可以是百分比高度*/ .father{display: table-cell;vertical-align: middle;text-align: center//宽高不能是百分比 } 清除浮动 清除浮动是为了清除使用浮动元素产生的影响。浮动的元素高度会塌陷而高度的塌陷使我们页面后面的布局不能正常显示 1、父级div定义height 2、父级div 也一起浮动 3、浮动元素的父级div定义伪类:after , clearboth用来闭合浮动的 ::after,::before{content: ;visibility: hidden;display: block;height: 0;clear: both; } Flex三个属性 flex:0 0 1这是flex 的缩写 flex-grow、flex-shrink、flex-basis flex-grow 表示当有剩余空间的时候分配给项目的比例flex-shrink 表示空间不足的时候项目缩小的比例flex-basis 表示分配空间之前项目占据主轴的空间 1flex-grow默认值 0 假设有一个宽度为 800 的容器里面有 3 个项目宽度分别是 100200300。 这时候就出现了多余的 200 的空间灰色部分。这时候如果我们对左中右分别设置flex-grow为 211各个项目的计算逻辑如下 首先将多余空间 200 除以 42 1 1等于 50left 100 2 x 50 200middle 200 1 x 50 250right 300 1 x 50 350 1flex-shrink默认值 1 假设父容器宽度调整为 550里面依然是 3 个项目宽度分别是 100200300这时候空间就不够用溢出了。首先要理解清楚当我们定义一个固定宽度容器为flex的时候flex会尽其所能不去改变容器的宽度而是压缩项目的宽度。这时我们对左中右分别设置flex-shrink为 123计算逻辑如下 溢出空间 100 200 300 - 550 50总权重 1 x 100 2 x 200 3 x 300 1400left 100 - (50 x 1 x 100 / 1400) 96.42middle 200 - (50 x 2 x 200 / 1400) 185.72right 300 - (50 x 3 x 300 / 1400) 267.86 sass和less的区别 1.编译环境不同 less是通过js编译 是在客户端处理 sass同通过ruby 是在服务器端处理 2.变量符不一样 less是用,sass是用$ 3.sass支持条件语句可以使用if{}else{},for{}循环等等。而less不支持。 4.less没有输出设置sass提供4中输出选项nested, compact, compressed 和 expanded。 输出样式的风格可以有四种选择默认为nested nested嵌套缩进的css代码 expanded展开的多行css代码 compact简洁格式的css代码 compressed压缩后的css代码 5.Sass和Less的工具库不同 Sass有工具库Compass, 简单说Sass和Compass的关系类似于像Javascript和jQuery的关系,Compass在Sass的基础上封装了一系列有用的模块和模板补充强化了Sass的功能。 Less有UI组件库Bootstrap,Bootstrap是web前端开发中一个比较有名的前端UI组件库Bootstrap的样式文件部分源码就是采用Less语法编写 1 VUE相关 数据请求在哪个生命周期函数? 越早越好能放created就放created里不要在 updated 里更新数据 data为啥是一个函数 组件中的data写成一个函数数据以函数返回值形式定义这样每复用一次组件就会返回一份新的data类似于给每个组件实例创建一个私有的数据空间让各个组件实例维护各自的数据。而单纯的写成对象形式就使得所有组件实例共用了一份data就会造成一个变了全都会变的结果。 组件中的 data 为什么是一个函数 1.vue中组件是用来复用的为了防止data复用将其定义为函数。 2.vue组件中的data数据都应该是相互隔离互不影响的组件每复用一次data数据就应该被复制一次之后当某一处复用的地方组件内data数据被改变时其他复用地方组件的data数据不受影响就需要通过data函数返回一个对象作为组件的状态。 3.当我们将组件中的data写成一个函数数据以函数返回值形式定义这样每复用一次组件就会返回一份新的data拥有自己的作用域类似于给每个组件实例创建一个私有的数据空间让各个组件实例维护各自的数据。 4.当我们组件的date单纯的写成对象形式这些实例用的是同一个构造函数由于JavaScript的特性所导致所有的组件实例共用了一个data就会造成一个变了全都会变的结果。 MVC和MVVM的区别 MVC全名是Model View Controller MVVM与MVC最大的区别就是MVVM实现了View和Model的自动同步也就是当Model的属性改变时我们不用再自己手动操作Dom元素来改变View的显示而是改变属性后该属性对应View层显示会自动改变 vue生命周期函数 beforeCreate( 创建前 ) created创建后 beforeMount挂在前 mounted挂载后 beforeUpdate数据更新前调用 updated更新后 beforeDestroy实例销毁前beforeUnmount destroyed实例销毁后 unmounted activated被 keep-alive 缓存的组件激活时调用 decactived被 keep-alive 缓存的组件停用时调用 vue父子组件的生命周期 一、加载渲染过程 父beforeCreate-父created-父beforeMount-子beforeCreate-子created-子beforeMount-子mounted-父mounted 二、子组件更新过程 父beforeUpdate-子beforeUpdate-子updated-父updated 三、父组件更新过程 父beforeUpdate-父updated 四、销毁过程 父beforeDestroy-子beforeDestroy-子destroyed-父destroyed vue的组件通信 1.方法一props和$emit 父组件通过props向下传递数据给子组件子组件通过event给父组件发送消息实际上就是子组件把自己的数据发送给父组件。 2.方法二$attrs和$listeners 第一种方式处理父子组件之间的数据传输有一个如果父组件A下面有子组件B组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢 如果采用第一种方法我们必须让组件A通过prop传递消息给组件B组件B在通过prop传递消息给组件C要是组件A和组件C之间有更多的组件那采用这种方式就很复杂了。Vue 2.4开始提供了 listeners来解决这个问题能够让组件A之间传递消息给组件C。 3.方法三provide和 inject 在 Vue.js 的 2.2.0 版本中添加加了 provide 和 inject 选项。他们成对出现用于父级组件向下传递数据。 父组件中通过provide来提供变量然后在子组件中通过inject来注入变量。不论子组件有多深只要调用了inject那么就可以注入provide中的数据。而不是局限于只能从当前父组件的prop属性来获取数据只要在父组件的生命周期内子组件都可以调用。 4.方法四vuex处理组件之间的数据交互 如果业务逻辑复杂很多组件之间需要同时处理一些公共的数据这个时候才有上面这一些方法可能不利于项目的维护vuex的做法就是将这一些公共的数据抽离出来然后其他组件就可以对这个公共数据进行读写操作这样达到了解耦的目的。 5.方法五中央事件总线 如果两个组件不是父子关系呢这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象然后通过bus.$emit触发事件bus.$on监听触发的事件。 公共事件总线eventBus的实质就是创建一个vue实例通过一个空的vue实例作为桥梁实现vue组件间的通信。它是实现非父子组件通信的一种解决方案。 6.方法六$parent和$children Vue.component(child,{props:{value:String, //v-model会自动传递一个字段为value的prop属性},data(){return {mymessage:this.value}},methods:{changeValue(){this.$parent.message this.mymessage;//通过如此调用可以改变父组件的值}},template:divinput typetext v-modelmymessage changechangeValue/div })Vue.component(parent,{template:divpthis is parent compoent!/pbutton clickchangeChildValuetest/button child/child/div,methods:{changeChildValue(){this.$children[0].mymessage hello;}},data(){return {message:hello}} })var appnew Vue({el:#app,template:divparent/parent/div }) hash和hostory 1、hash模式 这里的hash就是指url尾巴后的#号以及后面的字符。这里的#和css里的#是一个意思。hash也称作锚点本身是用来做页面定位的他可以使对应的id元素显示在可视区域内。 由于hash值变化不会导致浏览器向服务器发出请求而且hash改变会触发hashchange事件浏览器的进后退也能对其进行控制所以人们在html5的history出现前基本都是使用hash来实现前端路由的。他的特点在于hash虽然出现url中但不会被包含在HTTP请求中对后端完全没有影响因此改变hash不会重新加载页面。hash 本来是拿来做页面定位的如果拿来做路由的话原来的锚点功能就不能用了。其次hash的而传参是基于url的如果要传递复杂的数据会有体积的限制 2、history模式 history模式不仅可以在url里放参数还可以将数据存放在一个特定的对象中。 history———利用了HTML5 History Interface 中新增的pushState和replaceState方法。需要特定浏览器的支持history不能运用与IE8一下 vue响应式原理 vue2.0实现mvvm的双向绑定是采用数据劫持结合发布者-订阅者模式的方式通过Object.defineProperty()来劫持各个属性的settergetter在数据变动时发布消息给订阅者触发相应的监听回调。 使用Object.defineProperty()存在几个 1需要对原始数据克隆不能监听数组的变化 2需要分别给对象中的每一个属性设置监听必须遍历对象的每个属性 3如果在实例创建之后添加新的属性到实例上它不会触发视图更新$set强制更新 【数组的这些方法是无法触发set的:push, pop, shift, unshift,splice, sort, reverse.】 所以在vue3的时候为了解决这些问题用的是ES6中新提供的拦截器Proxy实现的。 !--vue2.0-- body姓名span idspanName/spanbrinput typetext idinpName!-- IMPORT JS --scriptlet obj {name: };let newObj {...obj};Object.defineProperty(obj, name, {get() {return newObj.name;},set(val) {newObj.name val;observe();}});function observe() {spanName.innerHTML newObj.name;}inpName.oninput function () {obj.name this.value;};/script /body !--vue3.0-- body姓名span idspanName/spanbrinput typetext idinpName!-- IMPORT JS --scriptlet obj {name: };obj new Proxy(obj, {get(target, prop) {return target[prop];},set(target, prop, value) {target[prop] value;observe();}});function observe() {spanName.innerHTML obj.name;}inpName.oninput function () {obj.name this.value;};/script /body Proxy的优势 可以直接监听对象而非属性 可以直接监听数组的变化 Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的 Proxy返回一个新对象可以只操作新对象达到目的而Object.defineProperty只能遍历对象属性直接修改 Proxy作为新标准将受到浏览器厂商重点持续的性能优化 Object.defineProperty的优势如下: 兼容性好,支持IE9 vue3和vue2区别重点 1.为什么要有vue3 我们使用vue2常常会遇到一些体验不太好的地方比如 随着功能的增长需求的增加复杂组件的代码越来越难以维护逻辑混乱虽然vue2也有一些复用的方法但是都存在一定的弊端比如我们常常用的Mixin,特别容易发生命名冲突暴露出来的变量意图不是很明显重用到其他组件容易冲突。vue2对于typeScript的支持非常有限没有考虑到ts的集成。 vue3的出现就是为了解决vue2的弊端其composition API很好的解决了逻辑复用的问题而且vue3源码就是用ts写的对ts的支持非常好。我们在开发项目过程中可以使用ts的加持使代码更加健壮。 2.vue3优点 vue3支持vue2的大多数特性实现对vue2的兼容vue3对比vue2具有明显的性能提升 打包大小减少41%初次渲染快55%更新快133%内存使用减少54% vue3具有的composition API实现逻辑模块化和重用增加了新特性如Teleport组件全局API的修改和优化等编译优化 vue2 通过标记静态根节点,优化 diff 算法 vue3 标记和提升所有静态根节点,diff 的时候只比较动态节点内容 优化编译和重写虚拟dom让首次渲染和更新dom性能有更大的提升 3.响应式原理不同 Vue2.x实现双向数据绑定原理是通过es5的 Object.defineProperty根据具体的key去读取和修改。其中的setter方法来实现数据劫持的getter实现数据的修改。但是必须先知道想要拦截和修改的key是什么所以vue2对于新增的属性无能为力比如无法监听属性的添加和删除、数组索引和长度的变更vue2的解决方法是使用Vue.set(object, propertyName, value) 等方法向嵌套对象添加响应式。 Vue3.x使用了ES2015的更快的原生proxy 替代 Object.defineProperty。Proxy可以理解成在对象之前架设一层“拦截”外界对该对象的访问都必须先通过这层拦截因此提供了一种机制可以对外界的访问进行过滤和改写。Proxy可以直接监听对象而非属性并返回一个新对象具有更好的响应式支持 4.生命周期不同 beforeCreate - 请使用 setup() created - 请使用 setup() beforeMount - onBeforeMount mounted - onMounted beforeUpdate - onBeforeUpdate updated - onUpdated beforeDestroy - onBeforeUnmount destroyed - onUnmounted errorCaptured - onErrorCaptured 如果要想在页面中使用生命周期函数以往vue2的操作是直接在页面中写入生命周期而vue3是需要去引用的这就是为什么3能够将代码压缩到更低的原因 5.默认项目目录结构不同 vue3移除了配置文件目录config 和 build 文件夹移除了 static 文件夹新增 public 文件夹并且 index.html 移动到 public 中在 src 文件夹中新增了 views 文件夹用于分类视图组件和公共组件 6.默认项目目录结构不同 在 Vue3 中全局和内部 API 都经过了重构并考虑到了 tree-shaking 的支持。因此全局 API现在只能作为 ES 模块构建的命名导出进行访问。 6.使用Proxy代替了defineProperty proxy 相比于 defineProperty 的优势 Object.defineProperty() 的问题主要有三个 不能监听数组的变化必须遍历对象的每个属性必须深层遍历嵌套的对象 Proxy 在 ES2015 规范中被正式加入它有以下几个特点 针对对象针对整个对象而不是对象的某个属性所以也就不需要对 keys 进行遍历。这解决了上述 Object.defineProperty() 第二个问题支持数组Proxy 不需要对数组的方法进行重载省去了众多 hack减少代码量等于减少了维护成本而且标准的就是最好的。 除了上述两点之外Proxy 还拥有以下优势 Proxy 的第二个参数可以有 13 种拦截方法这比起 Object.defineProperty() 要更加丰富Proxy 作为新标准受到浏览器厂商的重点关注和性能优化相比之下 Object.defineProperty() 是一个已有的老方法。 vue 的初始化过程new Vue()都做了什么 处理组件配置项初始化根组件时进行了选项合并操作将全局配置合并到根组件的局部配置上初始化每个子组件时做了一些性能优化将组件配置对象上的一些深层次属性放到 vm.$options 选项中以提高代码的执行效率初始化组件实例的关系属性比如 parent、children、root、refs 等处理自定义事件调用 beforeCreate 钩子函数初始化组件的 inject 配置项得到 ret[key] val 形式的配置对象然后对该配置对象进行响应式处理并代理每个 key 到 vm 实例上数据响应式处理 props、methods、data、computed、watch 等选项解析组件配置项上的 provide 对象将其挂载到 vm._provided 属性上调用 created 钩子函数如果发现配置项上有 el 选项则自动调用 $mount 方法也就是说有了el选项就不需要手动调用$mount方法。反之没提供 el 选项则必须调用 $mount接下来则进入挂载阶段 vue里的name作用 1递归组件运用指组件自身组件调用自身组件 2keep-alive包裹动态组件时会缓存不活动的组件实例会出现include和exclude属性包含或者排除指定name组件 div idapp keep-alive excludecompArouter-view//keep-alive /divexcludecompA keep-alive属性对compA组件不生效 3vue-tools插件调试 组件未定义name属性 组件将显示成这很没有语义。 通过提供name选项可以获得更有语义信息的组件树。 $nextTick原理 由于Vue DOM更新是异步执行的即修改数据时视图不会立即更新而是会监听数据变化并缓存在同一事件循环中等同一数据循环中的所有数据变化完成之后再统一进行视图更新。为了确保得到更新后的DOM所以设置了 Vue.nextTick()方法。 Vue.nextTick()官方说明在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法获取更新后的DOM。 使用场景 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。原因是created()钩子函数执行时DOM其实并未进行渲染。在数据变化后要执行的某个操作而这个操作需要使用随数据改变而改变的DOM结构的时候这个操作应该放在Vue.nextTick()的回调函数中。原因Vue异步执行DOM更新只要观察到数据变化Vue将开启一个队列并缓冲在同一事件循环中发生的所有数据改变如果同一个watcher被多次触发只会被推入到队列中一次。 vue自定义指令 Vue中内置了很多的指令如v-model、v-show、v-html等但是有时候这些指令并不能满足我们或者说我们想为元素附加一些特别的功能。自定义指令解决的问题或者说使用场景是对普通 DOM 元素进行底层操作所以我们不能盲目的胡乱的使用自定义指令 如何声明自定义指令 对于全局自定义指令的创建我们需要使用Vue.directive接口 Vue.directive(demo, Opt) 对于局部组件我们需要在组件的钩子函数directives中进行声明 Directives: {Demo: Opt } 一个指令定义对象可以提供如下几个钩子函数 (均为可选) bind只调用一次指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted被绑定元素插入父节点时调用 (仅保证父节点存在但不一定已被插入文档中)。update所在组件的 VNode 更新时调用但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。componentUpdated指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind只调用一次指令与元素解绑时调用。 指令钩子函数会被传入以下参数 el指令所绑定的元素可以用来直接操作 DOM。binding一个对象包含以下 property name指令名不包括 v- 前缀。value指令的绑定值例如v-my-directive1 1 中绑定值为 2。oldValue指令绑定的前一个值仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。expression字符串形式的指令表达式。例如 v-my-directive1 1 中表达式为 1 1。arg传给指令的参数可选。例如 v-my-directive:foo 中参数为 foo。modifiers一个包含修饰符的对象。例如v-my-directive.foo.bar 中修饰符对象为 { foo: true, bar: true }。 vnodeVue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode上一个虚拟节点仅在 update 和 componentUpdated 钩子中可用。 vue中 keep-alive 组件的作用 keep-alive 是 Vue 的内置组件当它包裹动态组件时会缓存不活动的组件实例而不是销毁它们。和 transition 相似keep-alive 是一个抽象组件它自身不会渲染成一个 DOM 元素也不会出现在父组件链中。 作用在组件切换过程中将状态保留在内存中防止重复渲染DOM减少加载时间及性能消耗提高用户体验性 原理在 created 函数调用时将需要缓存的 VNode 节点保存在 this.cache 中在 render页面渲染 时如果 VNode 的 name 符合缓存条件可以用 include 以及 exclude 控制则会从 this.cache 中取出之前缓存的 VNode 实例进行渲染。 VNode虚拟DOM其实就是一个JS对象 props: include - 字符串或正则表达式。只有名称匹配的组件会被缓存。exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。max - 数字。最多可以缓存多少组件实例。 v-model 语法糖 v-model 的本质就是语法糖即 input typetext v-modelname 相当于 input typetext :valuename inputname $event.target.value 实现v-modeld的两种方式 只要在一个自定义组件内通过设置一个名为 value 的 prop并且在数据发生变化时 $emit 一个带新值的 input 事件就可以在该自定义组件中使用 v-model 进行双向绑定。非常简单就像这种 template input typetext :valuevalue inputhandleInput :placeholderplacehodler / /templatescript export default { name: kInput, props: { value: [String, Number], placeholder: String }, methods: { handleInput ($event) { // 通过input标签的原生事件input将值emit出去以达到值得改变实现双向绑定 this.$emit(input, $event.target.value) } } } /script 一个组件上的v-model默认会利用名为value的 prop 和名为input的事件但是像单选框、复选框等类型的输入控件可能会将valueattribute 用于不同的目的。model选项可以用来避免这样的冲突 Vue.component(base-checkbox, {model: {prop: checked,event: change},props: {checked: Boolean},template: inputtypecheckboxv-bind:checkedcheckedv-on:change$emit(change, $event.target.checked) }) vue项目打包优化策略 1组件按需加载 2路由懒加载 resolve require([/components/DefaultIndex],resolve),异步加载 webpack提供的require.ensure() const 组件名() import(组件路径); 3优化构建速度 [ 缩小文件搜索范围] 在配置 Loader 时通过 include 去缩小命中范围 4使用 UglifyJsPlugin 插件来压缩代码drop_console除掉代码中的 console vue-router 有哪几种导航钩子? 答三种 第一种是全局导航钩子router.beforeEach(to,from,next)作用跳转前进行判断拦截。 第二种组件内的钩子beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave 第三种单独路由独享组件路由定义里的钩子beforeEnter webpack 1.webpack的作用 ①、依赖管理方便引用第三方模块、让模块更容易复用避免全局注入导致的冲突、避免重复加载或者加载不需要的模块。会一层一层的读取依赖的模块添加不同的入口同时不会重复打包依赖的模块。 ②、合并代码把各个分散的模块集中打包成大文件减少HTTP的请求链接数配合UglifyJS压缩代码可以减少、优化代码的体积。 ③、各路插件统一处理引入的插件babel编译ES6文件tslint,eslint 可以检查编译期的错误。 一句话总结webpack 的作用就是处理依赖模块化打包压缩文件管理插件。 一切皆为模块由于webpack只支持js文件所以需要用loader 转换为webpack支持的模块其中plugin 用于扩张webpack 的功能在webpack构建生命周期的过程中在合适的时机做了合适的事情。 2.webpack怎么工作的过程 ①解析配置参数合并从shell(npm install 类似的命令)和webpack.config.js文件的配置信息输出最终的配置信息 ②注册配置中的插件,让插件监听webpack构建生命周期中的事件节点做出对应的反应 ③解析配置文件中的entry入口文件并找出每个文件依赖的文件递归下去 ④在递归每个文件的过程中根据文件类型和配置文件中的loader找出对应的loader对文件进行转换 ⑤递归结束后得到每个文件最终的结果根据entry 配置生成代码chunk(打包之后的名字) ⑥输出所以chunk 到文件系统。 3.请你介绍一下webpack Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析然后将这些模块按照指定的规则生成对应的静态资源。 entry 入口定义整个编译过程的起点 entry可以是个字符串或数组或者是对象。 1、当entry是个字符串的时候用来定义入口文件 2、当entry是个数组的时候里面同样包含入口js文件另外一个参数可以是用来配置webpack提供的一个静态资源服务器webpack-dev-server。webpack-dev-server会监控项目中每一个文件的变化实时的进行构建并且自动刷新页面 3、当entry是个对象的时候我们可以将不同的文件构建成不同的文件按需使用比如在我的hello页面中只要\引入hello.js即可 output 输出定义整个编译过程的终点output参数是个对象用于定义构建后的文件的输出。其中包含path和filename 当我们在entry中定义构建多个文件时filename可以对应的更改为[name].js用于定义不同文件构建后的名字。 module  定义模块module的处理方式 plugins  插件对编译完成后的内容进行二度加工 插件Plugins是用来拓展webpack功能的它们会在整个构建过程中生效执行相关的任务。 Loaders和Plugins常常被弄混但是他们其实是完全不同的东西Loaders是在打包构建过程中用来处理源文件的JSXScssLess..一次处理一个;插件并不直接操作单个文件它直接对整个构建过程其作用。webpack有很多内置插件同时也有很多第三方插件可以让我们完成更加丰富的功能。 前端安全问题 1.CSRF 跨站请求伪造,利用cookie CSRF攻击攻击原理及过程如下 1. 用户C打开浏览器访问受信任网站A输入用户名和密码请求登录网站A 2.在用户信息通过验证后网站A产生Cookie信息并返回给浏览器此时用户登录网站A成功可以正常发送请求到网站A 3. 用户未退出网站A之前在同一浏览器中打开一个TAB页访问网站B 4. 网站B接收到用户请求后返回一些攻击性代码并发出一个请求要求访问第三方站点A 5. 浏览器在接收到这些攻击性代码后根据网站B的请求在用户不知情的情况下携带Cookie信息向网站A发出请求。网站A并不知道该请求其实是由B发起的所以会根据用户C的Cookie信息以C的权限处理该请求导致来自网站B的恶意代码被执行。 csrf攻击解决方法 目前防御CSRF攻击主要有三种策略 1、验证HTTP Referer 字段 2、在请求地址中添加token并验证 3、HTTP头中自定义属性并验证。 2.XSS 跨站脚本攻击,盗取cookie 指的是恶意攻击者往Web页面里插入恶意html代码当用户浏览该页之时嵌入其中Web里面的html代码会被执行从而达到恶意的特殊目的。 解决办法 请记住两条原则过滤输入和转义输出。 第一、在输入方面对所有用户提交内容进行可靠的输入验证提交内容包括URL、查询关键字、http头、post数据等 第二、在输出方面在用户输内容中使用标签。标签内的内容不会解释直接显示。 第三、严格执行字符输入字数控制。   性能优化 请说出三种减少网页加载时间的方法 1.服务器角度 采取CDN加速 开启gzip压缩 允许使用强缓存或协商缓存 增加服务器带宽 2.客户端角度 合理组织CSS、JavaScript代码位置 减少DOM操作、添加事件委托 部分操作可设置防抖和节流 对于可预见的操作采取preload或prerender的预加载 对于图片可以懒加载 合并CSS图片精灵图/雪碧图 减少使用iframe 资源优化打包角度 3.资源优化打包角度 使用打包工具将Js文件、CSS文件和静态文件进行恰当打包处理。 浅谈SPA、SEO、SSR 1. SPA 【单页面应用程序】传统的Web网站中进入了新的页面会从服务器请求完整的一个整个页面而在SPA中当切换到新的页面只需要重写页面发生了变化的部分。 目前常见的几个SPA框架 AngularJSReactVue.js SPA的优点 页面之间的切换非常快一定程度上减少了后端服务器的压力不用管页面逻辑和渲染后端程序只需要提供API完全不用管客户端到底是Web界面还是手机等 SPA的缺点 首屏打开速度很慢因为用户首次加载需要先下载SPA框架及应用程序的代码然后再渲染页面。不利于SEO 2. SEO 搜索引擎优化。SEO是一种通过了解搜索引擎的运作规则如何抓取网站页面如何索引以及如何根据特定的关键字展现搜索结果排序等来调整网站以提高该网站在搜索引擎中某些关键词的搜索结果排名。 常见SEO优化HTMLtitle标签、 meta标签的description、meta标签的keywords Google的相关文档中也没有提到过使用meta keywords Quora也讨论过Google是否还在使用meta keywords这个问题大部分的回答都是谷歌已经不再使用它了但是其它的一些搜索引擎比如百度等还在使用meta keywords。 SPA与SEO的冲突 前面我们谈到的SPA不利于SEO因为就目前而言部分搜索引擎如Google、bing等它们的爬虫虽然已经支持执行JS甚至是通过AJAX获取数据了但是对于异步数据的支持也还不足(也可能是搜索引擎提供商觉得没必要)Vue SSR中是这样说的如果你的应用程序初始展示 loading 菊花图然后通过 Ajax 获取内容抓取工具并不会等待异步完成后再行抓取页面内容。 前·面也谈到过SPA应用中通常通过AJAX获取数据而这里就难以保证我们的页面能被搜索引擎正常收录到。并且有一些搜索引擎不支持执行JS和通过AJAX获取数据那就更不用提SEO了。 3. SSR SSR是 Server-Side Rendering(服务器端渲染)的缩写在普通的SPA中一般是将框架及网站页面代码发送到浏览器然后在浏览器中生成和操作DOM但其实也可以将SPA应用打包到服务器上在服务器上渲染出HTML发送到浏览器这样的HTML页面还不具备交互能力所以还需要与SPA框架配合在浏览器上“混合”成可交互的应用程序。所以只要能合理地运用SSR技术不仅能一定程度上解决首屏慢的问题还能获得更好的SEO。 SSR的优点 更快的响应时间不用等待所有的JS都下载完成浏览器便能显示比较完整的页面了。这个个人深有体会我的博客最开始仅仅使用了Vue.js而没有做服务端渲染加之服务器不在大陆第一次输入地址到看到完整的页面几乎是过了4、5秒有时候还更长。 更好的SSR我们可以将SEO的关键信息直接在后台就渲染成HTML而保证搜索引擎的爬虫都能爬取到关键数据。 SSR的缺点 相对于仅仅需要提供静态文件的服务器SSR中使用的渲染程序自然会占用更多的CPU和内存资源一些常用的浏览器API可能无法正常使用比如window、docment和alert等如果使用的话需要对运行的环境加以判断开发调试会有一些麻烦因为涉及了浏览器及服务器对于SPA的一些组件的生命周期的管理会变得复杂可能会由于某些因素导致服务器端渲染的结果与浏览器端的结果不一致。 SSR常用框架 React 的 NextVue.js 的 Nuxt 移动端适配方案 1. 百分比方案 使用 百分比% 定义 宽度高度 用px固定根据可视区域实时尺寸进行调整尽可能适应各种分辨率通常使用max-width/min-width控制尺寸范围过大或者过小。下表是子元素不同属性设置百分比的依据 优势 原理简单不存在兼容性问题 不足 如果屏幕尺度跨度太大相对设计稿过大或者过小的屏幕不能正常显示在大屏手机或横竖屏切换场景下可能会导致页面元素被拉伸变形字体大小无法随屏幕大小发生变化。设置盒模型的不同属性时其百分比设置的参考元素不唯一容易使布局问题变得复杂 vw/vh方案 视口是浏览器中用于呈现网页的区域移动端的视口通常指的是 布局视口 vw : 1vw 等于 视口宽度 的 1%vh : 1vh 等于 视口高度 的 **1% **vmin : 选取 vw 和 vh 中 最小 的那个vmax : 选取 vw 和 vh 中 最大 的那个 2. rem方案 原理 rem是相对长度单位rem方案中的样式设计为相对于根元素font-size计算值的倍数。根据 屏幕宽度 设置html标签的font-size在布局时使用 rem 单位布局达到自适应的目的是 弹性布局 的一种实现方式。 实现过程 首先获取文档根元素和设备dpr设置 rem在html文档加载和解析完成后调整body字体大小 在页面缩放 / 回退 / 前进的时候 获取元素的内部宽度 (不包括垂直滚动条边框和外边距)重新调整 rem 大小。 实现方法用 css 处理器或 npm 包将页面 css 样式中的px自动转换成 rem。在整个 flexible 适配方案中文本使用px作为单位使用[data-dpr]属性来区分不同dpr下的文本字号。由于手机浏览器对字体显示最小是8px因此对于小尺寸文字需要采用px为单位防止通过 rem 转化后出现显示问题。手机淘宝 中的字体使用px为单位腾讯新闻中的字体使用rem为单位。 优势 兼容性好 ios: 6.1系统以上都支持android: 2.1系统以上都支持大部分主流浏览器都支持 不足 不是纯css移动适配方案需要引入js脚本 在头部内嵌一段 js脚本 监听分辨率的变化来动态改变根元素的字体大小css样式和 js 代码有一定 耦合性并且必须将改变font-size的代码放在 css 样式之前。小数像素问题浏览器渲染最小的单位是像素元素根据屏幕宽度自适应通过 rem 计算后可能会出现小数像素浏览器会对这部分小数四舍五入按照整数渲染。浏览器在渲染时所做的摄入处理只是应用在元素的尺寸渲染上其真实占据的空间依旧是原始大小。也就是说如果一个元素尺寸是 0.625px那么其渲染尺寸应该是 1px空出的 0.375px 空间由其临近的元素填充同样道理如果一个元素尺寸是 0.375px其渲染尺寸就应该是0但是其会占据临近元素 0.375px 的空间。会导致缩放到低于1px的元素时隐时现解决办法指定最小转换像素对于比较小的像素不转换为 rem 或 vw两个同样宽度的元素因为各自周围的元素宽度不同导致两元素相差1px宽高相同的正方形长宽不等了border-radius: 50% 画的圆不圆。Android 浏览器下 line-height 垂直居中偏离的问题。常用的垂直居中方式就是使用line-height这种方法在Android设备下并不能完全居中。cursor: pointer 元素点击背景变色的问题对添加了cursor:pointer属性的元素在移动端点击时背景会高亮。为元素添加tag-highlight-color:transparent 属性可以隐藏背景高亮。 3. 基于媒体查询的响应式设计 响应式设计 使得一个网站同时适配 多种设备 和 多个屏幕让网站的布局和功能随用户的使用环境屏幕大小、输出方式、设备/浏览器能力而变化使其视觉合理交互方式符合习惯。如使得内容区块可伸缩与自由排布边距适应页面尺寸图片适应比例变化能够自动隐藏/部分显示内容能自动折叠导航和菜单。 原理 主要实现是通过 媒体查询通过给不同分辨率的设备编写不同的样式实现响应式布局用于解决不同设备不同分辨率之间兼容问题一般是指PC、平板、手机设备之间较大的分辨率差异。实现上不局限于具体的方案通常结合了 流式布局弹性布局 方案。比如给小屏幕手机设置2x图为大屏手机设置3x图 优势 能够使网页在不同设备、不同分辨率屏幕上呈现合理布局不仅仅是样式伸缩变换 不足 要匹配足够多的设备与屏幕一个web页面需要多个设计方案工作量比较大通过媒体查询技术需要设置一定量的断点到达某个断点前后的页面发生显著变化用户体验不太友好 4.ios安全区域的适配 而我们需要将viewport设置为coverenv和constant才能生效。设置代码如下 meta nameviewport contentwidthdevice-width,initial-scale1.0,viewport-fitcover 同时设置env和constant代码同样env()和constant()需要同时存在而且顺序不能换。 body {/*兼容 IOS11.2*/padding:constant(safe-area-inset-top)constant(safe-area-inset-right)constant(safe-area-inset-bottom)constant(safe-area-inset-left); /* 兼容 iOS 11.2 *//* 可以通过增加padding-bottom来适配 */padding:env(safe-area-inset-top)env(safe-area-inset-right)env(safe-area-inset-bottom)env(safe-area-inset-left); /* 兼容 iOS 11.2 */ } 5.10px字体 /*font-size: 10px;*/ .font10px {font-size: 12px;transform : scale(0.83,0.83); }/*还有一些方式可以制作小字体图片 自制字体 SVG*/ 6.0.5px的线 /*伪类 transform 实现*/ .centent{position: relative;border:none; } .centent:after{content: ;position: absolute;bottom: 0;background: #000;width: 100%;height: 1px;-webkit-transform: scaleY(0.5);transform: scaleY(0.5);-webkit-transform-origin: 0 0;transform-origin: 0 0; } 7.在高清显示屏中的位图被放大图片会变得模糊 移动端的视觉稿通常会设计为传统PC的2倍。 前端的应对方案是设计稿切出来的图片长宽保证为偶数并使用backgroud-size把图片缩小为原来的1/2 例如图片宽高为200px*200px那么写法如下.css{width:100px;height:100px;background-size:100px 100px;}其它元素的取值为原来的1/2例如视觉稿40px的字体使用样式的写法为20px.css{font-size:20px}
http://www.dnsts.com.cn/news/86993.html

相关文章:

  • 大连网站设计公司排名dw 怎么做钓鱼网站
  • 网站的做代理商大英做网站
  • 南京网站关键词优化jsp网站开发大作业
  • 销售产品单页面网站模板wordpress转成APP
  • 做网站ps建立多大的画布网站没有在工信部备案
  • php 外贸商城网站建设建设银行投诉网站
  • 公司网站平台建设c2c二手车交易平台
  • 出版社网站建设道士召唤10个月灵的传奇手游
  • 做期货的一般看什么网站论坛网页模板
  • 医疗网站被黑后可以做排名广州市城乡建设信息中心网站
  • 同一个网站可以同时做竞价和优化购物网站的设计
  • 重庆网站建设cqhtwl大学生应届毕业生招聘官网
  • 电子商务网站开发与设计开源外贸网站
  • 网站的宣传推广云计算培训
  • 菏泽做网站建设的公司建设一个网站预算
  • 中山市做网站公司电商网站分析
  • 杭州网站优化流程图标在wordpress
  • 网站怎么做可以被收录wordpress没人用
  • 网站创意wordpress循环分类
  • 深圳网站建设网络公司深圳福田网站优化网络营销培训学校
  • 网站 维护 协议做外链那些网站比较好
  • 网站设计O2O平台佛山总代理网站源码下载网
  • 网站规划总结前端开发有前途吗
  • 网站分页需要前端做还是后端对购物网站建设的建议
  • 蓬莱专业做网站公司这里是我做的网站
  • 网站互联网推广企业网站带后台
  • 爱站关键词wordpress增加内存
  • 做网站能收回吗教育类网页设计素材
  • 台州路桥区专业高端网站设计网红助手24小时自助下单app
  • 制作网页网站公司网站建设的趋势