CSS相关

css3新增特性有哪些

css3比css2多了好多针对移动端的特性

  • 圆角:border-radius
  • 盒阴影:box-shadow
  • 动画:transition(过渡),transform(实现位移,倾斜,旋转,绽放),animation(关键帧动画)等

    如何实现一个div垂直居中(至少3种方法)

  • 定位:

    • 第一种思路:通过给div设置绝对定位,并且**left,right,top,bottom**设置为**0,margin:auto**即可以水平垂直居中
    • 第二种思路:通过给div设置绝对定位,**left为50%,top为50%**,再给div设置距左是自身的一半即:**margin-left:自身宽度/2,margin-top:自身高度/2。**
    • 第三种思路:通过给div设置绝对定位,left为50%,top为50%,再给div设置跨左和跟上是自身的一半:**transform:translate3d(-50%,-50%,0)**
  • flex布局:

    • 思路:有两个div,父级div和子级div,给父级div设置display:flex,并且设置父级div的水平居中justify-content:center,并且给父级div设置垂直居中align-items:center即可

      clearfix是解决什么问题的(另一种问法div塌陷问题如何解决的,或者说一下BFC)

  • 解决的方法有很多,主要目的是让父级元素有高度

    • 给父级元素设置绝对定位**:position:absolute**
    • 给父级元素设置**overflow:hidden;**
    • 通过伪对象来实现
      1. .clearfix:after {
      2. content: " ";
      3. display: block;
      4. clear: both;
      5. height: 0;
      6. }

对盒模型的理解(包括IE和w3c标准盒模型)

盒模型其实就是浏览器把一个个标签都看一个形象中的盒子,那每个盒子(即标签)都会有内容(width,height),边框(border),以及内容和边框中间的缝隙(即内间距padding),还有盒子与盒子之间的外间距(即margin)

用图表示为:
image.png

  • 当然盒模型包括两种:IE盒模型和w3c标准盒模型
    • IE盒模型总宽度即就是width宽度=border+padding+内容宽度
    • 标准盒模型总宽度=border+padding+width
  • 那如何在IE盒模型宽度和标准盒模型总宽度之间切换呢,可以通过box-sizing:border-box或设置成content-box来切换

    • 其中:box-sizing:border-box //IE盒模型
    • box-sizing:content-box //w3c盒模型

      css3动画:

      哦,您问的css3动画啊,css3动画大致上包括两种

  • 第一种:过渡动画:主要通过transition来实现,通过设置过渡属性,运动时间,延迟时间和运动速度实现。

  • 第二种:关键帧动画:主要通过animation配合@keyframes
  • **transition**动画和**animation**动画的主要区别有两点:

    • 第一点transition动画需要事件来触发,animation不需要
    • 第二点:transition只要开始结束两种状态,而animation可以实现多种状态,并且animation是可以做循环次数甚至是无限运动

      rem和em的区别

  • rem和em都是相对单位,主要参考的标签不同

    • rem是相对于根字号,即相对于标签的font-size实现的,浏览器默认字号是font-size:16px
    • em:是相对于父元素标签的字号,和百分比%类似,%也是相对于父级的,只不过是%相对于父级宽度的,而em相对于父级字号的

      手机端如何做适配的

      前端做适配没有最好的方法,只有适合的方法,目前前端主要做适配的方法有: — 百分比,em,rem,媒体查询(即media query),flex布局(即弹性盒),vw,vh等

  • 目前我在项目中用的多的是rem,flex布局,有时会用到媒体查询,在做pc响应式布局时用

  • 主要是用了一个手淘的js库flexible.js,在页面变化时,检测页面宽度,除以10份,动态的赋值给font-size.属性.;而页面的布局我是通过rem来进行布局的,所以就可以适配所有的移动端设备了

    vw和vh了解吗

  • vw和vh是最近2年才慢慢火起来的css布局单位,现在已经被一些公司在使用,

  • vw和vh分别相对于屏幕宽度和屏幕高度的,1vw相当于屏幕宽度的1%,100vw相当于满屏宽度100%,
  • vh和vh类似,只不过是相对于屏幕高度的,1vh相当于屏幕高度的1%,100vh相当于满屏高度的100%

    cookie,localStorage和sessionStorage的区别

  • cookie可以设置失效时间,但没有自己的存取取的方法,需要时封装,每次请求时跟随请求发送,而localStorage和sessionStorage可以有自己存取的方法例如:

    • setItem()
    • getItem()
    • removeItem()
    • clear()

image.png

  1. autio,video
    1. H5提供的音频和视频组件,可以实现视频播放,我以前用它做过音乐播放器,不过好久没用了,里面有play,pause还有获取当前时间和总时间的方法,得看一下audio,video的API,用时我也能很快上手的
  2. 其他

    兼容性相关

  3. pc端

    1. 一般是IE兼容的问题,例如:利用css hack来解决 * ,_,等
    2. JS有特性匹配来解决某个JS方法是否存在
  4. 手机端:主要遇到过移动端300ms延迟和点透问题,可以通过fastclick插件解决
  5. 性能优化是一个很大的一个话题:优化的方面有很多,
    1. 是网络加载方面的优化:例如:减少http请求(合并文件,css雪碧图,图片懒加载),减少dom操作(dom缓存),代码封装,
    2. 第三方库用cdn加载,gzip压缩等

      IE8如何支持语义化标签

      一个库 html5shiv.js,直接引入就ok,大家可以百度下这个的文件,原理就是把语义化标签在低版本浏览器转化成了块级元素,让浏览器可以解析

常用算法相关

数组排序

冒泡排序: 随便从数组中拿一位数和后一位比较,如果是想从小到大排序,那么就把小的那一位放到前面,大的放在后面,简单来说就是交换它们的位置,如此反复的交换位置就可以得到排序的效果。

  1. var arr=[3,1,4,2,5,21,6,15,63]
  2. function sortA(arr){
  3. for(var i = 0; i<arr.length-1; i++){
  4. for(var j=i+1;j<arr.length;j++){
  5. // 获取第一个值和后一个值比较
  6. var cur=arr[i]
  7. if(cur>arr[j]){
  8. //因为需要交换值,所以会把后一个值替换,我们要鲜保存下来
  9. let index=arr[j]
  10. // 交换值
  11. arr[j]=cur
  12. arr[i]=index
  13. }
  14. }
  15. }
  16. return arr;
  17. }
  18. // 因为一次循环只能交换一个最大的值,所以需要在套一层for循环

数组去重

利用ES6的set来实现 例如:[…newSet(arr)]

  1. function unique(arr){
  2. var newArr = [];
  3. var temp = {};var item;
  4. for ( var i = o, len = arr.length; i < len; i++){
  5. item = arr[i];
  6. if ( ! temp[item] ){
  7. temp[item] = true;
  8. newArr.push(item) ;
  9. }
  10. }
  11. return newArr;
  12. }

地址栏解析成对象

image.png

对象深拷贝,浅拷贝的解理

对象浅拷贝可以理解为改变一个对象属性值,另一个对象属性也会发生改变,即互相影响, 对象深拷贝即就是说改变一个对象属性,另一个对象属性值不会发生改变,可以通过多种方法来实现对象深拷贝

  • 通过JSON.stringify和JSON.parse来实现

    1. var obj={name:’1610A’}
    2. var obj2=JSON.parse(JSON.stringify(obj))
  • 通过递归来实现

image.png

  • 可以参照一下代码,看下函数兼容性处理,以及封装 ```javascript var EventUtil={

    addHandler:function(element,type,handler){ //添加事件

    1. if(element.addEventListener){
    2. element.addEventListener(type,handler,false); //使用DOM2级方法添加事件
    3. }else if(element.attachEvent){ //使用IE方法添加事件
    4. element.attachEvent("on"+type,handler);
    5. }else{
    6. element["on"+type]=handler; //使用DOM0级方法添加事件
    7. }

    },

    removeHandler:function(element,type,handler){ //取消事件

    1. if(element.removeEventListener){
    2. element.removeEventListener(type,handler,false);
    3. }else if(element.detachEvent){
    4. element.detachEvent("on"+type,handler);
    5. }else{
    6. element["on"+type]=null;
    7. }

    },

    getEvent:function(event){ //使用这个方法跨浏览器取得event对象

    1. return event?event:window.event;

    },

    getTarget:function(event){ //返回事件的实际目标

    1. return event.target||event.srcElement;

    },

    preventDefault:function(event){ //阻止事件的默认行为

    1. if(event.preventDefault){
    2. event.preventDefault();
    3. }else{
    4. event.returnValue=false;
    5. }

    },

    stopPropagation:function(event){ //立即停止事件在DOM中的传播

    1. //避免触发注册在document.body上面的事件处理程序
    2. if(event.stopPropagation){
    3. event.stopPropagation();
    4. }else{
    5. event.cancelBubble=true;
    6. }

    } }

  1. <a name="hRjpt"></a>
  2. # js相关
  3. <a name="FJVy7"></a>
  4. ## 闭包
  5. - 闭包说的通俗一点就是打通了一条在函数外部访问函数内部作用域的通道。正常情况下函数外部是访问不到函数内部作用域变量的,表象判断是不是闭包:函数嵌套函数,内部函数被return 内部函数调用外层函数的局部变量。
  6. - **优点:**可以隔离作用域,不造成全局污染
  7. - **缺点:**由于闭包长期驻留内存,则长期这样会导致内存泄露
  8. - **如何解决内存泄露:**将暴露全外部的闭包变量置为null
  9. - **适用场景:**
  10. - 封装组件,for循环和定时器结合使用,for循环和dom事件结合.可以在性能优化的过程中,`节流防抖函数`的使用,导航栏获取下标的使用
  11. <a name="ERBqk"></a>
  12. ## JS中的原型链的理解?
  13. 1. **什么原型 ,原型链**
  14. - **原型:**
  15. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22000767/1628245879289-633650eb-2085-4de4-9b0a-ead768b407bf.png#clientId=u809bfc32-f5ff-4&from=paste&id=u4caf5674&margin=%5Bobject%20Object%5D&name=image.png&originHeight=426&originWidth=609&originalType=url&ratio=1&size=50579&status=done&style=none&taskId=u5b4eb598-2ea8-4c4d-ac4d-34a7e528e33)
  16. - js中,万物皆对象,每一个对象都拥有自己的属性
  17. - js中怎么才能让多个对象共享一个或多个方法呢?原型的出现就是为了解决这个问题。在js中每个对象都有一个与它关联的对象,叫做原型对象
  18. - 每次获取对象属性都是一次查询过程,在对象的自有属性中找不到就会去查找它的原型对象
  19. - **原型链:**
  20. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22000767/1628245898609-f6b51f94-74eb-455f-9ca8-413cdc267f86.png#clientId=u809bfc32-f5ff-4&from=paste&id=u9080759f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=497&originWidth=604&originalType=url&ratio=1&size=60586&status=done&style=none&taskId=ue8d20d41-cccf-4ed6-91a2-c35206e6906)
  21. - 原型连成一条链,js在查找属性过程中,如果在自有属性中找不到就会去原型对象中查找,如果原型对象中还查不到,就回去原型对象的原型中查找,也就是按照原型链查找,直到查到原型链的顶端`Object`
  22. 2. **有什么用,怎么用的**
  23. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22000767/1628245988349-3ee263d2-5966-4054-9140-444d853867fd.png#clientId=u809bfc32-f5ff-4&from=paste&height=318&id=u3c4f1417&margin=%5Bobject%20Object%5D&name=image.png&originHeight=318&originWidth=615&originalType=binary&ratio=1&size=76484&status=done&style=none&taskId=ue5fc25db-9b5d-4405-9bbd-1ca3fc5f30c&width=615)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/22000767/1628245995849-f580872b-40df-4fd2-8ff3-61690ff89be1.png#clientId=u809bfc32-f5ff-4&from=paste&height=317&id=ubea63a38&margin=%5Bobject%20Object%5D&name=image.png&originHeight=317&originWidth=605&originalType=binary&ratio=1&size=107630&status=done&style=none&taskId=ue01dd266-df10-4fda-9fa0-c0f53f51596&width=605)
  24. 3. **优缺点**
  25. - **原型链继承的优点**
  26. - 只继承了父类构造函数的属性,没有`继承父类原型的属性`
  27. - 解决了原型链继承缺点1、2、3
  28. - 可以继承多个构造函数属性( `call多个`)
  29. - 在子实例中可向父实例传参
  30. - **原型链继承的缺点**
  31. - 只能继承父类构造函数的属性
  32. - 无法实现构造函数的复用(每次用每次都要重新调用)
  33. - 每个新实例都有父类构造函数的副本,臃肿
  34. <a name="f6VuL"></a>
  35. ## JS继承(含ES6的)--或者人家这样问有两个类A和B,B怎么继承A?
  36. 1. **什么是继承:官方概念**
  37. 1. 通过【某种方式】让一个对象可以访问到另一个对象中的属性和方法Js中继承 es6中的继承
  38. 2. **继承有什么用**
  39. 如何实现继承:构造函数继承原型 原型连继承 拷贝继承(混入继承:mixin)
  40. <a name="GGdzF"></a>
  41. ### 原型继承:让新实例的原型等于父类的实例
  42. ```javascript
  43. // 父类
  44. function Person(name){ //给构造函数添加了参数
  45. this.name=name;
  46. this.sum=function(){
  47. alert(this.name)
  48. }
  49. }
  50. // 给构造函数添加了原型属性
  51. Person.prototype.age = 10
  52. // 原型链继承
  53. function Per(){
  54. this.name='ker';
  55. }
  56. Per.prototype=new Person(); //主要
  57. var per1=new Per();
  58. console.log(per1.age); //打印结果:10
  59. // instanceof 判断元素是否在另一个元素的原型链上
  60. // per1 继承了Person的属性,返回 true
  61. console.log(per1 instanceof Person); //打印结果:true
  • 特点 :实例可继承的属性有∶实例的构造函数的属性,父类构造函数属性,父类原型的属性。
  • 缺点:
    • 新实例无法问父类构造凶数传参。
    • 继承单一。
    • 所有新实例都会共享父类实例的属性。(原型上的屋性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)

原型链继承:用.call()和.apply()将父类构造函数引入子类函数

  1. <script>
  2. // 父类
  3. function Person(name){ //给构造函数添加了参数
  4. this.name=name;
  5. this.sum=function(){
  6. alert(this.name)
  7. }
  8. }
  9. // 给构造函数添加了原型属性
  10. Person.prototype.age = 10
  11. // 借用构造函数继承
  12. function Con(){
  13. Person.call(this,'jer') //重点
  14. this.age=12
  15. }
  16. var Con1=new Con();
  17. console.log(Con1.name); //打印结果:jer
  18. console.log(Con1.age); //打印结果:12
  19. console.log(Con1 instanceof Person); //打印结果:false
  20. </script>
  • 特点:
    • 只继承了父类构造函数的属性,没有继承父类原型的属性
    • 解决了原型链继承缺点1、2、3
    • 可以继承多个构造函数属性( call多个)
    • 在子实例中可向父实例传参
  • 缺点:
    • 只能继承父类构造函数的属性。
    • 无法实现构造函数的复用。
    • (每次用每次都要重新调用)每个新实例都有父类构造函数的副本,臃肿。

继承的优缺点:

ES6继承是目前比较新,并且主流的继承方式,用class定义类,用extends继承类,用super()表示父类,【下面代码部分只是熟悉】

  1. // 例如:创建 A 类
  2. class A{
  3. constructor(){
  4. // 构造器代码,new时自动执行
  5. }
  6. // 方法1( ) { //A类的方法 }
  7. // 方法2( ) { //A类的方法 }
  8. }
  9. // 创建B类并继承A类
  10. class B extends A {
  11. constructor(){
  12. super() //表示父类
  13. }
  14. }
  15. // 实例化B类:
  16. var b1=new B( )
  17. console.log(b1);
  18. // b1.方法1( )

JS原生事件如何绑定

答:JS原生绑定事件主要为三种:

  1. html事件处理程序
  2. DOM0级事件处理程序
  3. DOM2级事件处理程序
  • html事件现在早已不用了,就是在html各种标签上直接添加事件,类似于css的行内样式,缺点是不好维护,因为散落在标签中,也就是耦合度太高

    1. <button onclick=”事件处理函数”>点我</button>
  • DOM0级事件,目前在PC端用的还是比较多的绑定事件方式,兼容性也好,主要是先获取dom元素,然后直接给dom元素添加事件 ```javascript var btn = document.getElementById(‘id元素’)

    1. btn.onclick = function() {
    2. //要处理的事件逻辑

    }

DOM0事件如何移除呢?很简单:btn.onclick=null;置为空就行 优点:兼容性好 缺点:只支持冒泡,不支持捕获

  1. - `DOM2级事件`,移动端用的比较多,也有很多优点,提供了专门的绑定和移除
  2. ```javascript
  3. var btn=document.getElementById('id元素')
  4. //绑定事件
  5. btn.addEventListener('click',
  6. 绑定的事件处理函数名,false)
  7. //移除事件
  8. btn.removeEventListener('click',要移除的事件处理函数名,false)

JS原生常用dom操作方法?

  • js原生dom操作方法有?
  • 查找
    • getElementByid
    • getElementsByTagName
    • querySelector
    • querySelectorAll
  • 插入:appendChild,insertBefore
  • 删除:removeChild
  • 克隆:cloneNode
  • 设置和获取属性setAttribute(“属性名”,”值”),getAttibute(“属性名”)

    ES6新增特性?

  • ES6新增特性常用的主要有:

    • let/const,箭头函数,
    • 模板字符串,解构赋值,
    • 模块的导入(import)
    • 导出(export default/export),Promise
    • 还有一些数组字符串的新方法,其实有很多,我平时常用的就这些

      (了解)JS设计模式有哪些(单例模式观察者模式等)

      JS设计模式有很多,但我知道的有单例模式,观察者模式

  • 单例模式:

    • 是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象。
  • 观察者模式:
    • 观察者的使用场合就是:
    • 当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。
  • 总的来说,观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化

    对JS面试对象的理解

    什么是面向对象: 将所需要做的功能抽象成一个“对象”,然后反复调用这个对象来完成你想要的功能

  1. 面向对象用法:object创建
    1. <script>
    2. var box = new Object() // 创建一个Object 对象
    3. box.name='面向对象用法' //创建一个name属性并赋值
    4. box.age = 100 // 创建一个age属性并赋值
    5. // 创建一个run () 方法并返回值
    6. box.run=function(){
    7. return this.name + this.age + '运行中'
    8. }
    9. alert(box.run()) //输出属性和方法的值
    10. console.log(box.run()); //打印输出:面向对象用法100运行中
    11. </script>
  • 缺点: 想创建多个类似的对象,就会产生大量的代码
  1. 工厂模式创建对象
    1. // 集成实例化的函数
    2. function createObject(name,age){
    3. var obj = new Object()
    4. obj.name = name
    5. obj.age = age
    6. obj.run=function(){
    7. return this.name + this.age +'运行中...'
    8. }
    9. return obj
    10. }
    11. var box1=createObject('less',100) //第一个实现
    12. var box2=createObject('jack',200) //第二个实现
    13. console.log(box1.run()); // 打印输出:less100运行中...
    14. console.log(box2.run()); // 打印输出:jack200运行中...
    15. // alert(box2.run()) //保持独立
  • 工厂模式解决了重复实例化的问题
  • 缺点:
    • 创建不同对象其中属性和方法都会重复建立,消耗内存;还有函数识别问题等等。
  1. 字面量创建对象:Var obj = { }
    1. // 构造函数的方法创建对象
    2. function box(name,age){
    3. this.name=name
    4. this.age=age
    5. this.run = function(){
    6. this.name+this.age+'运行中...'
    7. }
    8. }
    9. var box1=new box('less',100) //new box() 即可
    10. var box2=new box('jack',300)
    11. alert(box1.run()); //undefined
    12. alert(box1 instanceof box); //很清晰的识别他从属于box 打印输出为:true
  • 当使用了构造函数,并且new构造函数(),那么就后台执行了new object()
  • 将构造函数的作用域给新对象,(即new object()创建出的对象),而函数体内的this 就代表new object()出来的对象。
  • 执行构造函数内的代码
  • 返回新对象(后台直接返回)

    原型

    继承:说一下es6的面向对象

    ES6有了个关键字:Class,来定义类

  1. class User{
  2. // 构造器
  3. constructor(name,age){
  4. this.name=name
  5. this.age=age
  6. }
  7. //定义类方法
  8. showName(){
  9. console.log(this.name);
  10. }
  11. }
  12. let user = new User('rest',21)
  13. console.log(user.showName()); //打印数位为:undefined
  • ES6的class 有了专门的构造器 constructor,构造器和类分开了,定义方法:不需要原型来定义了,直接再类里面定义方法
  • Es6声明类的方法

    1. let Example1=class{
    2. constructor(a){
    3. this.a=a
    4. console.log(a);
    5. }
    6. }
    7. let ex1=new Example1(1)
    8. // 命名类
    9. let Example2=class Example2{
    10. constructor(a){
    11. this.a=a
    12. console.log(a);
    13. }
    14. }
    15. let ex2=new Example1(2)
    16. // 类声明
    17. class Example{
    18. // class主体内容
    19. constructor(a,b){
    20. this.a=a
    21. this.b=b
    22. }
    23. }
  • ES6的继承:**关键字:extends 继承、super 超级**

    • constructor 构造器里面的this是指向创建的实例对象
    • 方法里面的this都是指向谁调用这个方法就指向谁

      JS数组常用方法(至少6个)

  • JS数组常用方法有:

    • push,
    • pop,
    • unshift
    • shift
    • splice
    • join
    • concat
    • forEach
    • filter
    • map
    • sort
    • some
    • every(等等)
  • 不过都是平时开发中很常用的方法,大家可以补充一点儿es6的

    JS数组内置遍历方法有哪些和区别

    JS数组内置遍历(遍历就是循环的意思)方法主要有:

    1. ** forEach:**这个方法是为了取代for循环遍历数组的,返回值为undefined
  1. let arrInfo=[4,6,6,8,5,7,87]
  2. let as = arrInfo.forEach((item,index,arr)=>{
  3. //例如返回数组每项值大于9的数组
  4. return item>9
  5. })
  6. console.log(arrInfo); //打印结果:undefined
  • 其中:
    • item代码遍历的每一项,
    • index:代表遍历的每项的索引,
    • arr代表数组本身
  • filter:是一个过滤遍历的方法,如果返回条件为true,则返回满足条件为true的新数组

    1. let arrInfo=[4,5,6,6,8,9,7,98]
    2. let resultARR = arrInfo.filter((item,index,arr)=>{
    3. //例如返回数组每项值大于9的数组
    4. return item>9
    5. })
    6. console.log(resultARR); //打印结果:9
  • map:这个map方法主要对数组的复杂逻辑处理时用的多,特别是react中遍历数据,也经常用到,写法和forEach类似

  • some:这个some方法用于只要数组中至少存在一个满足条件的结果,返回值就为true,否则返回fasel, 写法和forEach类似
  • every:这个every方法用于数组中每一项都得满足条件时,才返回true,否则返回false, 写法和forEach类似

    JS作用域和作用域链

    JS作用域也就是JS识别变量的范围,作用域链也就是JS查找变量的顺序先说作用域,JS作用域主要包括全局作用域、局部作用域和ES6的块级作用域

  • 全局作用域:也就是定义在window下的变量范围,在任何地方都可以访问

  • 局部作用域:是只在函数内部定义的变量范围
  • 块级作用域:简单来说用let和const在任意的代码块中定义的变量都认为是块级作用域中的变量
    • 例如在for循环中用let定义的变量,在if语句中用let定义的变量等等
    • 注:尽量不要使用全局变量,因为容易导致全局的污染,命名冲突,对bug查找不利
  • 而所谓的作用域链就是由最内部的作用域往最外部,查找变量的过程.形成的链条就是作用域链

    从输入URL到页面加载完中间发生了什么?

    大致过程是这样的:
  1. DNS解析
  2. TCP连接
  3. 发送HTTP请求
  4. 服务器处理请求并返回需要的数据
  5. 浏览器解析渲染页面
  6. 连接结束

    输入了一个域名,域名要通过DNS解析找到这个域名对应的服务器地址(ip),通过TCP请求链接服务,通过WEB服务器(apache)返回数据,浏览器根据返回数据构建DOM树,通过css渲染引擎及js解析引擎将页面渲染出来,关闭tcp连接

JS事件代理(也称事件委托)是什么,及实现原理?

JS事件代理就是通过给父级元素(例如:ul)绑定事件,不给子级元素(例如:li)绑定事件,然后当点击子级元素时,通过事件冒泡机制在其绑定的父元素上触发事件处理函数,主要目的是为了提升性能,因为我不用给每个子级元素绑定事件,只给父级元素绑定一次就好了,在原生js里面是通过event对象的targe属性实现

  1. var ul = document.querySelector("ul");
  2. ul.onclick = function(e){ //e指event,事件对象
  3. var target = e.target || e.srcElement; //target获取触发事件的目标(li)
  4. if(target.nodeName.toLowerCase() == 'li'){ //目标(li)节点名转小写字母,不转的话是大写字母
  5. alert(target.innerHTML)
  6. }
  7. }

jq方式实现相对而言简单$('ul').on("click","li",function(){//事件逻辑}) 其中第二个参数指的是触发事件的具体目标,特别是给动态添加的元素绑定事件,这个特别起作用

JS数据类型有哪些?

  • 基本数据类型:
    • number
    • string
    • Boolean
    • null
    • undefined
    • symbol (ES6新增)
  • 复合类型:

    • Object
    • function

      call,apply,bind区别

      call,apply,bind主要作用都是改变this指向的,但使用上略有区别,说一下区别

  • call和apply的主要区别是在传递参数上不同,call后面传递的参数是以逗号的形式分开的

  • apply传递的参数是数组形式 [Apply是以A开头的,所以应该是跟Array(数组)形式的参数]
  • bind返回的是一个函数形式,如果要执行,则后面要再加一个小括号
    • 例如:bind(obj,参数1,参数2,)(),bind只能以逗号分隔形式,不能是数组形式
  • 手写bind案例:
    1. function bind_1(asThis, ...args) {
    2. const that = this;
    3. // this 就是调用 bind 的fn
    4. function handle(...args2) {
    5. return that.apply(asThis, ...args, ...args2)
    6. };
    7. handle.prototype= that.prototype
    8. return handle
    9. }

    git相关

  1. 你们公司项目是如何管理的?
    1. 主要通过git来进行项目版本控制的
  2. 说几个git常用命令?
    • git add .
    • git status
    • git commit –m ‘初始化 ‘
    • git push
    • git pull等
  3. 说一下多人操作同一个文件,如果出现冲突该如何解决?
    • 当遇到多人协作修改同一个文件时出现冲突,我先将远程文件先git pull下来,手动修改冲突代码后,再git add ,git commit,git push再上传到远程仓库。如果pull也pull不下来提示冲突的话,可以先通过git stash暂存下来,然后再pull拉取,然后git stash pop,取出原来写的,手动修改,然后提交

      Ajax相关如何与后端进行数据交互的

我和后端通过ajax来进行数据交互的,通过统一制定的接口文档,来实现前后端高效开发,如果接口文档不能详细说明,或者接口文档上的参数请求不出数据,我会主动和后端工程师沟通,直到完成跟接口相关的业务开发。当然这其中为了验证一些接口问题,会用到一些辅助工具,比方说,runapi这种在线测试工具

如果后端数据接口没有准备好,你是如何工作的

如果后端接口还没有准备好,我会和后端工程师沟通,通过制定接口返回数据的格式,然后前端通过一些mock数据的工具(上家公司使用的是easymock,贼简单)来批量生成假数据,可以让前端和后端同时开发,而无需等待后端数据接口写好再开发,这样提升项目整体的开发效率

说一下你对ajax的同源策略的理解

同源策略,它是由Netscape提出的一个著名的安全策略,现在所有的可支持javascript的浏览器都会使用这个策略。最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页”同源”。所谓”同源”指的是”三个相同“。

ajax同源策略是因为安全的考虑,ajax不允许访问不同域名下的资源即所谓同源策略的意思。

说一下什么情况下会产生跨域及产生跨域的解决方案和实现原理?

产生跨域的情况有:不同协议,不同域名,不同端口以及域名和ip地址的访问都会产生跨域。

跨域的解决方案目前有三种主流解决方案

  • jsonp
    • jsonp实现原理:主要是利用动态创建script标签请求后端接口地址,然后传递callback参数,后端接收callback,后端经过数据处理,返回callback函数调用的形式,callback中的参数就是json
  • 代理(前端代理和后端代理)
    • 前端代理我在vue中主要是通过vue脚手架中的config中的index文件来配置的,其中有个proxyTable来配置跨域的
  • CORS

    • CORS全称叫跨域资源共享,主要是后台工程师设置后端代码来达到前端跨域请求的

      原生ajax的交互过程(即流程)

  • 交互流程

    • 先创建XHR对象XMLHttpRequest()
    • 然后open准备发送,open中有三个参数
      • 一是提交方式get和post,
      • 二是接口地址,
      • 三是同步和异步
    • 第三步是用send发送
    • 第四步再发送的过程中通过**onreadystatechange**来监听接收的回调函数,可以通过判断**readyState==4和status==200**来判断是否成功返回,然后通过**responseText**接收成功返回的数据

      你对同步和异步的理解

      同步即sync,形象的说就是代码一行行执行,前面代码和请求没有执行完,后面的代码和请求就不会被执行

  • 缺点:容易导致代码阻塞

  • 优点:程序员容易理解(因为代码从上往下一行行执行,强调顺序)
  • 异步:即async,形象的说就是代码可以在当前程序没有执行完,也可以执行后面的代码
    • 缺点:程序员不易理解(因为不是按顺序执行的)
    • 优点:可以解决代码阻塞问题,提升代码执行效率和性能
  • 异步解决方案主要有三个

    • 回调函数
    • promise(重点掌握)
    • generator (了解)
    • asyncawait(重点掌握)

      ajax缓存如何解决

      通过在文件名后面添加随机数(也称为文件指纹)来实现,主要原理是浏览器对访问过的文件,
      首先会检测第二次请求的文件url在浏览器是否缓存过,如果缓存过就使用,否则如果是一个新的文件url,则从服务器重新请求

      javaScript原生,jQuery,vue,react,小程序ajax与后台交互主要用的什么技术

  • javaScript原生Ajax:

    • 用的是XMLHttpRequest对象
  • jQuery中的Ajax:
    • $.ajax()
    • $.getJSON()
    • $.get()
    • $.post()等
  • vue中的Ajax:
    • vue-resource(vue1.x中用)
    • axios(主流)
  • 微信小程序Ajax:用的是小程序内置的

    • wx.request()写法
    • query的$.ajax()类似,参数url,success,data,method,fail等

      http状态码

  • 1xx(临时响应)

    • 表示临时响应并需要请求者继续执行操作的状态代码
  • 2xx (成功)
    • 表示成功处理了请求的状态码。
    • 常见的2开头的状态码有:200 – 服务器成功返回网页
  • 3xx (重定向)
    • 表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向常见的3字开头的状态码有:
    • 301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应时,会自动将请求者转到新位置。
    • 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
    • 304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
  • 4xx(请求错误)
    • 这些状态代码表示请求可能出错,妨碍了服务器的处理。
    • 常见的4字开头的状态有:404 – 请求的网页不存在
  • 5xx(服务器错误)

    • 这些状态代码表示服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。
    • 常见的以5开头的状态码有:
    • 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
    • 503 (服务不可用)服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。

      你上家公司项目是前后端分离?

      对,是前后端分离的项目,但开始不是,开始前后端代码混在一起写的,后来重构成前后端分离的项目,方便前端和后端自己维护的代码

  • 注:所谓前后端分离就是前后端职责明晰:

  • 后端只提供数据接口地址返回json数据,
  • 前端用ajax请求json数据,页面的所有业务逻辑都是前端来写,让前端控制力更强,并且减轻后端逻辑处理压力。

    深拷贝,浅拷贝

  • 用es6的Object.assign({},{})进行对象合并,如果是数组可以用es6的Array.from,或是es6的扩展运算符...arr

  • 如果使用es5需要用循环来做浅拷贝,如果是深拷贝需要用递归的形式来实现.当然也可以使用**JSON.parse(JSON.stringify(对象))**的方式实现深拷贝

    Vue相关

    vue最大特点是什么或者说vue核心是什么

  • vue最大特点我感觉就是“组件化“和”数据驱动“

    • 组件化就是可以将页面和页面中可复用的元素都看做成组件,写页面的过程,就是写组件,然后页面是由这些组件“拼接“起来的组件树
    • 数据驱动就是让我们只关注数据层,只要数据变化,页面(即视图层)会自动更新,至于如何操作dom,完全交由vue去完成,咱们只关注数据,数据变了,页面自动同步变化了,很方便

      vue常用基本指令有哪些

  1. v-if:根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。
  2. v-show:根据表达式之真假值,切换元素的 display CSS 属性。
  3. v-for:循环指令,基于一个数组或者对象渲染一个列表,vue 2.0以上必须需配合 key值 使用。
  4. v-bind:动态地绑定一个或多个特性,或一个组件 prop 到表达式。
  5. v-on:用于监听指定元素的DOM事件,比如点击事件。绑定事件监听器。
  6. v-model:实现表单输入和应用状态之间的双向绑定
  7. v-pre:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
  8. v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

    Vue常用的修饰符

  • v-on 指令常用修饰符:
    • .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 } 模式添加侦听器
  • 注意: 如果是在自己封装的组件或者是使用一些第三方的UI库时,会发现并不起效果,这时就需要用`·.native修饰符了,如:
  1. <el-input
  2. v-model="inputName"
  3. placeholder="搜索你的文件"
  4. @keyup.enter.native="searchFile(params)"
  5. >
  6. </el-input>
  • v-bind 指令常用修饰符

    prop - 被用于绑定 DOM 属性 (property)。

    • camel - (2.1.0+) 将 kebab-case 特性名转换为 camelCase
    • sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器
  • v-model 指令常用修饰符
    • lazy - 取代 input 监听 change 事件
    • number - 输入字符串转为数字
    • trim - 输入首尾空格过滤

      Vue 组件中 data 为什么必须是函数

      ```vue //为什么data函数里面要return一个对象
  1. 因为一个组件是可以共享的,但他们**的data是私有的,所以每个组件都要return一个新的data对象,返回一个唯一的对象,不要和其他组件共用一个对象**
  2. <a name="TTVKY"></a>
  3. ## v-if和v-show的区别
  4. - v-ifv-show都可以显示和隐藏一个元素,但有本质区别
  5. - v-if是惰性的,只是值为false就不会加载对应元素,为true才动态加载对应元素
  6. - v-show:是无论为true和为false都会加载对应html代码,但为false时用display:none隐藏不在页面显示,但为true时页面上用display:block显示其效果
  7. - 适用场景:切换频繁的场合用v-show,切换不频繁的场合用v-if
  8. <a name="pCY0e"></a>
  9. ## vue自定义指令如何实现的和适用场景
  10. - vue除有了v-for,v-if等自带vue指令外,但不能满足所有的开发需求,有时需要自定义指令,自定义指令创建有全局自定义指令和局部自定义指令
  11. - 全局自定义指令:`**Vue.directive(‘指令名’,{ inserted(el) { } })**`
  12. - 局部自定义指令:`**directives:{ }**`
  13. <a name="rPL4W"></a>
  14. ## vue过滤器做什么的(vue1.x和vue2.x这块的区别)
  15. > **vue过滤器主要用于对渲染出来的数据进行格式化处理**。
  16. 例如:后台返回的数据性别用01表示,但渲染到页面上不能是01我得转换为“男“和”女”,这时就会用到过滤器,还有商品价格读取出来的是普通数值,例如:230035,但我要在前面加个货币符号和千分分隔等,例如变成:¥230035,都得需要vue过滤器<br />如何创建过滤器呢,跟创建自定义指令类似,也有全局和局部过滤器的形式
  17. - **全局过滤器**
  18. ```javascript
  19. Vue.filter(‘过滤器名’,function(参数1,参数2,…) {
  20. //………..
  21. return 要返回的数据格式
  22. })
  • 局部过滤器:在组件内部添加filters属性来定义过滤器

    1. fitlers:{
    2. 过滤器名(参数1,参数2,,…参数n) {
    3. //………..
    4. return 要返回的数据格式
    5. }
    6. }

    vue生命周期钩子函数有哪些,分别什么时候触发

  • vue生命周期即为一个组件从出生到死亡的一个完整周期,主要包括以下4个阶段:创建,挂载,更新,销毁

    • 创建前:beforeCreate, 创建后:created
    • 挂载前:beforeMount, 挂载后:mounted
    • 更新前:beforeUpdate, 更新后:updated
    • 销毁前:beforeDestroy, 销毁后:destroyed
  • 我平时用的比较多的钩了是created和mounted,created用于获取后台数据,mounted用于dom挂载完后做一些dom操作,以及初始化插件等.beforeDestroy用户清除定时器以及解绑事件等
  • 另外还新增了使用内置组件 keep-alive 来缓存实例,而不是频繁创建和销毁(开销大)
    • actived 实例激活
    • deactived 实例失效
  • 以下为详解版,大家理解就ok:
  • 生命周期钩子函数(11个)Function(类型),标注蓝色的那个是属于类型的意思。

    • beforeCreateFunction 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
    • created Function 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer), 属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
    • beforeMount Function 在挂载开始之前被调用:相关的 render 函数首次被调用。
    • mounted Function el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。
    • beforeUpdateFunction 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
    • updated Function 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
    • activatedFunction keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。
    • deactivated Function keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。
    • beforeDestroyFunction 实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。
    • destroyedFunction Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
    • errorCaptured(2.5.0+ 新增)(err: Error, vm: Component, info: string) => ?boolean 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

      vue组件通讯(即传值)有哪几种形式,分别是如何实现的

      vue组件通讯大致有三种:父传子,子传父,还有兄弟之间通讯

  • 父传子:主要通过**props**来实现的

    • 父组件通过import引入子组件,并注册,在子组件标签上添加要传递的属性,子组件通过props接收,接收有两种形式一是通过数组形式[‘要接收的属性’ ],二是通过对象形式{ }来接收,对象形式可以设置要传递的数据类型和默认值,而数组只是简单的接收
  • 子传父:主要通过**$emit**来实现
    • 具体实现:子组件通过通过绑定事件触发函数,在其中设置this.$emit(‘要派发的自定义事件’,要传递的值),$emit中有两个参数一是要派发的自定义事件
    • 第二个参数是要传递的值然后父组件中,在这个子组件身上@派发的自定义事件,绑定事件触发的methods中的方法接受的默认值,就是传递过来的参数
  • 兄弟之间传值有两种方法

    • 通过event bus实现
      • 创建一个空的vue并暴露出去,这个作为公共的bus,即当作两个组件的桥梁,在两个兄弟组件中分别引入刚才创建的bus,在组件A中通过bus.$emit(’自定义事件名’,要发送的值)发送数据,在组件B中通过bus.$on(‘自定义事件名‘,function(v) { //v即为要接收的值 })接收数据
    • 通过vuex实现
      • vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules5个要素,主要流程:组件通过dispatch到 actions,actions是异步操作,再actions中通过**commit到mutations,mutations**再通过逻辑操作改变state,从而同步到组件,更新其数据状态

        vue封装组件中的slot作用

  • vue封装组件涉及三个东西

    • 事件(v-on,$emit)
    • 传参通过props
    • slot:slot作用主要是可以实现内容分发,组件标签内嵌套内容,可通过<slot></slot>来定义占位的内容
      • 分为具名的slot和匿名的slot
  • 在编写可复用组件的时候,时刻考虑组件是否可复用是有好处的。一次性组件跟其他组件紧密耦合没关系,但是可复用组件一定要定义一个清晰的公开接口

  • Vue.js组件 API 来自 三部分:prop、事件、slot

    • prop 允许外部环境传递数据给组件,在vue-cli工程中也可以使用vuex等传递数据
    • 事件允许组件触发外部环境的 action(就是行为,也就是方法的意思)
    • slot 允许外部环境将内容插入到组件的视图结构内


vue转场动画如何实现的

vue转场动画主要通过vue中的提供的transition组件实现的

  1. <transition name=”名称”>
  2. <router-view></router-view>
  3. </transition>
  • 其中name为转场的名称,自己定义,可通过定义进入和离开两种转场动画,格式为:

    • 名称-enter { } // 将要进入动画
    • 名称-enter-active { } // 定义进入的过程动画
    • 名称-leave { } // 将要离开的动画
    • 名称-leave-active { } // 定义离开过程中的动画

      说一下你对单向数据流的理解

  • 单向数据流主要是vue 组件间传递数据是单向的,即数据总是由父组件传递给子组件,子组件在其内部维护自己的数据,但它无权修改父组件传递给它的数据,当开发者尝试这样做的时候,vue 将会报错。这样做是为了组件间更好的维护。

  • 在开发中可能有多个子组件依赖于父组件的某个数据,假如子组件可以修改父组件数据的话
    • 一个子组件变化会引发所有依赖这个数据的子组件发生变化,所以 vue 不推荐子组件修改父组件的数据

      vue双向数据绑定的原理

答:核心主要利用ES5中的**Object.defineProperty**实现的,然后利用里面的getter和setter来实现双向数据绑定的,大致就这些,其实要实现起来比这个要复杂一些,不过我大致了解过

vue路由或前端路由实现原理

前端路由实现原理主要通过以下两种技术实现的

  • 利用H5的history API实现
    • 主要通过history.pushState 和 history.replaceState来实现,不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录[发布项目时,需要配置下apache]
  • 利用url的hash实现
    • 我们经常在 url 中看到 #,这个 # 有两种情况,一个是我们所谓的锚点,路由里的 # 不叫锚点,我们称之为 hash,我们说的就是hash,主要利用监听哈希值的变化来触发事件 ——hashchange 事件来做页面局部更新
  • 总结:hash 方案兼容性好,而H5的history主要针对高级浏览器

以下为具体的API的区别:

  1. this.$router.push(location, onComplete?, onAbort?)
  2. //这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL
  3. <router-link :to="...">等同于调用 router.push(...)
  4. this.$router.replace(location, onComplete?, onAbort?)
  5. 这个方法不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录,
  6. 所以,当用 户点击浏览器后退按钮时,并不会回到之前的 URL
  7. this.$router.go(n) 这个方法的参数是一个整数,
  8. 意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)
  • 以上也可能会形成一个新的面试题:replace和push的区别
    • 可以说,以前在一个项目里面配置了一个二级路由,里面有tab切换部分(详情,评价,说明),因为返回上一页的时候,不能在这几个选项卡之间来回切换.所以我使用了**this.$router.replace**方法,不计入**history**记录中,所以不会出现,反复切换的**bug**

vue路由钩子(或称vue路由守卫)的理解

  • vue路由钩子是在路由跳转过程中拦截当前路由和要跳转的路由的信息,有三种路由钩子
    • 全局路由钩子 ```javascript beforeEach(to,from,next) {

}

  1. - 路由独享的钩子
  2. ```vue
  3. beforeEnter(to,from,next) {
  4. }
  • 组件内的钩子 ```javascript beforeRouteEnter(to,from,next) { //… } beforeRouteUpdate(to,from,next) { //… }

beforeRouteLeave(to,from,next) { //… }

  1. - 适用场景:动态设置页面标题,判断用户登录权限等:代码示例
  2. ```javascript
  3. //全局路由导航守卫
  4. vueRouter.beforeEach(function (to, from, next) {
  5. const nextRoute = [ 'detail'];
  6. const auth = sessionStorage.getItem("username");
  7. let FROMPATH = from.path;
  8. //跳转至上述3个页面
  9. if (nextRoute.indexOf(to.name) >= 0) {
  10. //上述数组中的路径,是相当于有权限的页面,访问数组列表中的页面就应该是在登陆状态下
  11. if (!auth) {
  12. let params = Object.assign({frompath:FROMPATH},from.query);
  13. next({path: '/newlogin',query:params});
  14. }
  15. }
  16. //已登录的情况再去登录页,跳转至首页
  17. if (to.name === 'newlogin') {
  18. if (auth) {
  19. // vueRouter.push({name: 'index'});
  20. next({path: '/'});
  21. }
  22. }
  23. next();
  24. });

vue路由懒加载解决什么问题的?

vue路由懒加载主要解决打包后文件过大的问题,事件触发才加载对应组件中的js

如何解决vue首屏加载慢或白屏?

  1. 路由懒加载

image.png

  1. 开启Gzip压缩

image.png

  1. 使用webpack的externals属性把不需要打包的库文件分离出去,减少打包后文件的大小

image.png

  1. 使用Vue的服务端渲染(SSR)

vue开发环境和线上环境如何切换

答:主要通过检测process.env.NODE_ENV===”production”和process.env.NODE_ENV===”development”环境,来设置线上和线下环境地址,从而实现线上和线下环境地址的切换

你们项目中vue如何跨域的

  • 跨域前端和后端都可以实现,如果只针对vue,vue本身可以通过代理的方式可以实现,具体实现
    • 在config中的index.js中配置proxy来实现:

image.png

  • “开发过程中使用脚手架反向代理(proxy),上线时后端配置cors(cors如需自动传递cookie前端也需要配置)

    Vue中methods,computed,watch的区别

  • methods中都是封装好的函数,无论是否有变化只要触发就会执行
  • computed:是vue独有的特性计算属性,可以对data中的依赖项再重新计算,得到一个新值,应用到视图中,和methods本质区别是computed是可缓存的,也就是说computed中的依赖项没有变化,则computed中的值就不会重新计算,而methods中的函数是没有缓存的。
  • Watch是监听data和计算属性中的新旧变化。
  • vue用什么绑定事件,用什么绑定属性

    • 用v-on绑定事件,简称:@,用v-bind来绑定属性,简称::属性

      vue如何动态添加属性,实现数据响应?

  • [x] vue主要通过用this.$set(对象,‘属性‘,值)实现动态添加属性,以实现数据的响应注意是添加,我记忆中如果是修改引用类型属性的值,是可以自动渲染的.

vue中的http请求是如何管理的

vue中的http请求如果散落在vue各种组件中,不便于后期维护与管理,所以项目中通常将业务需求统一存放在一个目录下管理

  • 例如src下的API文件夹,这里面放入组件中用到的所有封装好的http请求并导出,再其他用到的组件中导入调用。如下面封装的HTTP请求

image.png

你对axios拦截器的理解

axios拦截器可以让我们在项目中对后端http请求和响应自动拦截处理,减少请求和响应的代码量,提升开发效率同时也方便项目后期维护

例如:

image.png
image.png
或者对公共的数据做操作
image.png

vue和jquey的区别

  • jquery主要是玩dom操作的“神器“,强大的选择器,封装了好多好用的dom操作方法和如何获取ajax方法 例如:$.ajax()非常好用
  • vue:主要用于数据驱动和组件化,很少操作dom,当然vue可能通过ref来选择一个dom或组件

vue如何实现局部样式的或者说如何实现组件之间样式不冲突的和实现原理是什么?

  • css没有局部样式的概念,vue脚手架通过实现了,即在style标签上添加scoped

image.png

  • scoped的实现原理:
    • vue通过postcss给每个dom元素添加一个以data-开头的随机自定义属性实现的

      vue第三方ui样式库如何实现样式穿透的(ui库和less/sass穿透问题) >>> /deep/

image.png

vue目录结构(面试时可能会这样问说一下vue工程目录结构)

  • 统一的目录结构可以方便团队协作和职责明晰,也方便项目后期维护和管理,具体vue项目目录结构包括:

    • build:项目构建目录
    • config:项目配置,包括代理配置,线上和线下环境配置
    • node_modules:node包目录,npm install安装的包都在这个目录
    • src:平时开发时的目录
    • static:存入一些静态资源资源目录,我们可以把一些图片,字体,json数据放在这里
    • eslintrc.js:Eslint代码检查配置文件
    • babelrc:ES6配置
    • .gitignore:忽略提交到远程仓库的配置

      Vue脚手架是你们公司搭建的,还是用的vue的脚本架?webpack了解多少?

      我们公司用的vue官方的脚手架(vue-cli),vue-cli版本有3.0和2.9.x版本

  • webpack是一个前端模块化打包构建工具,vue脚手架本身就用的webpack来构建的,webpack本身需要的入口文件通过entry来指定,出口通过output来指定,默认只支持js文件,其他文件类型需要通过对应的loader来转换

  • 例如:less需要less,less-loader,sass需要sass-loader,css需要style-loader,css-loader来实现。
  • 当然本身还有一些内置的插件来对文件进行压缩合并等操作

    说一下你对vuex的理解

  • vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules5个要素,

  • 主要流程:

    • 组件通过dispatch到 actions,actions是异步操作
    • 再actions中通过commit到mutations
    • mutations再通过逻辑操作改变state
    • 从而同步到组件,更新其数据状态,而getters相当于组件的计算属性对,组件中获取到的数据做提前处理的.再说到辅助函数的作用.

      vuex如何实现数据持久化(即刷新后数据还保留)

      • 因为vuex中的state是存储在内存中的,一刷新就没了,例如登录状态,解决方案有:
  • 第一种:利用H5的本地存储(localStorage,sessionStorage)

  • 第二种:利用第三方封装好的插件,例如:vuex-persistedstate

image.png

  • 第三种:使用vue-cookie插件来做存储

image.png

  • 第四种:可以把数据传递到后台,存储到数据库中

说一下nextTick的作用和使用场景?

vue中的nextTick主要用于处理数据动态变化后,DOM还未及时更新的问题,用nextTick就可以获取数据更新后最新DOM的变化

适用场景:

  • 一种:有时需要根据数据动态的为页面某些dom元素添加事件,这就要求在dom元素渲染完毕时去设置,但是created与mounted函数执行时一般dom并没有渲染完毕,所以就会出现获取不到,添加不了事件的问题,这回就要用到nextTick处理
  • 第二种:在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重新应用插件的方法,
    • 例如:应用滚动插件better-scroll时

image.png
image.png

  • 数据改变后获取焦点

何为$nextTick?

因为Vue的异步更新队列,$nextTick是用来知道什么时候DOM更新完成的。

我们先来看这样一个场景:有一个div,默认用 v-if 将它隐藏,点击一个按钮后,改变 v-if 的值,让它显示出来,同时拿到这个div的文本内容。如果v-if的值是 false,直接去获取div内容是获取不到的,因为此时div还没有被创建出来,那么应该在点击按钮后,改变v-if的值为 true,div才会被创建,此时再去获取,
示例代码如下:

  1. <div id="app">
  2. <div id="div" v-if="showDiv">这是一段文本</div>
  3. <button @click="getText">获取div内容</button>
  4. </div>
  5. <script>
  6. var app = new Vue({
  7. el : "#app",
  8. data:{
  9. showDiv : false
  10. },
  11. methods:{
  12. getText:function(){
  13. this.showDiv = true;
  14. var text = document.getElementById('div').innnerHTML;
  15. console.log(text);
  16. }
  17. }
  18. })
  19. </script>

这段代码并不难理解,但是运行后在控制台会抛出一个错误:Cannot read property 'innnerHTML of null,意思就是获取不到div元素

异步更新队列

  • Vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一个事件循环中发生的所以数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和DOM操作。然后,在下一个事件循环tick中,Vue刷新队列并执行实际(已去重的)工作。所以如果你用一个for循环来动态改变数据100次,其实它只会应用最后一次改变,如果没有这种机制,DOM就要重绘100次,这固然是一个很大的开销。
  • Vue会根据当前浏览器环境优先使用原生的Promise.then和MutationObserver,如果都不支持,就会采用setTimeout代替。
  • 知道了Vue异步更新DOM的原理,上面示例的报错也就不难理解了。事实上,在执行this.showDiv = true时,div仍然还是没有被创建出来,直到下一个vue事件循环时,才开始创建。$nextTick就是用来知道什么时候DOM更新完成的,所以上面的示例代码需要修改为:
    1. <div id="app">
    2. <div id="div" v-if="showDiv">这是一段文本</div>
    3. <button @click="getText">获取div内容</button>
    4. </div>
    5. <script>
    6. var app = new Vue({
    7. el : "#app",
    8. data:{
    9. showDiv : false
    10. },
    11. methods:{
    12. getText:function(){
    13. this.showDiv = true;
    14. this.$nextTick(function(){
    15. var text = document.getElementById('div').innnerHTML;
    16. console.log(text);
    17. });
    18. }
    19. }
    20. })
    21. </script>
    这时再点击事件,控制台就打印出div的内容“这是一段文本“了。
    理论上,我们应该不用去主动操作DOM,因为Vue的核心思想就是数据驱动DOM,但在很多业务里,我们避免不了会使用一些第三方库,比如 popper.js、swiper等,这些基于原生javascript的库都有创建和更新及销毁的完整生命周期,与Vue配合使用时,就要利用好$nextTick。

v-for 与 v-if 的优先级

当它们处于同一节点,v-for的优先级比v-if更高,这意味着 v-if将分别重复运行于每个 v-for循环中。当你想为仅有的一些项渲染节点时,
这种优先级的机制会十分有用,如下:

  1. <li v-for="todo in todos" v-if="!todo.isComplete">
  2. {{ todo }}
  3. </li>

上面的代码只传递了未完成的 todos。
而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template>)上

vue中 keep-alive 组件的作用

keep-alive:主要用于保留组件状态或避免重新渲染。

比如: 有一个列表页面和一个 详情页面,那么用户就会经常执行打开详情=>返回列表=>打开详情这样的话 列表 和 详情 都是一个频率很高的页面,那么就可以对列表组件使用进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染。

  1. 属性:
    1. include:字符串或正则表达式。只有匹配的组件会被缓存。
    2. exclude:字符串或正则表达式。任何匹配的组件都不会被缓存
  2. 用法:
    1. 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition>相似,<keep-alive>是一个抽象组件:它自身不会渲染一DOM 元素,也不会出现在父组件链中。
    2. 当组件在<keep-alive> 内被切换,在 2.2.0 及其更高版本中,activated 和 deactivated生命周期 将会在 树内的所有嵌套组件中触发

自我成长相关:

  • 平时怎么学习新技术的?
    • 上官网看文档,上github上找相关开源项目练手,上技术社区博客园,csdn,51cto,掘金,简书参加技术问题讨论,上知乎,通过专业书籍(例如:高程三,javascript权威指南即犀牛书)系统学习,加入相关技术群参考讨论
  • 未来的职业规划是什么?
    • 2年内先做好技术,小有所成后,其他机会也就慢慢来了
  • 离职原因

    • 公司资金链断裂.两个月发不出工资.领导让我出来找工作的
    • 行业整体不怎么景气.公司这边.浮动工资(绩效工资)占比增大
    • 公司这边需要长期外派出差,我个人的一些朋友人脉都在北京这边,所以不想出去.
    • 公司项目完成了.剩下的都是一些维护的工作.公司新招了两个大学生.我带了他们查不多两个月
    • 待定….

      常见面试

  • 自我介绍

    你贵姓:
    我说一下我的个人情况: 我叫XXX,这几年一直从事前端开发工作 掌握技术有: html css h5 c3 javascript bootstrap 框架包括: vue 技术站 vuex eleemntui axios echart …

    1. react技术站 react antd axios redux
    2. 版本管理工具 git
    3. 打包工具 webpack

    在这几年工作中: 作为前端来说 最容易碰到的问题:(每人都需要不同,总结3个) 适配问题 rem flex 响应式 ie9下v-for 在option渲染数据,字符不显示的问题 通过虚拟DOm 从新编写select的样式 接口安全的问题 :接口发送 和 请求 统一加密,通过key 进行校验 常见问题有很多,我那边总结了一个文档,我相信这些都已经不是问题了 希望能够加入咱们公司,把咱们公司的项目 打造的更人性化

  • 项目中遇到的问题: 项目介绍 自我介绍