1.响应式布局如何实现
为什么要使用响应式布局:
在之前使用固定宽高有一定的局限:屏幕越来越宽时,因为定得宽是固定的,这样会让页面不美观
屏幕越来越小时,因为定宽的局限会让用户看不到完整的页面内容
在这种情况下,响应式布局就出现了
响应式布局的实现(有五种方法)
1.百分比布局:百分比布局是相对于父元素进行布局,百分比能够对width,height,padding,margin来进行布局,border,font-size不能;
局限: 因为百分比布局只能对大面积的地方进行布局,所以不够完美 2.css3媒体查询:媒体查询可以根据不同的分辨率来设置不同的css样式,通过这种方式来适配不同屏幕,相比于百分比布局,媒体查询可以对布
局进行更细致的调整
@media screen and(min-width:1200px) @media screen and(max-width:1200px) Screen就是客户端屏幕的信息
局限:媒体查询在设置的时候需要在每个分辨率和操作下设置不同的css样式
3.rem响应式布局:rem是一个单位,跟px,em类似,1rem就等于html的font-size值,有两种方法可以进行设置
1.通过媒体查询来设置,在不同的分辨率下给html的font-size赋值;比较麻烦
2.js进行动态计算给font-size设置值:封装一个函数:通过屏幕的宽度去处理某个数,得出来的值就是html的font-size值,当屏幕宽
度改变的时候就调用这个函数,这样在使用rem的时候就会根据html的font-size来进行等比缩放;
4.弹性盒子布局:通过display:flex;来布局,给父元素设置display:flex;在给子元素设置想要改变的属性;
5.vw响应式布局:vw是基于视口的布局方案,所以在使用的时候需要在meta标签的视口中声明;1vw等于视口宽度的1% 1vh等于视口高度的1%;
现在用的都是vw,因为高度是根据内容的多少而自适应的。
2.rem布局原理
原理:rem是指相对于根元素的字体大小的单位,是基于根元素的font-size值来进行计算,就是1rem就等于html的font-size值;1rem等于多少px,就是font-size的值*
你设定的rem的值;
怎么使用rem来布局
使用Js来动态修改根元素的font-size值,当屏幕宽度发生改变的时候rem就会被动态计算出来,那你设置的rem就会自动转换为px单位;
JS代码:function rem(){
document.documentElement.style.fontSize=document.documentElement.clientWidth/7.5+'px'
}
rem()
window.onresize=rem;
3.数据类型判断
一共有4中数据类型判断的方法
1.typeof()他可以检测一些普通数据类型,比较直观的数据,比如number,string这些能够具体的检测出来他们的类型,判断引用数据类型无论引用的对象是什么类型都返回object;
2.instanceof 他可以检测引用数据类型,可以判断一个变量是否是某个类型和是否是某个实例,由构造类型判断数据类型,返回的是true或者false,不可以判断null和undefined fn instanceof Fn
3.constructor 他是通过对象的construnctor直接来判断他是否和他的原型相同,但是一旦构造函数的原型被更改那么这个方法就不好用了 fn.constructor == Array
4.Object.prototype.toString.call() 他目前是一个最完美的解决方案,他只需要在括号里边写你想要判断的数据类型就行了,他可以直接从原型里面找要判断的类型
4.原型和原型链
函数原型:每个函数都有一个prototype对象,这个对象就是函数的原型,每个函数原型中都有一个constructor属性,就是构造函数本身,
构造函数被实例化后,包含一个__proto__属性,这个属性就是函数的原型,new实例化后的对象没有prototype原型,有__proto__;
函数的原型有一个优点就是在原型中添加属性,所有的实例化对象都可以访问到
原型链:在访问一个属性或者方法的时候,先从自身里面去找,如果自身找不到就通过这个对象的proto属性指向的对象查找,如果还没有
就继续通过现在查找的对象的proto属性指向的对象查找,直到结束,如果最后找不到就返回undefined;
代码实现:先定义一个函数,里面写一些属性;然后在这个函数的原型上设置一些属性;然后在new 实例化这个函数;最后通过调用这个实例化出来的新函数来查找属性,就可以实现一个原型链;
5.闭包
要了解闭包,先得了解变量的作用域,分为全局作用域和局部作用域,JS中函数内部可以访问函数外部的变量,但函数外部却无法访问函数内部
的变量;
闭包就是能够访问其他函数内部的变量的函数,闭包的本质就是把函数内部和外部连接起来;
闭包有一个封闭性的特点:就是一旦形成闭包,那么外界就无法访问到闭包里面的数据q
闭包的优缺点
优点:可以模仿块级作用域,把变量保存在内存中,防止全局变量污染,就是减少创建全局变量,减少传递给函数的参数量;
缺点:虽然说防止了全局变量污染,但是这样容易导致内存泄漏,会让使用过的变量无法回收,一直占着内存;
应用场景:1.SetTimeout:原生的setTimeout传递的函数不能带参数,通过闭包可以实现传参效果。
2.回调:定义一个行为,然后把它关联到某个用户事件上。代码通常会作为一个回调绑定到事件上;
6.js继承
BOM:浏览器对象模型;DOM:文档对象模型;
1.构造函数继承:构造函数继承的中心思想就是把父函数的this指向改为子函数的this指向,从而实现继承;
优点:可以传递参数,借助call等改变this指向的方法;
改变this指向的方法:call 第二个参数与要改变指向中的方法的参数对应
apply 第二个参数是一个数组,数组中的元素与要改变的方法中的参数对应
bind方法使用后返回的是一个函数,所以第二个参数要在()里写,调用
缺点:他只能继承父函数本身的属性,父类原型的方法却不能使用;无法实现构造函数的复用。每个新实例都有父类构造函数的副本
2.原型链继承:原型链继承就是把子函数的原型改为父函数的实例,从而实现继承
优点:子类可以继承父类和父类原型中的属性和方法;
缺点:子类无法在继承的过程中给父类传递参数,因为子类的原型都是New Parent,所以实例化出来的对象都是一样的,
而且Parent上面的引用类型只要有一个实例对象修改了,其他实例对象也会跟着修改,因为他们的原型对象都是
共用的。
3.组合式继承:组合式继承就是把构造函数继承和原型链继承结合起来,从而实现继承;
优点:他使用原型链实现对原型属性和方法的继承,又通过借用构造函数来实现对实例属性的继承。这样既通过在原型
上定义方法实现了函数复用,又保证每个实例都有他自己的属性。
缺点:在使用组合式继承的过程中父类的原型对象被调用了两次,这个是没有必要的,而且子类实例的构造函数是来自父类;
4.原型式继承:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1.所有实例都会继承原型上的属性。2.无法实现复用。(新实例属性都是后面添加的)
5.寄生式继承:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
6.寄生组合式继承:在寄生式继承的基础上,将父类的原型传入包裹函数中,然后定义子类的构造函数,并在子类的构造函数中调用父类的构造函数,
然后生成子类的对象,修改子类的构造函数属性,实现理想的继承
优点:效率高 原型链保持不变
7.时间冒泡和事件捕获
事件类型:有键盘事件,鼠标事件,表单事件
事件:JS和HTML之间的交互是通过事件实现的,事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。
事件流: 事件流描述的是页面中接收事件的顺序
1.事件冒泡:就是事件开始时由嵌套最深的元素接收,然后逐级向上传播到最外面的那个节点;
阻止冒泡:1.js中的event.stopPropagation() 2.vue修饰符 .stop 加到你想要阻止冒泡的点击事件后面
2.阻止默认行为:1.js中的event.preventDefault() 2.vue中的.prevent
3.事件捕获:由嵌套最外面的节点先触发事件,最后是嵌套最深的节点触发事件
设置事件捕获:1.js中addEventListener(事件名字,function(){},true/false);true和false如果在未指定的情况下,默认为false,向上冒泡的
事件不会触发;
2. .captrue 在定义的事件后面写click.captrue
3.事件委托:利用事件冒泡的原理,指定某一个事件程序来管理某一类型的所有事件;比如子元素的事件交由父元素进行处理;
写法:jq:$("#ul").on("click",'li',function(){ js:ul.onclick = function(){
$(this); var event = event || window.event;
}) var target = event.target || event.srcElement;
}
8.h5和css3的新特性
h5:1. 用于绘画 canvas 元素;2.用于播放视频的 video 和 audio 元素;
3. 本地离线存储 localStorage 长期存度储数据,浏览器关闭知后数据不丢失;sessionStorage 的数据在浏览器关闭后自动删除。
4.增加语义化的标签:比如article、footer、header、nav、section
5.表单控件:date、time、email、url、search等;
css3:选择器、渐变background-image: linear-gradient线性渐变、radial-gradient径向渐变
变形box-shadow: 2px 2px 2px #000;
过渡动画transition: all默认值,所有属性都将获得过渡效果,none:没有属性会获得过渡效果, transition-duration:定义过渡效果花费的时间
transform属性: translate(x,y) 根据X轴和Y轴位置给定的参数,从当前元素位置移动,scale(*x*,*y*):改变元素的宽度和高度,rotate(*angle*):在参数中规定角度 旋转角度
盒子模型、flex弹性布局、媒体查询@media;
9.SessionStorage,LocalStorage,Cookie 的区别
他们都是保存在浏览器端,而且是同源的
LocalStorage:生命周期是永久的,关闭页面或浏览器之后localStorage中的数据也不会消失。就是除非主动删除数据,否则的话数据
永远不会消失;不参与和浏览器的通信,大小为5M
方法:LocalStorage.getItem(),setItem(),removeItem(),clear();
SessionStorage:生命周期是只在当前浏览器窗口中有效,SessionStorage是在同源的窗口中始终存在的数据。只要这个浏览器窗口没
有关闭,即使刷新页面或者进入同源的另一个页面,数据也还在。但是SessionStorage在关闭了浏览器数据就会销毁。
方法:SessionStorage.getItem(),setItem(),removeItem(),clear();
Cookie:生命周期只在设置的cookie过期时间之前有效,存放数据一般为4K左右,一般数量不能超过20个,cookie可以与服务端进行通
信,但是使用cookie保存过多数据会带来性能问题。而且cookie需要自己封装。总之cookie就是一个存放数据的东西,存放
客户端和应用设备上。
应用场景:用户注册,用户登录,购物车等
cookie的参数:name,value,域名,路径,是否是http,是否是https
cookie的操作
document.cookie = "username=sorber" name名字
document.cookie 获取cookie的内容
10.什么是深拷贝和浅拷贝,如何实现
深拷贝与浅拷贝都是针对与引用数据类型来说的;
浅拷贝只复制一层对象的属性,值引用;应用场景就是:对于只有一层结构的Array,Object想要拷贝一个副本时使用;
实现方式:1.使用Object.assign({},obj)第一个参数是一个空对象,第二个参数是你要复制的对象;通过这个方法我们知道浅拷贝不能修改基础的数据类型,可以修改引用的数据类型;
2.ES6中的...扩展运算符来进行浅拷贝的实现;
深拷贝就是递归复制了所有的层级和地址引用。就是拷贝多层,每一级别的数据都会别拷贝出来;应用场景就是复制深层次的object的数据结构;
实现方式:1.利用JSON.parse(JSON.stringify(obj));就是先将这个对象转换为字符串,再将字符串转换为一个对象,这样就实现了一个深拷贝的原理;
2.通过定义一个函数deep来实现,他的参数是一个obj对象,函数里面第一步先判断参数obj是否为一个对象,如果不是就返回return false;如果是的话就定义一个空的数组作为存储空间;
随后在遍历obj,如果内容是一个对象的话就把循环的当前项添加到上面创建的新数组中;最后在返回这数组;然后要是需要进行深拷贝的话就调用这个函数;
11.解构赋值
解构赋值语法是一种Javascript表达式。通过解构赋值,可以将属性/值从对象/数组中取出,赋值给其他变量。是Es6中的新语法,他的本质是模式匹配,就是
只要等号两边的模式相同,左边的变量就会被赋予匹配的右边的值,要是匹配不成功变量的值就是undefined;他是针对数组或者对象进行模式匹配,然后对
其中的变量进行赋值;他左边表示的是要解构的目标,右边表示解构源;解构赋值还是对赋值运算符的扩展;
应用场景:1.交换变量的值;2.让函数中返回多个值,函数只能返回一个值,但用解构赋值的话可以返回是一个数组或者对象;3.函数参数的定义;
4.提取json数据
12.ES6有哪些新扩展
1.新增了let和const两个块级作用域;和var一样都是定义变量的关键字,var是es5里面的;let和const是es6里面的;
区别:let声明的变量不可以自动提升;var声明的可以自动提升;let不允许在相同作用域里,重复声明一个变量,var可以;
let允许块级作用域的任意嵌套,外层无法读取内层作用域的变量,var可以;let声明的作用域只在当前代码块的{}内有效,let可以解决for循环i全局变量污染的问题;
const声明的是一个只可以读的常量。只要声明,常量的值就不可以改变。他和let一样const也是一个块级作用域,无法变量提升,重复声明
2.新增了箭头函数
箭头函数和普通函数的不同:他们的写法不同;this指向不同:箭头函数指向的是定义时的对象,普通函数是指向调用它的对象;
箭头函数不可以当作构造函数,就是不可以使用new命令,否则报错;箭头函数没有arguments对象,得到的是外层函数的参数;
总结:箭头函数,最开始就是为了解决this指向问题,箭头函数里面的this是定义的时候确定的,this一旦确定无法改变,箭头函数最好的就是简洁;
同时箭头函数一定是匿名函数,箭头函数适合于没有复杂逻辑和无副作用的纯函数场景下,比如map,filter的回调函数中;
最好不要在最外层定义箭头函数,因为在函数内部操作this会容易污染全局作用域。在箭头函数外部包一层普通函数,可以将this控制在可见范围内;
3.增加了解构赋值
4.模板字符串
传统的输出模板特别繁琐,而且容易拼接错误
ES6中的模板字符串是增强版的字符串,用反引号``,标识,它可以当做普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量;
模板字符串里还可以2放入花括号,在花括号里边可以写入任意JS表达式,还可以引用对象属性。而且模板字符串还可以调用函数;
5.ES6还新增了Set和Map数据结构
Set对象他类似于数组,且成员的值都是唯一的。他常见的方法有5种:add():添加某个值然后返回Set结构本身。size()返回Set实例的成员总数;
delete()删除某个值,返回一个布尔值,表示是否删除成功;has()返回一个布尔值,表示该值是否为Set的成员。clear()清除所有成员,没有返回值;
Set集合中的数据不允许有重复,可以做数组去重1.(...new set(arr)) 2.arr.forEach(item => set.add(item));
Map对象是键值对集合,和JSON对象类似,但是key不仅可以是字符串还可以是对象;
Map常见的方法也有5种:map.set()可以获取对象的属性;get()可以获取对象的name属性;size()获取元素的存储数;has()可以知道指定元素是否
存在;delete()可以删除指定属性
6.把for循环改为for of循环
for in是es5的标准,用来遍历Key值,遍历对象和数组,for of是es6的标准,用来遍历value值,遍历数组,不能遍历普通对象;
因为普通对象没有symbol属性,如果对象拥有symbol属性,就可以使用for of遍历;
symbol是es6新增的一种基本数据类型,他是一个独一无二的数据类型,在es5中对象属性名字都是字符串容易造成属性名冲突,为了避免这种情况
Es6就引入了symbol类型,Symbol值能够作为对象属性的标识符;
使用for in会遍历数组所有的可枚举属性,包括原型,所以for in更适合遍历对象;
for in遍历的是数组的索引,for of遍历的是数组的元素值
7.Es6新增了模块化
在Es6之前是JavaScript是没有模块系统的,那么他就无法将一个大程序拆分成若干个互相依赖的小文件;如果需要进行模块化操作,就需要从第三方引入;
在ES6中就提供了模块化,才让JavaScript第一次支持了module。ES6的模块化分为导出(export)和导入(import)两个模块;
模块可以理解为和函数代码块一样的功能,是封装对象的属性和方法的JavaScript代码,他可以是某单个文件,变量或者函数
而且引入模块和引入脚本是有区别的,前者更多的是按需引入加载,后者是无论使用还是不使用,全部一次性引入和加载,类似于通过script标签引入Jquery等,这些都是一次性引入的;
导出:Es6模块导出分为默认导出和指定导出,默认导出的话可以用任意名字来接收,比如导出的是export default module1; 接收的时候可以 import x,
如果要一次导出多个,需要用{}包裹,接收时必须与导出时同名
接收:接收用import {name,age} from './module.js'
在导出中除了export关键字,每一个声明必须和脚本中的一样,因为导出的函数和声明需要有一个名称;
导出数据,只需要在里边写上数据名就可以export {name,age} 导出函数只需要你定义好函数,然后把函数名导出就可以export sum;
8. (...)扩展运算符:用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。
9.新增了Promise关键字
13.promise是什么?有哪些状态和参数?如何使用?
Promise是什么?
Promise是异步编程的一种解决方案,从语法上讲,promise是一个对象,通过他可以获取异步操作的消息;Promise是一个内置的构造函数,他是通过new Promise来操作;
Promise其实就是一个方法,一个JS甚至是一个页面的后续JS代码的执行,因为他们都依赖于异步返回的数据,基于这个数据进行操作;
为什么会有Promise?
在ES5中处理异步,基本都是选择回调函数的请求方式,在请求到的成功回调函数里面继续写函数,长期就形成了回调地狱;在需要的操作少的时候
是可以接受的,但是在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,且难以维护;所以就出现了Promise最初就为了解决回调地狱的问题;
他采用链式调用的方式并且代码比较简洁明了且容易维护。
Promise的状态有哪些?
1.pending进行中,2.fulfilled/resolved -成功 3.rejected-失败
Promise对象代表一个异步操作,只有异步操作的结果,可以决定当前是哪一种状态,除此之外任何的操作都无法改变这个状态。
Promise原型上还有then(),catch(),all(),race()等方法;
then()是成功之后执行的一个方法;有两个参数,第一个参数是成功之后执行的,第二个是失败之后执行的;
catch()是失败后执行,可以捕获异常;
all()方法是在处理多个异步处理时非常有用,就是调用多个promise回调成功之后的统一处理;
race()方法在处理数据的时候,哪个结果获得的快,就返回哪个,不管结果本身是成功还是失败。可以用来测试多个接口的响应速度;
Promise怎么使用?
Promise是一个构造函数,所以我们在使用的时候是通过new Promise来实例化,它里面有两个默认的参数,resolve和reject是早就封装在构造函数里面的方法。
函数里面可以加一些逻辑,用来判断,返回成功就执行resolve,返回失败就执行reject;resolve方法可以把promise的状态从pedding改为resolved,。Promise有一个特性就是一旦改变
不会再变。所以只要变成resolved或者是rejected.那么他将不会再变。
从本质来说,Promise主要用来解决异步回调的回调嵌套过多,导致的地域回调问题,可以使用then链式方法捕获最后的结果,比如我们经常用的axios就是用的Promise方式处理异步请求;
14.请写出在vue中使用Promise封装api接口的思路
Promise中封装了原生的XHR,vue中为我们提供了axios来进行数据的请求,在vue项目少的情况下使用,会很方便,简单;但是如果在vue项目多的情况下
我们就需要在每一个vue项目中写axios请求,这样会比较繁琐并且比较消耗性能。所以我们需要对axios进行进一步的封装。
1.在src里面新建一个utils文件夹,在这个文件里边再放一个request.js文件,在这个文件里要做3件事,第一件事就是引入axios;第二件事就是用axios创建一个实例化的空对象取名叫Server,
通过Server设置请求拦截器(interceptors.request)和响应拦截器(interceptors.response)然后通过. use引入函数,请求拦截器就是当把数据发送出去,还没到达服务端的时候,拦截你的数据
看是否合法;请求拦截器函数里面有两个函数一个叫config,这个函数就是axios,当resolved调用成功之后返回 return config;;还有一个叫error,这个是rejected失败之后掉用的;
失败之后返回return Promise.reject(error);
第三件事就是设置响应拦截器:响应拦截器就是服务端响应回来,但是数据还没有到达我们客户端的时候;interceptors.response.use;他也有两个函数,一个就是成功之后的response(),这里边
可以判断一下,如果status状态为200的话就只返回一个data数据,否则的话就返回一个空字符串;这样可以节省很多代码;如果失败的话和请求拦截器一样返回return Promise.reject(error)错误;
最后在封装好后,导出模板实例化对象;需要把Server给导出去export default Server;然后在main.js里面引入,import axios from '../utils/server.js'
Promise封装api可以用来处理一些公共数据,提高了安全性;
15.Ajax是什么?以及如何创建Ajax?
Ajax是什么?
ajax主要是用来实现客户端和服务端异步通信的效果,实现页面的局部刷新,ajax原生方式主要是通过XMLHttpRequest,ActiveObject(IE)对象来实现异步通信效果
ajax的优势在哪儿?
1.不需要插件的支持,可以直接被大多数主流的浏览器支持
2.提高web程序性能:传统模式是通过form表单,数据获取是通过页面刷新获取整页内容,ajax可以通过XMLHttpRequest对象向服务器请求数据;
3.提高了用户体验 4.无须刷新页面即可获取数据
Ajax的应用场景
用户登录注册,检测用户数据是否重复
做城市选择,用到二级联动或者三级甚至更高时,可以使用Ajax;
如何创建Ajax?
1.创建一个对象,let xhr=null,创建一个请求:XMLHttpRequest,ActiveObject();
2.使用open方法初始化请求:xhr.open('get','地址') 他第一个参数是请求数据的方式,第二个参数是请求的url地址
3.设置header头 ajax跨域不能设置header头:xhr.setRequestHeader()设置http头信息;
4.设置回调函数:xhr.onreadystatechange = function(){};
5.通过send()发送请求
jq方式:通过$ajax({-
url:'地址',type:'get'请求方式,async: true,是否为异步,dataType:'json'数据的类型,success:(res)=>{成功之后的业务逻辑},error:(error)=>{失败之后}
})
XMLHttpRequest对象的常用方法和属性
方法:open()初始化 send()发送请求 setRequestHeader 设置请求头
属性:onreadystatechange:用于指定状态改变时触发的事件处理器 readyState:获取请求状态
responseText 获取服务端响应内容 status:http状态码
常见的http状态码
200:请求成功 301请求资源移动到新的url地址 403客户端请求无权限,服务器拒绝请求 404找不到文件
500服务内部错误,一般是服务端代码有问题 502网关错误,服务端返回无效响应 503服务器性能问题导致,无法处理客户端请求
16.Ajax请求的时候get和post区别?
get传递参数显示在url地址中,post参数通过http消息formdata发送给服务器
get提交的数据有长度限制,原因是特定的浏览器url有长度限制,而post请求一般没有长度限制
get方式请求的数据会被缓存起来,所以相对来说不太安全,post相对来说比较安全
同等条件下,get传输数据会比post快一些
17.什么是跨域和解决跨域的方法
1.同源策略
要了解跨域就要先知道同源策略;同源策略是浏览器的一种约定,他是浏览器最核心也是最基本的安全功能,同源指的就是,同协议,同域名,同端口,
同源策略的目的就是限制不同源的document或者脚本之间的相互访问,以免造成干扰和混乱。
2.为什么会有同源策略
如果没有了同源策略,浏览器的一些正常功能可能都会受到影响,因为ajax是很灵活的,他可以发任何的请求,如果没有同源策略的限制,那么只要你
构造好参数和请求路径你的请求想往哪发就往哪发,这样太不安全了,会导致各种数据泄露;有了同源策略,那就不能随意发送请求了。
3.跨域的发生和解决方式
当一个请求url的协议,域名,端口,三者之间任意一个与当前页面的url不同即为跨域;
跨域的解决方式常见的有三种
1.cros服务端操作:把当前请求地址加入可允许访问的header中 Access-Control-Allow-Oragin
2.vue中的代理方式
在vue中使用axios也可以配置跨域,在/config/index.js中将里面的target设置为我们要访问的域名。也就是后台ip地址。
再把changeorigin:true,设置为true开启反向代理,在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样客户端和服务端进行数据的交互就不会有跨域问题
最后pathRiwrite{'^/api':''}设置为空,这里理解成用'/api'代替target里面的地址
3.jsonp是服务器与客户端跨源通信的方法。最大的特点就是简单适用,兼容性好,缺点是只支持get请求,不支持post请求;
jsonp实现的原理:主要是利用动态创建script标签请求后端接口地址,然后传递callback参数,后端接收callback,后端再经过数据处理返回
callback函数调用的形式,callback中的参数就是json;
jsonp使用场景:在jquery的api接口中使用,dataType设置为jsonp,也可以在script标签中通过src调用,需要传递callback回调函数
还可以在vue-resource插件中`this.$http.jsonp('url',{}).then(res=>{})`
ajax的核心是通过XMLHttpRequest获取非本页内容,jsonp的核心是通过script标签来调用服务器提供的js脚本;
jsonp只支持get请求,而ajax支持get和post请求
18.vue中methods,computed,watch的区别
首先就是这三个都是以函数为基础的,但他们却都不相同;
computed:他是当页面中有某些数据依赖于其他数据的变化进行改变的时候,可以使用computed的计算属性,计算属性具有缓存性;
computed是在HTML,DOM加载后马上执行的,比如赋值操作;
在需要对很多的数据进行处理和计算并且有另一个值需要依赖这个数据进行变化的时候就需要计算属性;
watch:watch和computed很相似,watch是用来观察和监听页面上的vue实例,在大部分情况下我们还是会使用computed,但如果要在数据变化
的同时进行异步操作的时候,warch是比较合适的选择。watch作为一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是
方法名;
如果在data中没有相应的属性的话,是不能使用watch的。
watch有一个特点,就是当值第一次改变的时候不会执行监听函数的。如果我们需要在最初绑定值的时候也
执行函数就需要用到immediate属性;就需要将immediate设为true;为true的时候就会立马执行handler方法,这个是vue规定的写法,当watch的值发生变化的时候就会触发;
deep属性:当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能监听到变化时,
就需要deep属性对对象进行深度监听;
methods:methods是应用于逻辑和方法的处理,只要调用就会重新执行一次,这个调用是需要有一定的触发条件,比如点击事件;
methods和computed最大的区别就是computed依赖于data中的数据,而方法不依赖;这个依赖就是如果data中的数据发生变化,computed
会根据函数里面包含的计算属性重新计算;
总结:他们的形式都是function,而本质的话computed依赖于data中的数据;场景的话:methods是应用于逻辑和方法的处理;其余两者都是监听
data中的数据;写法上:methods可以带参数和返回值,不过不是必须的是可有可无;computed:必须携带返回值,不允许带参数;
watch:不允许带参数和返回值;用法上:methods:是使用一次调用一次;computed:一次调用,可以看做data;watch:调用一次
永久使用;使用位置:methods:在生明周期函数中使用;computed:和data一样可以在vue标签{
{}}中使用;watch:一般在生命周期
函数或者在methods被其他方法调用;
19.vue双向数据绑定原理
vue的双向数据绑定原理是采用数据劫持结合发布者和订阅者模式的方式,再利用Object.defineProperty()来劫持各个属性的setter,getter,在数据
变动时发布消息给订阅者,在触发相应的监听回调;
其实就是通过Object.defineProperty()这个方法和里面的get()获取属性值和set()设置属性值这两个方法操作的;它里面有两个常用参数,第一个
参数就是定义的对象的名字;比如var obj = {},obj就是第一个参数,第二个参数是要定义或修改的属性的名称,比如要定义obj对象里的name属性;get是获取属性,set是修改属性;
实现过程:1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Wather,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始话相应的相应的订阅器
20.prop 验证,和默认值
props:会接受不同的数据类型和设置默认值 ;有六种数据类型:Number,String,Object,Function,Array,Boolean;
props数据是单项数据传递,父不影响子,子不影响父;而且不能在组件中直接修改prop传递的值,Vue会发出警报;
在vue中父子组件的关系可以总结为props向下传递,事件向上传递。父组件通过prop给子组件下发数据,子组件通过事件给父组件发送消息。
prop是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来就不会了。这是为了阻止子组件无意间修改了父组件的状态,避免了
应用的数据流变得难以理解。
解决办法:将想要更改的值,传递给父组件,在父组件中更改,在传递给子组件。
具体步骤:先将值传递给子组件,子组件props接收并使用,然后通过$emit广播一个事件给父组件,并将值传递给父组件,父组件接收子组件广播
过来的事件,并定义一个方法,在该方法中改变传递过来的值,父组件又会将值传递给子组件,这样就形成了一个闭环,问题就解决了。
21.vue组件父子,子父看,兄弟通信
vue中组件的引入是通过在父组件中使用import {Son} from 后面写入组件路径 ,然后在局部组件components中注册子组件标签名字;
在父组件template标签中引入子组件的标签即可
父传子:是通过prop属性来进行的,现在父组件中的子组件标签上绑定一个自定义属性,用于绑定要传递的值;然后在子组件中使用prop属性进行
数据的接收,可直接使用;prop中可以对传递过来的数据进行数据类型验证,设置默认值等;接收完的数据直接在子组件中使用,不需要在data中定义;
子传父:子传父主要是通过事件绑定的方式完成,在子组件元素中绑定一个事件,触发事件后,在事件中使用$emit,里面有两个参数(自定义事件,传递的值),
在父组件中的子组件标签上绑定一个自定义事件,事件名必须是$emit中的事件名,自定义事件调用父组件自己定义的函数;
最后给父组件的函数设置形参,形参中存储的就是子组件传递过来的值。采用事件传递方式
兄弟组件传值:有两种方式可以实现
一种是通过创建一个bus.js的文件,在这个文件里面导出一个空的vue对象,在需要传递值和接收值得两个组件中都引入bus.js文件,在
发布数据的组件中通过bus.$emit(定义的事件,值)来传递数据;在需要接收数据的组件中通过bus.$on(自定义事件,(data)=>{})接收
里面的data就是接收到的值;
第二种就是vuex的方法实现:在需要使用的组件中使用this.$store.state对象就可以使用仓库中state里面的数据;所有组件都可以使用,
这样就完成了兄弟组件的传值;
22.vue中的生命周期
有八个生命周期
beforeCreate(创建前):这是数据创建完成之前,这个阶段实例的data,methods这些是都访问不到的
Created(创建后):数据加载完成,是最早能够获取数据的函数无法获取DOM节点,这个阶段已经完成了数据观测,属性和方法的运算,但是数据并没有
在DOM元素上进行渲染;可以从服务器获取一些初始化的数据,还有通过ajax向服务器发送一些数据。
beforeMounted(挂载前):数据加载完成之后,DOM加载完成之前,只是模板和数据进行结合,但是没有挂载到页面上,可以在这里进行数据的最后修改
Mounted(挂载后):DOM节点挂载完成之后,最早可以操作DOM的函数;可以完成模板中的html渲染到页面上。这里面可以进行ajax交互。可以进行axios
数据请求;而且mounted只会执行一次;
beforeUpdate(更新前):在数据更新之前调用;会更新当前组件数据,但不会在页面渲染出来;
Updated(更新后):data数据改变的时候,影响到DOM的时候;在这里可以获取到最新的DOM结构;
beforeDestroy(销毁前):在实例销毁之前调用,这个时候实例还可以使用,在这里可以清除一些组件中的定时器和监听dom事件
Destroy(销毁后):实例化销毁的时候触发;所有的事件监听器都会被清除,这个函数在服务器端渲染期间不被调用;
第一次加载页面只会触发前四个钩子函数;
23.vue路由传参如何实现
有query和params两种传参
query分为视图导航模式:格式就是:to="/path"+参数列表,在router-link里边写
编程导航:是通过this.$router.push({path:'路径+参数'}),获取参数的时候是this.$router.query.参数名
params传递参数动态路由导航:在路由中找到指定路由的path:在后面加/:id;
视图导航模式:在router-link标签上加:to后面拼接"'/路由地址/'+item.id"来进行路由跳转并传参
编程导航模式:通过this.$router.push({name:'Detail'通过name属性来进行跳转},params:{id:id});获取参数就是:this.$route.params.id;
区别:query要通过path来引入,params要通过name引入,接收参数都是一样的只不过一个是用.query一个是.params;
query是类似于我们ajax中的get传参,params是类型于post传参,就是query在浏览器地址中显示参数,后者不显示;
24.路由导航模式有几种,如何实现
这个就是vue-router提供的导航守卫主要是用来通过跳转或取消的方式守卫导航。通俗的说就是一个拦截器;
钩子函数有几种参数:to:即将要进入的路由对象;from:当前导航正要离开的路由;next:进行管道中的下一个钩子,必须调用,他里面的参数
为false就终止执行,为true的话就继续执行,里面是一个路由路径的话跳转至指定的路由;
分为全局守卫:有beforeEach、beforeResolve、afterEach(在路由实例对象注册使用);
beforeEach(全局前置守卫)可以进行一个判断,比如让一些用户通过一些用户不通过;如果用户名字是想要通过的那个,就执行next()
如果不是就得注意一个问题,不能直接写next(指定路径),因为那样会造成死循环,直接执行跳转的时候,又会触发beforeEach方法,这样
就成了一个死循环,所以要再加一个判断:就是判断如果要去的路由是指定路径的话执行next(),跳转到指定路径,else的话还是跳转到
该路径,这样都是跳转到该路径,就不会造成死循环了;
beforeResolve(全局解析守卫):和beforeEach类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件解析之后,解析
守卫就会被调用;
afterEach(全局后置钩子):这个是全局后置钩子,他和守卫不同的是,这些钩子不会接受next函数也不会改变导航本身;
路由专属守卫:在配置路由的时候设置,他只有一个路由守卫beforeEnter;
组件内部守卫:有三个方法:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave(在组件属性中定义)
beforeRouteEnter在渲染该组件的对应路由被确认前调用;他不能获取组件实例this因为当前守卫执行前,组件实例还没被创建,可以
通过传一个回调给next来访问组件实例,在导航被确认的时候执行回调,并把组件实例 作为回调方法的参数;
beforeRouteUpdate:在当前路由改变,该组件被复用时调用,这个可以访问组件实例this
beforeRouteLeave:导航离开该组件的对应路由时被调用,他也可使用组件实例this;
25.vuex 中 state,getters,mutations,actions,modules的用途和用法
state 数据源载体,保存着所有的全局变量
getters 用于改变state的值,对state中的数据派生出一些状态,例如对数据进行过滤。会对state中的变量进行过滤再保存,只要state中的变量发生了改变,它也会
发生改变,不变化的时候,使用的是缓存。
mutation 唯一可以提交可以改变state的状态,也就是数据的属性值,他是通过直接改变状态的方式改变state,而且mutation必须同步执行,mutations相当于生成了修改全局
变量的事件函数,所以触发的时候需要事件驱动。因为他返回的是promise所以他是一个异步操作;
actions 他类似于mutation,不同就在于Action提交的是mutation,而不是直接变更状态。Action可以包含任意的异步操作;
Action他接受一个与store实例具有相同方法和属性的context对象,里面有commit方法和state属性等;触发action通过store.dispatch方法触发;
modules 由于使用单一状态树,应用的状态会集中到一个比较大的对象。当应用变得非常复杂的时候,store对象就有可能变得相当臃肿。为解决这个问题,vuex允许
我们将store分割成模块也就是Module,每个模块拥有自己的state,mutation,action,getter。甚至是嵌套子模块;需要注意的是modules模块中的state不能通过
this.store.state获取,必须加上module的命名空间;但是getters和mutations能正常使用;
总结:state中的状态数据,只能通过Mutation来修改;getters是来获取state中的数据,只会读取;
actions是处理mutation的;modules是来分模块处理全局状态的;
mapState,mapGetters是来获取全局变量的,作为计算属性处理;
mapMutations,mapActions相当于事件处理函数,放在methods中,等待触发;
mapState,mapGetters,mapMutations,mapActions后面可以是对象,也可以是数组,数组里放原方法或属性名;对象,或者自己定义新的方法或属性名;
26.vue 中 key 的作用
在生成虚拟dom的过程中,相同的组件产生相同的dom结构,不同的组件产生不同的dom结构,同一层级的dom节点,他们可以通过唯一的id
进行区分,这个id就是key。
作用:高效的更新虚拟dom
27.vue 自定义指令如何使用
很多时候我们需要直接操作 dom 元素,如果只是个别需要操作 dom 元素,我们可以通过 ref 获取当前 dom 元素,并对其进行操作,但是如果
特别多的时候,我们不可能每次都去写一遍 ref 还有方法,所以这时候自定义指令就可以帮你轻松解决这个问题
分为全局和局部;
钩子函数:
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
钩子函数的参数:
**el**: 指令所绑定的元素,可以用来直接操作 DOM,就是放置指令的那个元素。
**binding**: 一个对象,里面包含了几个属性:value:指令的绑定值,name:指令名等;
**vnode**:Vue 编译生成的虚拟节点。
**oldVnode**:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
28.vue 常用修饰符
事件修饰符:
.prevent: 提交事件不再重载页面
.stop: 阻止单击事件冒泡
.self: 当事件发生在该元素本身而不是子元素的时候会触发
.capture: 事件侦听,事件发生的时候会调用
.once 只执行一次
面试需要答的:
.trim - 输入首尾空格过滤
.number - 输入字符串转为有效的数字
.lazy - 取代 input 监听 change 事件
.passive:addEventListener中的第三个参数,表示 listener 永远不会调用 preventDefault()
.native:组件绑定当前组件的事件是不会触发的,需要用native才能触发
.sync:对prop进行双向绑定
29.keep-alive 的作用
keep-alive是Vue中的内置组件,能在切换过程中把状态保留在内存中,防止重复渲染DOM
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
prop:
- include: 字符串或正则表达式。只有匹配的组件会被缓存。
- exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
keep-alive生命周期钩子函数:activated、deactivated
场景:Vue中前进刷新,后退缓存用户浏览数据
列表页面 =>点击进入详情页=> 后退到列表页 要缓存列表原来数据
重新进入列表页面 => 获取最新的数据
30.什么是虚拟dom,和 diff 算法
什么是虚拟DOM
可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。
将原本需要在真实dom进行的创建节点,删除节点,添加节点等一系列复杂的dom操作全部放到vdom中进行,这样就通过操作vdom来
提高直接操作的dom的效率和性能。
虚拟DOM的最终目标是将虚拟节点渲染到视图上
diff算法分为一下几个步骤
- 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中
- 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异
- 把所记录的差异应用到所构建的真正的DOM树上,视图就更新了
虚拟DOM就是对于复杂的文档DOM结构提供了一种方便的工具,用于最小化的dom操作本质上是通过JAVAScript来描述DOM之间的元素关系的;
作用是能够更高效的渲染和更新视图实现原理是通过Dff算法来实现,就是比如当前页面的数据发生改变时,dff算法会比较同一层级的节点,如果节点类型不同,
那么会直接干掉前面的节点,重新创建一个新节点,然后插入这个新节点,而不会再比较这个节点以后的子节点了,如果节点类型相同,那么会直接重新计算该节点的属性,对节点进行更新
这就是dff的一个默认执行的操作,通常我们去渲染节点时,需要结合key属性来去使用,作为唯一标识,能够让dff正确识别当前节点,如果数据发生改变,或插入了新的节点时,
这个时候dff算法就可以快速的找到当前需要修改的节点位置,去做视图更新,从而减少了dom重复的操作,大大地优化了网页性能
31.图片懒加载
当打开一个有很多图片的页面时,先只加载页面上看到的图片,等滚动到页面下面时,再加载所需的图片。这就是图片懒加载。
作用:减少或延迟请求数,缓解浏览器的压力,增强用户体验。
实现方法:1、设置图片src属性为同一张图片,同时自定义一个data-src属性来存储图片的真实地址
2、 页面初始化显示的时候或者浏览器发生滚动的时候判断图片是否在视野中
3、 当图片在视野中时,通过js自动改变该区域的图片的src属性为真实地址
1.document.documentElement.clientHeight获取屏幕可视窗口大小;
2.document.documentElement.scrollTop获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离
3.判断当滚动条滚动到一定高度的时候就进行图片懒加载;
32.瀑布流原理
瀑布流的实现原理就是通过比较每一列的高度,如果这一列高度低的话就在这一列进行添加;
实现步骤:1.获取放图片的div和div里面的图片元素;
2.通过window.onload=function(){}在页面加载的时候执行定义的函数;
3.定义一个变量columns计算出页面中有多少列=外层盒子的宽度box.offsetWidth/子元素的宽度items[0].offsetWidth最后计算的时候用parseInt除成整数
4.循环所有的元素,在循环里面判断如果i小于columns的话就把每一项的top值设置为0;把元素的left值设置为元素的宽度乘以下标值;然后在循环外面定义一个空数组
把每一项的高度都添加进去(items[i].offsetHeight);然后就是i>columns的逻辑,在这里面定义一个空变量为minHeight为最小高度,这个最小高度让他默认为0;
在定义一个变量为Index为0;然后在写一个循环,循环内容就是每个上面存储每一项高度的数组,然后再通过if判断找出最小的高度值,逻辑就是如果当前循环的高度小于
上面定义的minHeight最小高度的话,就让minHeight等于这个高度,然后再让index等于这个元素的下标;
5.最后一步就是把后面的元素插入到高度最小的元素下面,让循环的当前项的top值为最小高度,让他到这个元素的下面;left值为当前项距离外层盒子的Left值;
33.从输入URL到页面加载完成期间经历了什么?
1.通过DNS服务器:url=>ip地址;
2.到达ip地址对应的服务器;
3.服务器接收用户的请求;
4.把处理后的结果返回给客户端;
5.客户端把结果渲染到浏览器即可,最后页面显示出来;
34.vue2.0和3.0区别
1.默认进行懒观察
在 2.x 版本里,不管数据多大,都会在一开始就为其创建观察者。当数据很大时,这可能会在页面载入时造成明显的性能压力。
3.x 版本,只会对「被用于渲染初始可见部分的数据」创建观察者,而且 3.x 的观察者更高效。
2.更精准的变更通知
比例来说:2.x 版本中,使用 Vue.set 来给对象新增一个属性时,这个对象的所有 watcher 都会重新运行;3.x 版本中,只有依赖那个属性的 watcher 才会重新运行。
3. 3.0 新加入了 TypeScript 以及 PWA 的支持
4.部分命令发生了变化:4
1.下载安装 npm install -g vue@cli 2.删除了vue list 3.创建项目 vue create 4.启动项目 npm run serve
5.默认项目目录结构也发生了变化:
1.移除了配置文件目录,config 和 build 文件夹
2.移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中
3.在 src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件
35.react生命周期函数
React的生命周期从广义上分为三个阶段:挂载,渲染,卸载;因此可以把React的生命周期分为两类:挂载,卸载过程和更新过程。
挂载,卸载过程
1.constructor():constructor()完成了React数据的初始化,他接受两个参数:props和context,当想在函数内部使用这两个参数的时候,需要使用super()传入这两个参数;
需要注意的是只要使用了constructor()就必须写super(),否则会导致this指向错误;
2.componentWillMount():这个一般用的比较少,他更多的是在服务端渲染时使用。他代表的过程是组件已经经历constructor()初始化数据后,但是还未渲染DOM时。
3.componentDidMount():组件第一次渲染完成,此时DOM节点已经生成,可以在这里调用Ajax请求,返回数据setState后组件会重新渲染;
4.componentWillUnmount():在这里完成组件的卸载和数据的销毁。会做2件事:(1):clear清除你在组件中所有的setTimeout,setInterval;(2):移除所有组件中的监听:removeEventListener;
更新过程
5.componentWillReceiveProps(nextProps):在接收父组件改变后的props需要重新渲染组件时用到的比较多;他会接收一个参数nextProps;通过对比nextProps和this.props,将nextProps的state
作为当前组件的state,从而重新渲染组件;
6.shouldComponentUpdate(nextProps,nextState):主要用于性能优化(部分更新);唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的
流程,在这里return false可以组织组件的更新;
7.componentWillUpdate(nextProps,nextState):shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState。
8.componentDidUpdate(prevProps,prevState):组件更新完毕以后,react只会在第一次初始化成功时进入componentDidmount,之后每次重新渲染都会重新进入这个生命周期,这里可以拿到
prevProps和prevState,也就是更新前的props和state;
9.render():render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的
DOM节点,并重新渲染。
36.类组件(Class component)和函数式组件(Functional component)之间有何不同?
函数式组件又称无状态组件,无状态组件就是他没有自己的state状态管理,他只能接收父组件props传递过来的数据;无状态组件主要用来定义模板;
Class组件又称有状态组件,他有自己的state状态管理,使用this.state.数据的这种表达式把业务数据挂载到组件的实例上,然后传递props到展示组件,展示组件接收到props,把props放到模板里。
类组件里面有一个constructor()这个就是组件的构造方法,只要使用了他就必须使用super(),这个就是指向组件的构造方法;
37.何为受控组件(controlled component)?
React组件的数据渲染是否被调用是通过传递过来的props完全控制,控制为受控组件,否则为非受控组件;例如:要实现利用父组件的数据控制子组件中内容的显示与隐藏;
38.generator(异步编程、yield、next()、await 、async)
Generator是一个函数,可以在函数内部通过yield返回一个值(此时,Generator函数的执行会暂定,直到下次触发.next());
使用流程:
1.创建一个Generator函数的方法是在function关键字后添加*标识。
2.在调用一个Generator函数后,并不会立即执行其中的代码,函数会返回一个Generator对象,通过调用对象的next函数,可以获得yield/return的返回值。
3.无论是触发了yield还是return,next()函数总会返回一个带有value和done属性的对象。
4.value为返回值,done则是一个Boolean对象,用来标识Generator是否还能继续提供返回值。
需要注意的是:Generator函数的执行时惰性的,yield后的代码只在触发next时才会执行;
next()我们可以在调用next()的时候传递一个参数,可以在上次yield前接收到这个参数:
应用场景:1.因为Generator对象是一个迭代器,所以我们可以直接用于for of循环;2.模拟实现Promise执行器
async await
async 是 ES7 才有的与异步操作有关的关键字,在定义函数的时候在函数的前面加上async 函数返回的是promise
await 操作符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用。也就是async可以没有await,但是await必须要有async
39.Axios 拦截做过哪些?
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。有几点优势:1.可以从浏览器中创建 XMLHttpRequests 2.从 node.js 创建 http 请求 3.支持 Promise API
4.拦截请求和响应 5.转换请求数据和响应数据 6.自动转换 JSON 数据;
可以在请求或响应被 then 或 catch 处理前拦截它们。可以为自定义 axios 实例添加拦截器;
请求拦截可以用它做我们的loading 加载和数据的权限验证,包括我们所有的数据预加载也可以实现;
响应拦截:axios 拦截可以配置公用地址,以及对于跨域问题解决
40.meta 标签内属性及详解
1.keywords:用来告诉搜索引擎,你网页的关键字;
2.description:用来告诉搜索引擎,你网站的主要内容;
3.viewport:移动端的窗口:width=device-width宽度等于当前设备的宽度;initial-scale=1.0初始缩放比例,默认为一倍;minimum-scale=1.0/maximum-scale=1.0最小/大缩放比例;
user-scalable=no是否允许用户缩放页面;
4.robot:用来告诉爬虫哪些页面需要索引,哪些页面不需要索引。属性值为content,content参数有all,index搜索引擎将索引此网页,follow继续通过此网页的链接索引;
none将忽略此网页;noindex 搜索引擎不索引此网页;nofollow搜索引擎不继续通过此网页的链接索引搜索其他的网页;
5.author用于标注网页作者;
6.generator网页制作软件;
7.copyright版权;
8.revist-after重访;
9.renderer他是为双核浏览器准备的,用于指定双核浏览器默认以何种方式渲染页面;
10.expires期限,可以设定网页的到期时间。一旦网页过期,必须到服务器上重新传输;
11.Pragma禁止浏览器从本地计算机的缓存中访问页面内容;
12.Refresh刷新,自动刷新并指向新页面;里面有个content=2是指停留2秒钟后自动刷新到URL网址;后面的分号是在秒数的前面和网址的后面;
13.Set-Cookie用于cookie的设定,如果网页过期,那么存盘的cookie将被删除;
14.Window-target显示窗口的设定,强制页面在当前窗口以独立页面显示;
15.content-Type显示字符集的设定,设定页面使用的字符集;
16.content-language显示语言的设定;
17.cache-control指定请求和响应遵循的缓存机制,
41.对BFC规范(块级格式化上下文:block formatting context)的理解?
BFC 就是“块级格式化上下文”的意思,创建了 BFC 的元素就是一个独立的盒子,不过只有 Block-level box 可以参与创建 BFC, 它规定了内部的 Block-level Box 如何布局,
并且与这个独立盒子里的布局不受外部影响,当然它也不会影响到外面的元素。
BFC 有一下特性:
内部的 Box 会在垂直方向,从顶部开始一个接一个地放置。
Box 垂直方向的距离由 margin 决定。属于同一个 BFC 的两个相邻 Box 的 margin 会发生叠加,
每个元素的 margin box 的左边, 与包含块 border box 的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
BFC 的区域不会与 float box 叠加。
触发条件:
float的值不为none(默认)
overflow的值不为visible(默认)
display的值为inline-block、table-cell、table-caption
position的值为absolute或fixed
BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然。
计算 BFC 的高度时,浮动元素也参与计算。
42.Object.defineProperty()方法有何作用?
作用:Object.defineProperty方法会直接在对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
在vue中通过getter和setter函数来实现双向绑定;
语法:他有三个参数object,propName,descriptor
参数解释:object:要定义属性的对象,返回的也是;propName:要定义或修改的属性名称。
descriptor:要定义或修改的属性描述符
描述符:1.value描述符:设置属性值,默认值为undefined。
2.writable描述符:设置属性的值是否可写,默认值为true。
3.enumerable枚举描述符:设置属性是否可枚举,就是是否使用for/in语句或Object.keys()函数遍历访问,默认为true。
4.configurable描述符:设置是否可配置属性特性,默认为true。如果为false,将无法删除该属性,不能够修改属性值,也不能修改属性的属性描述符。
43.vue 中数组中的某个对象的属性发生变化,视图不更新如何解决?
这种情况分为两种
第一种是数组的值改变,在改变数组的值的时候使用索引值去更改某一项,这样视图不会实时更新,这种情况是因为直接通过索引去改变数组,vue对象监听不到他的变化,所以没有更新;
解决方法:使用vue的变异方法pop(),push(),shift(),unshift(),revese(),sort(),splice()等方法也会触发视图更新
第二种是改变了对象的某一项,但是其他依赖这个数据的视图没有更新,比如父组件和子组件公用一份数据,数据通过props传到子组件,在子组件中修改数据父组件中不会响应;
解决方法:1.利用vue.set(object,key,val):例:vue.set(vm.obj,'k1','v1');
2.利用Object.assign({},this.obj)创建新对象;如果是数组就把花括号改为中括号;
3.先删除掉那一项,然后再使用set去添加;
扩展:
1.vue鉴权
vue鉴权一般就是指管理后台的权限验证,先从登录说,当用户登录成功后,服务端接口一般会给用户分配一个token用于校验用户是否登录,当用户进入管理后台页面
的时候,我们可以通过token获取当前登录用户的角色,以及当前用户可以访问的路由地址列表,我们可以把用户可以访问的地址列表存储在本地。
后台的鉴权可以从两方面处理,一部分就是用户进入后台后,根据用户可以访问的路由地址信息,渲染出左侧的菜单栏部分,这样的话就只能访问左侧二级菜单相关的页面。
但是用户可能不是通过左侧二级菜单访问,可能是直接在浏览器输入路由地址访问,这个时候我们就得考虑使用路由守卫,路由守卫中有一个to方法,可以获取用户即将要
的路由地址,用这个地址跟用户存储的可访问的路由地址进行比较如果在用户可访问的地址列表中,就执行next(true),否则的话直接跳转到自定义的403页面提示,提示
用户无权限访问当页面。