前端面试总结

总结

一. html/css
1.BFC

定义
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有 块级盒子参与,它规定了内部的 块级盒子 如何布局,并且与这个区域外部毫不相干
布局规则
1、内部的 Box 会在垂直方向,一个接一个地放置
2、Box 垂直方向的距离由 margin 决定。属于同一个 BFC 的两个相邻 Box 的 margin会发生重叠
3、每个元素的 margin box 的左边, 与包含块 border box 的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此
4、BFC 的区域不会与 浮动元素 重叠
5、BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此
6、计算 BFC 的高度时,浮动元素也参与计算
哪些元素会生成 BFC:
1、根元素
2、float 属性不为 none
3、position 为 absolute 或 fixed
4、display 为 inline-block, table-cell, table-caption, flex, inline-flex
5、overflow 不为 visible

2.H5,cs3新特性

H5 新特性
1、拖拽释放(Drap and drop) API ondrop
拖放是一种常见的特性,即抓取对象以后拖到另一个位置,在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放
2、自定义属性 data-id
3、语义化更好的内容标签(header,nav,footer ,aside, article, section)
4、音频 ,视频(audio, video) 如果浏览器不支持自动播放怎么办?在属性中添加 autoplay
5、画布 Canvas
5.1 getContext() 方法返回一个用于在画布上绘图的环境
Canvas.getContext(contextID) 参数 contextID 指定了您想要在画布上绘制的类型。当前唯一的合法值是 “2d”,它指定了二维绘图,并且导致这个方法返回 一个环境对象,该对象导出一个二维绘图 API
5.2 cxt.stroke() 如果没有这一步 线条是不会显示在画布上的
5.3 canvas 和 image 在处理图片的时候有什么区别?
image 是通过对象的形式描述图片的,canvas 通过专门的 API 将图片绘制在画布上.
6、 地理(Geolocation) API
7、 本地离线存储 localStorage 长期存储数据 浏览器关闭后数据不丢失
8、 sessionStorage 的数据在浏览器关闭后自动删除
9、 表单控件 calendar , date , time , email , url , search , tel , file , number
10、新的技术 webworker, websocket , Geolocation

CSS3 新特性
1、颜色: 新增 RGBA , HSLA 模式
2、文字阴影(text-shadow)
3、边框: 圆角(border-radius) 边框阴影 : box-shadow
4、盒子模型: box-sizing
5、背景:background-size background-origin background-clip
6、渐变: linear-gradient , radial-gradient
7、过渡 : transition 可实现动画
8、自定义动画 animate @keyfrom
9、媒体查询 多栏布局 @media screen and (width:800px) {…}
10、border-image
11、2D 转换;transform: translate(x,y) rotate(x,y) skew(x,y) scale(x,y)
12、3D 转换
13、字体图标 font-face
14、弹性布局 flex

3.margin塌陷问题

外边距塌陷共有两种情况:
第一种情况:两个同级元素,垂直排列,上面的盒子给 margin-bottom 下面的盒子给margin-top,那么他们两个的间距会重叠,以大的那个计算。解决这种情况
的方法为:两个外边距不同时出现
第二种情况:两个父子元素,内部的盒子给 margin-top,其父级也会受到影响,同时产生上边距,父子元素会进行粘连,解决这种情况的方法为:父级添加一个 css 属性,overflow: hidden,禁止超出
外边距重叠就是 margin-collapse
解决方案:
1、为父盒子设置 border,为外层添加 border 后父子盒子就不是真正意义上的贴合 (可
以设置成透明:border:1px solid transparent)。
2、为父盒子添加 overflow:hidden;
3、为父盒子设定 padding 值;
4、为父盒子添加 position:fixed;
5、为父盒子添加 display:table;
6、利用伪元素给子元素的前面添加一个空元素
.son:before{ content:"";
overflow:hidden; }

4.flex布局

父容器上的属性

  .father {
      display: flex;   
      flex-flow: row wrap;      flex-direction和flex-wrap的合写,设置主轴方向(row横向,column纵向),和是否换行wrap、nowrap
      justify-content: space-between;   主轴对齐方式 
      /* align-items: center; */      一行时,侧轴对齐方式
      align-content: space-around;   多行时,侧轴对齐方式
    }

子容器上的属性

order:0;     子项的前后顺序,越小越靠前,默认是0
flex-grow: 0;   子项的放大比例。默认是0,不放大
flex-shrink:1;  子项的缩小比例,默认是1,不缩小
flex-basis:auto;  子项占据的主轴空间
align-self:auto;  单个子项的对齐方式

合写属性

flex:flex-grow   flex-shrink flex-basis;
flex:1;是   1          1        0%                  项目自动填充
flex:auto;  1          1        auto
flex:20px/20%; 1      1        20px/ 20%      长度单位或者百分比

flex布局的兼容性 ,,,,,,,,,

5.grid布局
  .father {
      width: 100%;
      height: 500px;
      display: grid;
      grid-template-columns: 100px 100px 100px 200px;
      grid-template-rows: 100px 100px;
      grid-gap: 10px 30px;
      place-content: start center;
    }
6.三角形

宽高都为0的盒子,通过border设置边框宽度和颜色,把其他三边颜色设为透明,就可以出一个三角形

7.rgba和opacity

opacity属性的值,可以被其子元素继承,给父级div设置opacity属性,那么所有子元素都会继承这个属性,并且,该元素及其继承该属性的所有子元素的所有内容透明度都会改变。而RGBA设置的元素,只对该元素的背景色有改变,并且,该元素的后代不会继承该属性。

8.左边100px,右边自适应场景

给父元素设置display:flex; 然后右边直接flex:1;

9.为什么会有浮动,清除浮动的方法

浮动定位将元素排除在普通流之外,即元素讲脱离文档流,不占据空间。浮动元素碰到包含它的边框或者浮动元素的边框停留
为什么需要清除浮动
1、父元素的高度无法被撑开,影响与父元素同级的元素;
2、与浮动元素同级的非浮动元素(内联元素)会跟随其后;
3、若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构
清除浮动的方式
1、父级盒子定义高度,height 简单粗暴,但是只适合高度固定的布局

​ 2、结尾处加空div,并给这个空div上加上clear:both; 能让父级div自动获取高度,但是这种做法会增加很多空div,让人感觉不好

​ 3、父级盒子上加上overflow:hidden; 缺点是溢出部分会被隐藏

​ 4、父级盒子定义 伪元素after,考虑兼容ie,需要zoom(设置zoom:1可以在IE6下清除浮动、解决margin导致的重叠等问题)

 .parents::after {
      content: '';
      display: block;
      clear: both;
    }
  .parents {
      zoom: 1;
    }

​ 5、双伪元素法(4方法 的升级) 四五方法一样,就是在父元素的头和尾加伪元素撑起父元素

 .parents::before,
    .parents::after {
      content: '';
      display: block;
      clear: both;
    }

  .parents {
      zoom: 1;
    }
10.less和sass

sass 与 less 都是预编译(预处理)的css语言

LESS和Sass的他们的实现方式:Less是基于JavaScript,是在客户端处理的。
Sass是基于Ruby,是在服务器端处理的

11.响应式布局及实现
  1. 百分比布局
  2. bootstrap栅格系统(antdesign 里面的珊格布局)
  3. Flex 伸缩盒布局
  4. 媒体查询
12.css哪些属性可以继承,哪些不行

​ 能继承的属性

  1. 字体系列属性:font、font-family、font-weight、font-size、font-style;

  2. 文本系列属性:
    2.1内联元素:color、line-height、word-spacing、letter-spacing、
    text-transform;
    2.2块级元素:text-indent、text-align;

  3. 元素可见性:visibility

  4. 表格布局属性:caption-side、border-collapse、border-spacing、empty-cells、
    table-layout;

  5. 列表布局属性:list-style

不能继承的属性

  1. display:规定元素应该生成的框的类型;

  2. 文本属性:vertical-align、text-decoration;

  3. 盒子模型的属性:width、height、margin 、border、padding;

  4. 背景属性:background、background-color、background-image;

  5. 定位属性:float、clear、position、top、right、bottom、left、min-width、
    min-height、max-width、max-height、overflow、clip;

12.盒模型(标准盒模型和ie盒模型)

盒子模型(Box Modle)可以用来对元素进行布局,包括内边距,边框,外边距,和实际内容这几个部分

标准盒模型下盒子的大小 = content + border + padding + margin

ie盒模型下盒子的大小 = width(content + border + padding) + margin

二.js
1.es6
  • let和const关键字

    • let 定义变量,变量不可以再次定义,但可以改变其值
    • 具有块级作用域
    • 没有变量提升,必须先定义再使用
    • let声明的变量不会压到window对象中,是独立的

    • 使用const关键字定义常量
    • 常量是不可变的,一旦定义,则不能修改其值
    • 初始化常量时,必须给初始值
    • 具有块级作用域
    • 没有变量提升,必须先定义再使用
    • 常量也是独立的,定义后不会压入到window对象中
  • 解构赋值

    ES 6 允许按照一定**模式**,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

    对象、数组的解构赋值。直接用=号

    // 假设从服务器上获取的数据如下
    let response = {
        data: ['a', 'b', 'c'],
        meta: {
            code: 200,
            msg: '获取数据成功'
        }
    }
    // 如何获取到 code 和 msg
    let { meta: { code, msg } } = response;
    console.log(code, msg); // 200, 获取数据成功
    
  • 箭头函数

    ES6 中允许使用箭头定义函数 (=> goes to),目的是简化函数的定义,并且里面的this也比较特殊(箭头函数内部的 this 指向外部作用域中的 this ,或者可以认为箭头函数没有自己的 this

    MDN解释:箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this

  • 函数参数默认值

    es6可以给函数的参数设置一个默认值,我们实际传递给函数的实参,优先级大于默认值

  • 函数剩余参数

  • Array对象扩展

    1. 扩展运算符(。。。)可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开,还可以在构造字面量对象时, 将对象表达式按key-value的方式展开
    2. Array.from() 把伪数组转换成数组
    3. forEach遍历数组
    4. 数组实例的 find() 和 findIndex()
    5. 数组实例的 includes()
  • String对象扩展

    1. 模板字符串
    2. includes(), startsWith(), endsWith()
    3. repeat() repeat方法返回一个新字符串,表示将原字符串重复n
    4. trim() trim() 方法可以去掉字符串两边的空白
  • Number

    ES6 将全局方法parseInt()parseFloat(),移植到Number对象上面,功能完全保持不变。 Number.parseInt() Number.parseFloat()

    parseInt() 会去掉小数,parseFloat() 不会

  • 新增对象Set

    ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set的特点就是该对象里面的成员不会有重复。

    Set本身是一个构造函数,用来生成 Set 数据结构。

    // 1. 基本使用
    let s = new Set();
    // 得到一个空的Set对象
    // 调用add方法,向s中添加几个值
    s.add(3);
    s.add(7);
    s.add(9);
    s.add(7); // Set对象中的成员都是唯一的,前面添加过7了,所以这里添加无效
    ​
    console.log(s.size);
    console.log(s); // {3, 7, 9}
    
    • size:属性,获取 set 中成员的个数,相当于数组中的 length
    • add(value):添加某个值,返回 Set 结构本身。
    • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
    • has(value):返回一个布尔值,表示该值是否为Set的成员。
    • clear():清除所有成员,没有返回值。
  • 定义对象的简洁方式

    let id = 1;
    let name = 'zs';
    let age = 20;
    ​
    // 之前定义对象的方案
    // let obj = {
    //     // 属性: 值
    //     id: id,
    //     name: name,
    //     age: age,
    //     fn: function () {
    //         console.log(this.age);
    //     }
    // };
    ​
    // obj.fn();
    ​
    ​
    // ES6的新方案
    let obj = {
        id,  // 属性名id和前面的变量id名字相同,则可以省略 :id
        name,
        nianling: age,
        // 下面的函数是上面函数的简化写法,可以省略 :function  。但是注意这里仅仅是上面函数的简化,不是箭头函数
        fn () {
            console.log(this.name);
        }
    };
    obj.fn();
    
  • Promise

    1. 概述:Promise是异步编程的一种解决方案,从语法上讲,Promise是一个对象,可以获取异步操作的消息

    2. 目的: (1)、避免回调地狱的问题(2)、Promise对象提供了简洁的API,使得控制异步操作更加容易

    3. Promise有三种状态:pendding //正在请求,rejected //失败,resolved //成功

    4. 基础用法:new Promise(function(resolve,reject){ })

    5. resolved,rejected函数:在异步事件状态pendding->resolved回调成功时,通过调用resolved函数返回结果;当异步操作失败时,回调用rejected函数显示错误信息

    6. then的用法:then中传了两个参数,第一个对应resolve的回调,第二个对应reject的回调

    7. catch方法:捕捉promise错误函数,和then函数参数中rejected作用一样,处理错误,由于Promise抛出错误具有冒泡性质,能够不断传递,会传到catch中,所以一般来说所有错误处理放在catch中,then中只处理成功的,同时catch还会捕捉resolved中抛出的异常

    8. all方法:Promise.all([promise1,promise2])——参数是对象数组。以慢为准,等数组中所有的promise对象状态为resolved时,该对象就为resolved;只要数组中有任意一个promise对象状态为rejected,该对象就为rejected

      let p = Promise.all([Promise1, Promise2])
      
      p.then((data) => {
          //都成功才表示成功
      })
      .catch((err) => {
          //有一个失败,则都失败
      });
      
    9. race方法:Promise.race([promise1,promise2])——参数是对象数组。以快为准,数组中所有的promise对象,有一个先执行了何种状态,该对象就为何种状态,并执行相应函数

2.原型链

在这里插入图片描述

3.this的理解

​ this是一个关键字,代表函数运行时,自动生成的一个内部对象,只能在函数内部使用

​ 在普通函数中,this指向window

​ 在定时器中,this也是指向window

​ 在构造函数中,this指向当前实例化 对象

​ 在事件处理函数中,this指向事件触发对象

​ 总的来说,谁调用指向谁

4.foreach和map区别

​ 1、forEach()返回值是undefined,不可以链式调用,对数据的操作会改变原数组。

​ 2、map()返回一个新数组,原数组不会改变。

​ 3、没有办法终止或者跳出forEach()循环,除非抛出异常,所以想执行一个数组是否满足什么条件,返回布尔值,可以用一般的for循环实现,用Array.every()或者Array.some();

5.some和every

​ every()和 some()目的:确定数组的所有成员是否满足指定的测试

​ some方法遍历 只要其中一个为true 就会返回true的,every()方法必须所有都返回true才会返回true,哪怕有一个false,就会返回false;

6.find和 filter

​ 数组操作方法find(), 查找,找到数组中第一个满足条件的成员并返回该成员,如果找不到返回undefined。

​ 同样findindex(), 查找,,找到数组中第一个满足条件的成员并返回该成员的索引,如果找不到返回 -1。

​ indexOf,遍历一直,如果数组中存在,则返回对应的索引值,不存在的话返回-1

​ filter () 过滤 filter方法用于过滤数组成员,满足条件的成员组成一个新数组返回

7.reduce方法

reduce()方法里边,有两部分,第一是个回调函数,第二个参数是设置的初始值。回调函数中可以有四个参数,第一个参数是上一次回调返回的值,或者设置的初始值,第二个参数是当前被处理的项,第三个参数是当前被处理项的索引值,第四项是原数组

1.求和

var total = [ 0, 1, 2, 3 ].reduce(
  ( acc, cur ) => acc + cur,
  0
)

// 累加对象里面的值
let sum = [{x: 1}, {x:2}, {x:3}].reduce(
    (accumulator, currentValue) => accumulator + currentValue.x
    ,0
);
 
console.log(sum) // logs 6

2.二维数组变一维

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
 ( acc, cur ) => acc.concat(cur),
 []
)

3.计算每个元素出现的次数

const names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
 
let countedNames = names.reduce(function (allNames, name) { 
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
  1. 数组去重

    let arr = [1,2,3,4,4,1]
    let newArr = arr.reduce((pre,cur)=>{
        if(!pre.includes(cur)){
          return pre.concat(cur)
        }else{
          return pre
        }
    },[])
    console.log(newArr);// [1, 2, 3, 4]
    
8.数组去重
  1. 将数组的每一个元素通过两次for循环依次与其他元素做比较,发现重复元素,利用数组方法splice()删除重复元素

    function noRepeat1(arr){
            // 第一层for用来控制循环的次数
            for(var i=0; i<arr.length; i++){
                //第二层for 用于控制与第一层比较的元素
                for(var j=i+1; j<arr.length; j++){
                    //如果相等
                    if(arr[i] == arr[j]){
                        //删除后面的 即第 j个位置上的元素  删除个数 1 个
                        arr.splice(j,1);
                        // j--很关键的一步  如果删除 程序就会出错 
                        //j--的原因是 每次使用splice删除元素时 返回的是一个新的数组 
                        // 这意味这数组下次遍历是 比较市跳过了一个元素
                        /*
                            例如: 第一次删除后 返回的是 1 1 3 2 1 2 4
                         *  但是第二次遍历是 j的值为2  arr[2] = 3
                         *  相当于跳过一个元素 因此要 j--
                         * */
                        j--;
     
                    }
     
                }
            }
     
            return arr;
        }
    
    1. 通过foreach遍历数组,新建一个空数组,然后用includes()或者indexof ()判断新数组里边有没有遍历出来的每一项,没有的话,加到新数组里边去

    2. 通过filter过滤,返回 self.indexOf(value) === index 值的情况

         var newarr = arr.filter(function (value, index, self) {
            return self.indexOf(value) === index;
          });
      

      4.通过reduce()方法,先设置一个空数组,然后拿includes判断每一项是否在新的数组中,不再 的话,加里边

      let arr = [1,2,3,4,4,1]
      let newArr = arr.reduce((pre,cur)=>{
          if(!pre.includes(cur)){
            return pre.concat(cur)
          }else{
            return pre
          }
      },[])
      console.log(newArr);// [1, 2, 3, 4]
      

    5.通过new Set()去重 ,可以看下

  2. slice()和splice()区别

    slice截取数组的一段 返回一个新的数组 不改变原数组,两个参数,一是,开始删除的位置,二是结束的位置(不包括),

    splice可以删除或者新增 会改变原数组,三个参数可以有,一是开始位置,二是改变多少项,三个替换的内容

  3. js继承

    继承有以下六种方法
    1、原型链继承 JavaScript 实现继承的基本思想:通过原型将一个引用类型继承另一个引
    用 类型的属性和方法
    2、借用构造函数继承(伪造对象或经典继承) JavaScript 实现继承的基本思想:在子类构造
    函数内部调用超类型构造函数。 通过使用 apply()和 call()方法可以在新创建的子类对象上
    执 行构造函数
    3、组合继承(原型+借用构造)(伪经典继承) JavaScript 实现继承的基本思想:将原型链和借
    用构造函数的技术组合在一块,从而发挥两者之长的一种继承模式
    将原型链和借用构造函数的技术组合到一起,从而取长补短发挥两者长处的一种继承模式
    4、型式继承 JavaScript 实现继承的基本思想:借助原型可以基于已有的对象创建新对
    象, 同时还不必须因此创建自定义的类型
    5、寄生式继承 JavaScript 实现继承的基本思想:创建一个仅用于封装继承过程的函数,
    该 函数在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。
    寄生式继承是原型式继承的加强版
    6、寄生组合式继承 JavaScript 实现继承的基本思想:通过借用函数来继承属性,通过原
    型 链的混成形式来继承方法

11.new

1、创建一个空对象: 并且 this 变量引入该对象,同时还继承了函数的原型
2、设置原型链 空对象指向构造函数的原型对象
3、执行函数体 修改构造函数 this 指针指向空对象,并执行函数体
4、判断返回值 返回对象就用该对象,没有的话就创建一个对象

三.vue
1.介绍一下vue

vue是一款渐进式 的轻量级框架,他的核心库只关注视图层,

Vue作为一款轻量级框架、简单易学、双向数据绑定、组件化、数据和结构的分离、虚拟DOM、运行速度快,并且作者是中国人尤雨溪,对应的API文档对国内开发者优化,作为前端开发人员的首选入门框架,Vue 有很多优势:

1、 Vue.js 可以进行组件化开发,使代码编写量大大减少,读者更加易于理解。

2、 Vue.js 最突出的优势在于可以对数据进行双向绑定。

3、使用 Vue.js 编写出来的界面效果本身就是响应式的,这使网页在各种设备上都能显示出非常好看的效果。

4、相比传统的页面通过超链接实现页面的切换和跳转,Vue 使用路由不会刷新页面。

5、vue是单页面应用,使页面局部刷新,不用每次跳转页面都要请求所有数据和dom,这样大大加快了访问速度和提升用户体验。

6、而且他的第三方UI组件库使用起来节省很多开发时间,从而提升开发效率。

2.vue生命周期

​ Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

1)beforeCreate

​ 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

2)created

​ 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer), 属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

3)beforeMount

​ 在挂载开始之前被调用:相关的 render 函数首次被调用。

4)mounted

​ el 被新创建的 vm. e l 替 换 , 并 挂 载 到 实 例 上 去 之 后 调 用 该 钩 子 。 如 果 r o o t 实 例 挂 载 了 一 个 文 档 内 元 素 , 当 m o u n t e d 被 调 用 时 v m . el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm. elrootmountedvm.el 也在文档内。

5)beforeUpdate

​ 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。

6)updated

​ 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

7)activated

​ keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。

8)deactivated

​ keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。

9)beforeDestroy

​ 实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。

10)destroyed

​ Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

11)errorCaptured(2.5.0+ 新增)

​ 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

3.vue-cli脚手架创建项目,目录结构
  • node_modules:第三方依赖

  • public:公共资源

  • src:源码

    • assets:静态资源,css、img、js、font等
    • compoments:组件,一般自定义组件
    • router:路由配置
    • views:视图组件
  • App.vue:首页组件(默认组件)

  • main.js:入口文件

  • .browserslistrc:配置使用CSS兼容性插件的使用范围

  • .eslintrc.js:配置ESLint

  • .gitignore:配置git忽略的文件或者文件夹

  • babel.config.js:使用一些预设

  • package.json:项目描述既依赖

  • package-lock.json:版本管理使用的文件

  • README.md:项目描述

  • 或者这样回答

    1、 assets 文件夹是放静态资源

    2、 components 是放组件

    3、 router 是定义路由相关的配置

    4、 view 视图

    5、 app.vue 是一个应用主组件

    6、 main.js 是入口文件

4.介绍路由,路由模式,权限控制

url地址和资源的对应关系,就是路由,

vue的路由有三种模式

  1. hash模式 使用URL的hash值来作为路由。通过onhashchange事件监听hash值的改变实现,它的特点在于:hash 虽然出现URL中,但不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。
  2. history模式 利用了HTML5 中新增的pushState() 和replaceState() 方法。(需要特定浏览器支持) 这两个方法应用于浏览器的历史记录站,在当前已有的back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改是,虽然改变了当前的URL,但你浏览器不会立即向后端发送请求。 history模式,会出现404 的情况,需要后台配置。
  3. abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式

hash模式和history模式切换,在router.js文件中,路由初始化上加 mode:history;

const router = new VueRouter({
    // mode: 'history',
    base: process.env.BASE_URL,
    routes
})
  1. 路由权限

    1、创建vue实例的时将vue-router挂载,但vue-router初始时只挂载登录页面(或是其他不需要权限的页面)。

    2、当用户登录后,获取后台返回的该用户能访问的页面数组role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。

    3、调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。

    4、使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。

5.data为什么是个函数return,而不是对象形式

​ 1、 每个组件都是 Vue 的实例。

​ 2、 组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一个会影响其他

​ 3、组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空 间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。

6.组件之间通信方式

​ 1)父组件向子组件传递数据

​ 父组件内设置要传的数据,在父组件中引用的子组件上绑定一个自定义属性并把数据绑定在自定义属性上,在子组件添加参数props接收即可

​ 2)子组件向父组件传递/数据

	 子组件通过vue实例方法$emit进行触发并且可以携带参数,父组件监听使用@(v-on)进行监听,然后进行方法处理

​ 3)非父子组件之间传递数据

	 1、引入第三方new vue定义为eventBus
		2、在组件中created中订阅方法eventBus.$on("自定义事件名",methods中的方法名)
	 3、在另一个兄弟组件中的methods中写函数,在函数中发布eventBus订阅的方法eventBus.$emit("自定义事件名”)
	 4、在组件的template中绑定事件(比如click)
7.axios,封装axios,一些参数配置项举例
/**
 * 封装一下axios
 */
// import store from '@/store.js'
// import router from '@/router.js' // 用到的话引入
import axios from 'axios'
const instance = axios.create({
  baseURL: '..', // 配置请求的基地址
  timeout: 3000, // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  withCredentials: true, // 表示跨域请求时是否需要使用凭证
  headers: { 'X-Requested-With': 'XMLHttpRequest' }, // `headers` 是即将被发送的自定义请求头
  transformRequest: [data => { // `transformRequest` 允许在向服务器发送前,修改请求数据
    // 它的意思,其实就是把这样的数据(对象){ name:"yangxu",age:23 } 转换成这样的数据(字符串) "name=yangxu&age=23"这样的查询字符串
    return JSON.stringify(data)
  }]
})
// // 添加请求拦截器
// axios.interceptors.request.use(function (config) {
//   // 在发送请求之前做些什么
//   return config;
// }, function (error) {
//   // 对请求错误做些什么
//   return Promise.reject(error);
// });

// // 添加响应拦截器
// axios.interceptors.response.use(function (response) {
//   // 对响应数据做点什么
//   return response;
// }, function (error) {
//   // 对响应错误做点什么
//   return Promise.reject(error);
// });
export default instance
8.v-if和v-show

v-if和v-show都能控制元素的显示和隐藏,区别是v-show是通过css中的display:none;控制显示隐藏 的,而v-if是动态的向DOM树内添加或者删除DOM元素来实现的显示与隐藏

v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建

总结(适用场景):如果要频繁切换某节点时,使用v-show(无论true或者false初始都会进行渲染,此后通过css来控制显示隐藏,因此切换开销比较小,初始开销较大),如果不需要频繁切换某节点时,使用v-if(因为懒加载,初始为false时,不会渲染,但是因为它是通过添加和删除dom元素来控制显示和隐藏的,因此初始渲染开销较小,切换开销比较大)

9.watch和computed区别

computed是计算属性,他主要是同步对数据进行一些处理,比如说进行一些计算或者对字符串的处理(购物车合计),他的使用是在,一个数据,是依赖多个数据变化的而变化,只有依赖的数据有变化时,数据才会变化,所以,他具有缓存的功能

而watch,他不仅可以做一些同步处理,而且做一些异步的处理,比如一些事件的派发,一些请求,他做的是侦听,一个数据发生改变,可能会触发多个事物,比如说视频禁止快进场景,快进了,提示不能快进,并且给他返回快进前位置

10.说一说watch,深度监听和立即执行,场景和原理

watch深度监听一个对象的变化

​ 1、有个原则监听谁,写谁的名字,然后是对应的执行函数, 第一个参数为最新的改变值,第二个值为上一次改变的值, 注意: 除了监听 data,也可以监听计算属性 或者一个 函数的计算结果

​ 2、启用深度监听对象 deep:true

在选项参数中指定immediate: true将立即以表达式的当前值触发回调,watch监听开始之后立即被调用

	watch:{
  	 a:{
      	   handler:function(val,oldval){  
       },
       deep:true;
       immediate: true;
  		}
	}

11.vuex

​ Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,可以解决不同组件数据共享问题。

他有五个核心属性

1.state 存放所有公共状态的属性,项目全局通用的属性放在state里边

​ 使用:1. this.$store.state.属性

​ 2.通过mapState辅助函数 ,先import引入mapState函数,采用数组形式引入state属性( mapState([‘count’]) ),然后通过扩展运算符,把导出的属性映射到计算属性中

 import { mapState } from 'vuex'
 computed: {
    ...mapState(['count'])
  }

2.mutations mutations是一个对象,对象中存放修改state的方法 , state数据的修改只能通过mutations,并且mutations他是同步更新的

​ 使用: 1. this.$store.commit(‘方法名’, 参数)

			2. 通过mapMutations辅助函数,首先引入,然后通过扩展运算符,把mutations     内的方法映射到methods里

3.actions Vuex中mutations中要求不能写异步代码,如果有异步的ajax请求,应该放置在actions中

 actions: {
  //  获取异步的数据 context表示当前的store的实例 可以通过 context.state 获取状态 也可以通过context.commit 来提交mutations, 也可以 context.diapatch调用其他的action
    getAsyncCount (context) {
      setTimeout(function(){
        // 一秒钟之后 要给一个数 去修改state
        context.commit('addCount', 123)
      }, 1000)
    }
 } 

使用: 1. this.$store.dispatch(‘异步的方法名’, 参数)

​ 2, 通过mapActions辅助函数,首先引入,然后通过扩展运算符,把actions 内的方法映射到methods里

4.getters 除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的, getters可以理解为类似于计算属性

    getters: {
    // getters函数的第一个参数是 state
    // 必须要有返回值
     filterList:  state =>  state.list.filter(item => item > 5)
  }

​ 使用: 1. this.$store.getters.属性

​ 2.mapGetters辅助函数,映射到计算属性中,和state一样的方式

5.modules 如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护,所以给他分模块管理

const store  = new Vuex.Store({
  modules: {
    user: {
     namespaced: true,         // 保证内部模块的高封闭性
       state: {
         token: '12345'
       },
       mutations: {
        //  这里的state表示的是user的state
         updateToken (state) {
            state.token = 678910
         }
       }
    },
    setting: {
      state: {
         name: 'Vuex实例'
      }
    }
  })

使用: 1. this.$store.state.模块名称.属性名

这样取有些麻烦,可以通过getters改善一下

 getters: {
   token: state => state.user.token,
   name: state => state.setting.name
 } 
  1. this.$store.dispatch(‘user/updateToken’) // 直接调用方法
12.scoped

把scoped写在style上,保证单页面使用这些样式,不会污染其他

13.vue项目登录功能,及登录后储存信息

1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码

2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token和一些其他的用户信息

3、前端拿到信息,将信息存储到vuex中并且要做持久化缓存,缓存到localstorage中,(如果仅仅保存到vuex中,会存在一刷新页面,vuex中数据丢失的情况,

因为刷新页面会重新加载vue实例,store里面的数据就会被重新赋值)。

4.再发请求的时候携带token或者相关参数

14.数据双向绑定原理

vue双向绑定他是通过数据劫持,结合发布者-订阅者模式实现的

通过Object.defineProperty来劫持对象属性的getter和setter操作,并种下一个监听器,当数据变化时发出通知,给订阅者,然后触发相应的监听回调

订阅者模式中的发布函数,是发布时执行 的回调

订阅函数,是添加订阅者,传入发布时要执行的函数,可能会携带额外参数

15.$set

vue在创建实例的时候把data深度遍历所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。让 Vue 追踪依赖,在属性被访问和修改时通知变化。所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
当你在对象上新加了一个属性 newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制(因为是在初始化之后添加的),vue.$set是能让vue知道你添加了属性, 它会给你做处理

如果在实例创建之后添加新的属性到实例上,不触发updated函数,视图不更新。

this.$set(this.data,”key”,value’)

  data() {
    return {
      test: [1, 2, 3, 4],
    }
  },
  methods: {
    btn() {
      // this.test[1] = 'hi'
      this.$set(this.test, 1, 'hi')
      console.log(this.test)
    },
  },
16.vue.config.js配置
module.exports = {
  outputDir: 'D:\\website', // 打包文件夹
  publicPath: process.env.NODE_ENV === 'production' ? 'website/' : '/', // 部署时所在相对路径
  // lintOnSave: false, // eslint-loader 是否在保存的时候检查
  devServer: { // 对请求进行拦截和处理的一个中间件
    proxy: 'http://localhost:90/freshproject/'
    // proxy: {
    //   '/api': {
    //     target: 'http://localhost:8080', //要访问的跨域的域名
    //     ws: true, // 是否启用websockets
    //     changeOrigin: true, // 开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样客户端端和服务端进行数据的交互就不会有跨域问题
    //     pathRewrite: {  // 为是否将指定字符串转换一个再发过去
    //       '^/api': ''
    //     }

    //   },

    // },
    // before(app) { // before方法:能够在其他所以的中间件之前执行自定义的中间件
    //   app.get('/test', (req, res) => {
    //     res.json(test)
    //   })
    // }

    // configureWebpack: (config) => {
    //   if (process.env.NODE_ENV === 'production') {
    //     // 为生产环境配置
    //     // 在打包之后的js中去掉console.log
    //     config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
    //   } else {
    //     // 为开发环境配置
    //   }
    // },
    // productionSourceMap: false, // 生产环境是否生成 sourceMap 文件


    // cdn 引入,减小打包后体积,优化 "表示要引入的资源的名字": “表示该模块提供给外部引用的名字”
    // 要注意名字的写法,否则会报错 xxx is not defined
    // configureWebpack: {
    //   externals: { // 配置不打包的js
    //     'vue': 'Vue',
    //     'element-ui': 'ELEMENT',
    //     //   'vue-router': 'VueRouter',
    //     //   'vuex': 'Vuex',
    //     //   'axios': 'axios'

    //   }
    // },
  }
}
17.封装组件,上传npm

1.写好组件

通过vue-cli创建项目,新建自己的组件文件夹,里边放自己写的组件,同时,在这个组件文件夹下创建index.js文件,通过import导入自己写的组件,然后通过install函数,结合Vue.component()注册组件,然后导出,这样,在main.js里边就可以import这个index.js文件,并vue.use()使用,然后在这个vue项目中就可以全局使用我们自己写 的组件了

2.打包上传

需要配置打包命令在package.json中,专门打包对应的文件,然后npm上传打包生成的包

3.使用

当你上传成功后,别人就可以直接npm i 安装你的包了

18.nextTick

​ 视图更新之后,基新的视图进行操作,this.$nextTick将回调延迟到下次dom更新循环之后执行

​ 在vue中,数据和dom渲染是异步的,数据的变化不是立即就引起视图的变化,而是在下一轮的渲染操作中去更新视图

19.项目优化方案

1.打包的时候去掉map文件 productionSourceMap: false

2.路由懒加载

3.使用gzip压缩

4.cdn 加载 直接引入第三方资源,减小服务器压力

5.组件的按需引入

6.去掉打包后 的console

    configureWebpack: (config) => {
      if (process.env.NODE_ENV === 'production') {
        // 为生产环境配置
        // 在打包之后的js中去掉console.log
        config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
      } else {
        // 为开发环境配置
      }
    },
20.为什么v-if和v-for不能一起用,解决方案

v-for 比 v-if 具有更高的优先级,每一次判断v-if真假的时候,都会先v-for循环

解决: 一是可以把v-if和v-for分开,别写在一个元素上边;二是可以先通过计算属性,把v-if为false 的情况给他过滤掉,直接显示为真的情况

  1. <router-view :key="$route.fullPath" / >

    通过绑定一个fullPath,可以识别当前页面路由的完整地址,当地址发生改变(包括参数改变)则重新渲染页面(例如动态路由参数的变化)

四.其他
1.localstorage、sessionstorage、cookie

共同点:都是保存在浏览器端、且同源的
区别:
1、cookie 数据始终在同源的 http 请求中携带(即使不需要),即 cookie 在浏览器和服务器间来回传递,而 sessionStorage 和 localStorage 不会自动把数据发送给服务器,仅在本地保存。cookie 数据还有路径(path)的概念,可以限制 cookie 只属于某个路径下
2、存储大小限制也不同,cookie 数据不能超过 4K,同时因为每次 http 请求都会携带cookie、所以 cookie 只适合保存很小的数据,如会话标识。sessionStorage 和 localStorage虽然也有存储大小的限制,但比 cookie 大得多,可以达到 5M 或更大
3、数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效; localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie 过期时间之前有效,即使窗口关闭或浏览器关闭
4、作用域不同,sessionStorage 不在不同的浏览器窗口中共享,即使是同一个页面;
localstorage 在所有同源窗口中都是共享的;cookie 也是在所有同源窗口中都是共享的
5、web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者
6、web Storage 的 api 接口使用更方便

2.浏览器兼容问题

1.IE8下的png图片无法显示,因为会把png格式的图片解析成span标签

解决方案: 对span标签设置宽高和display:inline-block

2.置较小高度的容器(小于10px),在IE6下不识别小于10px的高度

解决方案:给容器添加overflow:hidden

3.图片默认有间隙

解决方案:

1)给img标签添加左浮动float:left;

2)给img标签添加display:block;

4.字体大小在不同浏览上不一致。例如font-size:14px,在 IE 中的实际行高是16px,下面有3px留白;在 Firefox 中的实际行高是17px,下面有3px留白,上边1px留白;在 opera 中就更不一样了。

解决方案: 统一指定行高 line-height 高度

5…当在a标签中嵌套img标签时,在某些浏览器中img会有蓝色边框

解决方案: 给img添加border:0;或者是border:none

6.百分比的bug 父元素宽度为100%,子元素宽度各为50%,在IE6下各个元素宽度之和超过100%

解决方案:给右边浮动的子元素添加clear:right

3.购物车
4.换肤功能

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值