2022年最新互联网大厂前端面试题及答案-前端工程必备技能(持续整理更新中【关注收藏不迷路】)

对于做前端的朋友,或者做了前端几年了,基础不好的,或者想进大厂的想了解深入,下面的知识点很多前端朋友都没有深入了解。很重要,看完有种茅塞顿开感觉,**关注+收藏哦,总有一天用的得。**
涉及到知识点:HTML知识,JS,ES5/ES6,Vue, Webpack, 前端HTTP网络知识,css/css3。
持续整理更新中
在这里插入图片描述

js部分

面试官:JS的数据类型都有哪些?

ES5的5种:Null,undefined,Boolean,Number,String, ES6新增:Symbol表示独一无二的值
ES10新增:BigInt 表示任意大的整数

null 和 undefined 的区别?

在 if 语句中 null 和 undefined 都会转为false两者用相等运算符比较也是相等

首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。

不同:

undefined 代表的含义是未定义,

定义了形参,没有传实参,显示undefined

一般变量声明了但还没有定义的时候会返回 undefined

对象属性名不存在时,显示undefined

函数没有写返回值,即没有写return,拿到的是undefined

null 代表的含义是空对象。也作为对象原型链的终点

null 主要用于赋值给一些可能会返回对象的变量,作为初始化。

js数据类型的判断方式有哪些?
1.typeof

缺点:typeof null的值为Object,无法分辨是null还是Object
2.instanceof

缺点:只能判断某对象是否存在于目标对象得的原型链上
3.constructor
4.Object.prototype.toString.call()

一种最好的基本类型检测方式 Object.prototype.toString.call() ;它可以区分 null 、 string 、

booleannumberundefinedarrayfunctionobjectdatemath 数据类型。

缺点:不能细分为谁谁的实例

    // -----------------------------------------typeof
    typeof undefined // 'undefined' 
    typeof '10' // 'String' 
    typeof 10 // 'Number' 
    typeof false // 'Boolean' 
    typeof Symbol() // 'Symbol' 
    typeof Function // ‘function' 
    typeof null // ‘Object’ 
    typeof [] // 'Object' 
    typeof {
    
    } // 'Object'


    // -----------------------------------------instanceof
    function Foo() {
    
     }
    var f1 = new Foo();
    var d = new Number(1)


    console.log(f1 instanceof Foo);// true
    console.log(d instanceof Number); //true
    console.log(123 instanceof Number); //false   -->不能判断字面量的基本数据类型


    // -----------------------------------------constructor
    var d = new Number(1)
    var e = 1
    function fn() {
    
    
      console.log("ming");
    }
    var date = new Date();
    var arr = [1, 2, 3];
    var reg = /[hbc]at/gi;

    console.log(e.constructor);//ƒ Number() { [native code] }
    console.log(e.constructor.name);//Number
    console.log(fn.constructor.name) // Function 
    console.log(date.constructor.name)// Date 
    console.log(arr.constructor.name) // Array 
    console.log(reg.constructor.name) // RegExp
    //-----------------------------------------Object.prototype.toString.call()
    console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]" 
    console.log(Object.prototype.toString.call(null)); // "[object Null]" 
    console.log(Object.prototype.toString.call(123)); // "[object Number]" 
    console.log(Object.prototype.toString.call("abc")); // "[object String]" 
    console.log(Object.prototype.toString.call(true)); // "[object Boolean]" 

    function fn() {
    
    
      console.log("ming");
    }
    var date = new Date();
    var arr = [1, 2, 3];
    var reg = /[hbc]at/gi;
    console.log(Object.prototype.toString.call(fn));// "[object Function]" 
    console.log(Object.prototype.toString.call(date));// "[object Date]" 
    console.log(Object.prototype.toString.call(arr)); // "[object Array]"
    console.log(Object.prototype.toString.call(reg));// "[object RegExp]"

面试官:=====有什么区别?

===是严格意义上的相等,会比较两边的数据类型和值大小

  • 数据类型不同返回false
  • 数据类型相同,但值大小不同,返回false

==是非严格意义上的相等,

  • 两边类型相同,比较大小
  • 两边类型不同,根据下方表格,再进一步进行比较。
  • Null == Undefined ->true String == Number ->先将String转为Number,在比较大小
  • Boolean == Number ->现将Boolean转为Number,在进行比较 Object ==
  • String,Number,Symbol -> Object 转化为原始类型

面试官:NaN === NaN返回什么?
返回 falseNaN永远不等于NaN,判断是否为NaN用一个函数 isNaN来判断;

isNaN传入的如果是其他数据类型,那么现将它使用Number()转为数字类型在进行判断

深拷贝和浅拷贝是什么,区别在哪?
浅拷贝主要是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝需要不但对指针进行拷贝,并对指针指向的内容进行拷贝,经过深拷贝后的指针是指向两个不同地址的指针。
代码方式理解和使用:

    // ----------------------------------------------浅拷贝
    // 只是把对象的属性和属性值拷贝到另一个对象中
    var obj1 = {
    
    
      a: {
    
    
        a1: {
    
     a2: 1 },
        a10: {
    
     a11: 123, a111: {
    
     a1111: 123123 } }
      },
      b: 123,
      c: "123"
    }
    // 方式1
    function shallowClone1(o) {
    
    
      let obj = {
    
    }

      for (let i in o) {
    
    
        obj[i] = o[i]
      }
      return obj
    }

    // 方式2
    var shallowObj2 = {
    
     ...obj1 }

    // 方式3
    var shallowObj3 = Object.assign({
    
    }, obj1)

    let shallowObj = shallowClone1(obj1);

    shallowObj.a.a1 = 999
    shallowObj.b = true

    console.log(obj1);  //第一层的没有被改变,一层以下就被改变了

    // ----------------------------------------------深拷贝

    // 简易版  
    function deepClone(o) {
    
    
      let obj = {
    
    }
      for (var i in o) {
    
    
        // if(o.hasOwnProperty(i)){
    
    
        if (typeof o[i] === "object") {
    
    
          obj[i] = deepClone(o[i])
        } else {
    
    
          obj[i] = o[i]
        }
        // }
      }
      return obj
    }


    var myObj = {
    
    
      a: {
    
    
        a1: {
    
     a2: 1 },
        a10: {
    
     a11: 123, a111: {
    
     a1111: 123123 } }
      },
      b: 123,
      c: "123"
    }

    var deepObj1 = deepClone(myObj)
    deepObj1.a.a1 = 999
    deepObj1.b = false
    console.log(myObj);



    // 简易版存在的问题:参数没有做检验,传入的可能是 Array、null、regExp、Date
    function deepClone2(o) {
    
    
      if (Object.prototype.toString.call(o) === "[object Object]") {
    
      //检测是否为对象
        let obj = {
    
    }
        for (var i in o) {
    
    
          if (o.hasOwnProperty(i)) {
    
    
            if (typeof o[i] === "object") {
    
    
              obj[i] = deepClone(o[i])
            } else {
    
    
              obj[i] = o[i]
            }
          }
        }
        return obj
      } else {
    
    
        return o
      }
    }

    function isObject(o) {
    
    
      return Object.prototype.toString.call(o) === "[object Object]" || Object.prototype.toString.call(o) === "[object Array]"
    }

    // 继续升级,没有考虑到数组,以及ES6中的map、set、weakset、weakmap
    function deepClone3(o) {
    
    
      if (isObject(o)) {
    
    //检测是否为对象或者数组
        let obj = Array.isArray(o) ? [] : {
    
    }
        for (let i in o) {
    
    
          if (isObject(o[i])) {
    
    
            obj[i] = deepClone(o[i])
          } else {
    
    
            obj[i] = o[i]
          }
        }
        return obj
      } else {
    
    
        return o
      }
    }


    // 有可能碰到循环引用问题  var a = {}; a.a = a; clone(a);//会造成一个死循环
    // 循环检测
    // 继续升级
    function deepClone4(o, hash = new map()) {
    
    
      if (!isObject(o)) return o//检测是否为对象或者数组
      if (hash.has(o)) return hash.get(o)
      let obj = Array.isArray(o) ? [] : {
    
    }

      hash.set(o, obj)
      for (let i in o) {
    
    
        if (isObject(o[i])) {
    
    
          obj[i] = deepClone4(o[i], hash)
        } else {
    
    
          obj[i] = o[i]
        }
      }
      return obj
    }

    // 递归易出现爆栈问题
    //  将递归改为循环,就不会出现爆栈问题了
    var a1 = {
    
     a: 1, b: 2, c: {
    
     c1: 3, c2: {
    
     c21: 4, c22: 5 } }, d: 'asd' };
    var b1 = {
    
     b: {
    
     c: {
    
     d: 1 } } }
    function cloneLoop(x) {
    
    
      const root = {
    
    };
      // 栈 
      const loopList = [  //->[]->[{parent:{a:1,b:2},key:c,data:{ c1: 3, c2: { c21: 4, c22: 5 } }}]
        {
    
    
          parent: root,
          key: undefined,
          data: x,
        }
      ];
      while (loopList.length) {
    
    
        // 深度优先
        const node = loopList.pop();
        const parent = node.parent; //{} //{a:1,b:2}
        const key = node.key; //undefined //c
        const data = node.data; //{ a: 1, b: 2, c: { c1: 3, c2: { c21: 4, c22: 5 } }, d: 'asd' }  //{ c1: 3, c2: { c21: 4, c22: 5 } }}
        // 初始化赋值目标,key 为 undefined 则拷贝到父元素,否则拷贝到子元素
        let res = parent; //{}->{a:1,b:2,d:'asd'} //{a:1,b:2}->{}
        if (typeof key !== 'undefined') {
    
    
          res = parent[key] = {
    
    };
        }
        for (let k in data) {
    
    
          if (data.hasOwnProperty(k)) {
    
    
            if (typeof data[k] === 'object') {
    
    
              // 下一次循环 
              loopList.push({
    
    
                parent: res,
                key: k,
                data: data[k],
              })
            } else {
    
    
              res[k] = data[k];
            }
          }
        }
      }
      return root
    }


    function deepClone5(o) {
    
    
      let result = {
    
    }
      let loopList = [
        {
    
    
          parent: result,
          key: undefined,
          data: o
        }
      ]

      while (loopList.length) {
    
    
        let node = loopList.pop()
        let {
    
     parent, key, data } = node
        let anoPar = parent
        if (typeof key !== 'undefined') {
    
    
          anoPar = parent[key] = {
    
    }
        }

        for (let i in data) {
    
    
          if (typeof data[i] === 'object') {
    
    
            loopList.push({
    
    
              parent: anoPar,
              key: i,
              data: data[i]
            })
          } else {
    
    
            anoPar[i] = data[i]
          }
        }
      }
      return result
    }


    let cloneA1 = deepClone5(a1)
    cloneA1.c.c2.c22 = 5555555
    console.log(a1);
    console.log(cloneA1);


    // ------------------------------------------JSON.stringify()实现深拷贝

    function cloneJson(o) {
    
    
      return JSON.parse(JSON.stringify(o))
    }

    // let obj = { a: { c: 1 }, b: {} };
    // obj.b = obj;
    // console.log(JSON.parse(JSON.stringify(obj))) // 报错 // Converting circular structure to JSON

    

深拷贝能使用hash递归的方式写出来就可以了
不过技多不压身,推荐还是看一看使用while实现深拷贝方法

面试官:为什么JS是单线程的?

**答:**因为JS里面有可视的Dom,如果是多线程的话,这个线程正在删除DOM节点,另一个线程正在编辑Dom节点,导致浏览器不知道该听谁的

面试官:说说 Promise 的原理?你是如何理解 Promise 的?

promise是一个对异步操作进行封装并返回其结果的构造函数. 使代码更加简洁和避免回调地狱。
promise是浏览器引擎自带的(但不是所有浏览器都支持promise)

Promise是异步编程的一种解决方案,可以替代传统的解决方案–回调函数和事件。ES6统一了用法,并原生提供了Promise对象。作为对象,Promise有一下两个特点: * (1)对象的状态不受外界影响。 * (2)一旦状态改变了就不会在变,也就是说任何时候Promise都只有一种状态。
Promise有三种状态,分别是:**Pending **(进行中), ** Resolved (已完成), Rejected ** (已失败)。Promise从Pending状态开始,如果成功就转到成功态,并执行resolve回调函数;如果失败就转到失败状态并执行reject回调函数。
基本用法

var promise = new Promise(function(resolve,reject)
setTimeout(function(){
    
                                  
  console.log("hello world");},2000);
});    

    function greet(){
    
    
    var promise = new Promise(function(resolve,reject){
    
    
        var greet = "hello  world";
        resolve(greet);
    });
    return promise;
    }
    greet().then(v=>{
    
    
    console.log(v);//*
    })

function greet(){
    
    
var promise = new Promise(function(resolve,reject){
    
    
    var greet = "hello  world";
    resolve(greet);
});
return promise;
}
var p = greet().then(v=>{
    
    
console.log(v);
})

console.log(p);

面试官:async 和await 理解,以下代码的执行顺序是什么?

关于async
async 其实就是promise的语法糖。函数前面必须加一个async,异步操作的方法前加一个await 关键字。顾名思义,就是让你等一下,执行完了再继续往下走。注意:await 只能在async函数中执行,否则会报错

关于await
await的意思就是等待。它后面可以跟一个表达式。如果是值(如字符串、数字、普通对象等等)的话,返回值就是本身的值。 通常使用方式为在后面跟一个promise对象。await会等待这个promise的状态由pending转为fulfilled或者rejected。在此期间它会阻塞,延迟执行await语句后面的语句。
如果promise对象的结果是resolve,它会将resolve的值,作为await表达式的运算结果。

  async function async1() {
    
    
   console.log('async1 start')
   await async2()
   console.log('async1 end')
  }
  async function async2() {
    
    
   console.log('async2')
  }
  async1()
  console.log('script start')

//执行到await时,如果返回的不是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部继续执行
//执行到await时,如果返回的是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部等promise状态达到fulfill的时候再继续执行下面的代码
//所以结果为
//async1 start
//async2
//script start
//async1 end

面试官:var let const 有什么区别⭐⭐⭐⭐⭐

答:

  • var

    • var声明的变量可进行变量提升,let和const不会
    • var可以重复声明
    • var在非函数作用域中定义是挂在到window上的
  • let

    • let声明的变量只在局部起作用
    • let防止变量污染
    • 不可在声明
  • const

    • 具有let的所有特征
    • 不可被改变
    • 不可改变只适用于直接地址。如果使用const声明的是对象的话,是可以修改对象内部的值的。

模块化

面试官:为什么要使用模块化?都有哪几种方式可以实现模块化,各有什么特点?⭐⭐⭐

为什么要使用模块化

  • 防止命名冲突
  • 更好的分离,按需加载
  • 更好的复用性
  • 更高的维护性

面试官:exportsmodule.exports有什么区别?⭐⭐⭐

导出方式不一样

  • exports.xxx=‘xxx’
  • module.export = {}

exports是module.exports的引用,两个指向的是用一个地址,而require能看到的只有module.exports

面试官:JS模块包装格式有哪些?⭐⭐⭐

commonjs

  • 同步运行,不适合前端

AMD

  • 异步运行
  • 异步模块定义,主要采用异步的方式加载模块,模块的加载不影响后面代码的执行。所有依赖这个模块的语句都写在一个回调函数中,模块加载完毕,再执行回调函数

CMD

  • 异步运行
  • seajs 规范

面试官:ES6和commonjs的区别
Commonjs、AMD、CMD、UMD、ESM 都有什么区别

问:require 和 import的区别?
调用时机

require 是运行时调用,所以其实是可以放在任何地方的
Import 是编译时调用,所以必须放在文件的开头
使用时,

require 需要使用 module.exports = fs 或者exports.fs = xxx
import 用 export default 或 export const xx
解构赋值

require 是赋值的过程
import 是解构的过程

面试官:箭头函数和普通函数的区别?箭头函数可以当做构造函数 new 吗?

  • 箭头函数是普通函数的简写,但是它不具备很多普通函数的特性
  • 第一点,this指向问题,箭头函数的this指向它定义时所在的对象,而不是调用它的对象 不会进行函数提升
  • 没有arguments对象,不能使用arguments,如果要获取参数的话可以使用rest运算符
  • 没有yield属性,不能作为生成器Generator使用
  • 不能new
    • 没有自己的this,不能调用call和apply
    • 没有prototype,new关键字内部需要把新对象的_proto_指向函数的prototype

js 遍历数组的方法⭐⭐⭐⭐⭐

reduce、map、filter、every、some、foreach.

数组可以改变原数组的方法⭐⭐⭐⭐⭐
Push、pop、shift、unshift、splice、sort、reverse
不改变的
join 变成字符
Slice,截取
concat 合并数组

foreach 和 map 有什么区别⭐⭐⭐⭐
foreach 没有返回值,一般如果用来遍历修改原数组的话可以用 foreach 方法

localstorage 怎么存储图片⭐⭐⭐⭐
创建一个canvas对象,把图片保存在 canvas 中,然后 canvas 对象 toDataUrl,在把 dataurl 数据存储在 localstorage 中。

或者使用 blob 二进制流存储,canvas 对象toBlob

**如何实现大文件上传?**⭐⭐⭐⭐

使用 input 接受大文件,使用file.slice进行分割分块上传(制定好一个块的大小,然后进行分割),等所有块上传完毕之后,promise.all(),运行成功回调

如何实现 localstorage 定时清除⭐⭐⭐⭐

自己重写一个 set 方法,内部逻辑就是添加一个现在的时间以及有效时长
再重写一个 get 方法,每当 get 的时候先进行判断是否过期,如果过期就删除,并返回 null,没过期的话正常返回

秒传、分片传输、断点传输⭐⭐⭐⭐

秒传
文件上传前,服务器先对文件做MD5校验,如果服务器上有同样的文件,则返回一个新地址,如果不想秒传也可以,修改文件中的内容就可以了(改名字不行)
分片传输
利用Blob提供的slice方法把大文件分割为一个个小文件分别传输。全部上传完成时候由服务端进行归总整合
断点传输
在分片上传的基础上,分成一个个小文件之后,每个小文件上传完毕之后对其进行状态的存储(localStorage),如果中间发生网络断线或者刷新,下次可以接着上次的进度上传

面试官:说说你知道的状态码⭐⭐⭐⭐⭐

  • 2开头的表示成功
    • 一般见到的就是200
  • 3开头的表示重定向
    • 301永久重定向
    • 302临时重定向
    • 304表示可以在缓存中取数据(协商缓存)
  • 4开头表示客户端错误
    • 403跨域
    • 404请求资源不存在
  • 5开头表示服务端错误
    • 500

**面试官:https和http有什么区别,https的实现原理?**⭐⭐⭐⭐⭐

  • http无状态无连接,而且是明文传输,不安全,默认连接80端口
  • https 是有不可否认性的,可以保证对方身份的真实性,默认端口是443端口,加密传输,而且会保证数据的完整性
  • https实现原理⭐⭐⭐
    • 首先客户端向服务端发送一个随机值和一个客户端支持的加密算法,并连接到443端口。
    • 服务端收到以后,会返回另外一个随机值和一个协商好的加密算法,这个算法是刚才发送的那个算法的子集
    • 随后服务端会再次发送一个 CA 证书,这个 CA 证书实际上就是一个公钥,包含了一些信息(比如颁发机构和有效时间等)
      客户端收到以后会验证这个 CA 证书,比如验证是否过期,是否有效等等,如果验证未通过,会弹窗报错。
    • 如果验证成功,会生成一个随机值作为预主密钥,客户端使用刚才两个随机值和这个预主密钥组装成会话密钥;再使用刚才服务 - 端发来的公钥进行加密发送给服务端;这个过程是一个非对称加密(公钥加密,私钥解密)
    • 服务端收到以后使用私钥解密,随后得到那两个随机值和预主密钥,随后再组装成会话密钥。
    • 客户端在向服务端发起一条信息,这条信息使用会话秘钥加密,用来验证服务端时候能收到加密的信息
    • 服务端收到以后使用刚才的会话密钥解密,在返回一个会话密钥加密的信息,双方收到以后 SSL 建立完成;这个过程是对称加密(加密和解密是同一个)

面试官:localStorage、SessionStorage、cookie、session 之间有什么区别⭐⭐⭐⭐⭐

  • localStorage
    生命周期:关闭浏览器后数据依然保留,除非手动清除,否则一直在
    作用域:相同浏览器的不同标签在同源情况下可以共享localStorage
  • sessionStorage
    生命周期:关闭浏览器或者标签后即失效
    作用域:只在当前标签可用,当前标签的iframe中且同源可以共享
  • cookie
    一开始cookie 不是用来存储的,而是为了弥补 http 的状态的不足,http 是无状态协议。每当向服务器发起请求、请求结束,下次发送请求的时候服务端就不知道是谁了,所以 cookie 是用来弥补这个不足的
    cookie 有很多缺陷,比如:
    • 容量缺陷。cookie 的存储空间只有4KB
    • 性能缺陷。有时候 cookie 我们用不到,但是不管用的到用不到,http 在发送请求的时候一定会带着 cookie,这就造成了性能的浪费
    • 安全缺陷。cookie 在 http 下很容易被非法用户获取。尤其是设置了 http-only 为 false 的情况下,这个时候 js 可以读取到 cookie,很容易受到 xss攻击。
  • cookie 是保存在客户端的,一般由 server 设置值及过期时间
    • cookie 没有提供删除的 API,如果想要删除的 的话可以把 max-age 设为0或者把 expire 设置为当前时间(立刻过期)即可
  • cookie 的属性有
    • http-only
      • 不能被客户端更改访问,防止 XSS 攻击
    • max-age
      • 生效后存活的时间
    • Secure
      • 是否只允许在 https 下传输
      • expire
      • 过期时间
  • session
    • session 是保存在服务端的
    • session 的运行依赖 sessionId,sessionId 又保存在 cookie 中,所以禁用了 cookie之后 session 也是用不了的,如果硬要用也可以,可以把 sessionId 存储在 url 中
    • session一般是用来跟踪用户状态的
    • session 比较安全,因为存储在服务器中,不过为了减少服务端的压力,很多信息还是推荐存在 cookie 中的

**问:服务端渲染和客户端渲染的区别,各自的优缺点?**⭐⭐⭐⭐⭐

  • 服务端渲染(SSR Server Site Rendering)
  • 有利于 SEO,首屏加载快,但是重复请求次数多,开发效率低,服务器压力大
  • 渲染的时候返回的是完整的 html 格式
  • 应用场景:可能被搜索到的
  • 客户端渲染(CSR Client Site Rendering)
  • 不利于 SEO,首屏加载慢,前后端分离开发,交互速度快、体验好
  • 渲染的时候返回的是 json 数据格式,由浏览器完成渲染
  • 应用场景:app 内部"嵌套"的 h5页面

问:什么是JWT(Json Web Token)?⭐⭐⭐⭐⭐
答:
在没有 JWT 之前,验证客户端的方式就是通过 token,具体方式如下

  • 用户输入账号密码以后,向服务端发起请求,服务端生成token返回给客户端,然后下次客户端请求数据的时候会携带着 token,服务端收到之后,会与之前保存的 token进行验证,验证通过以后返回数据,验证不通过就不返回。
  • 不过这种方式的扩展性很差,因为如果有上万个用户发起请求的话就需要保存上万条 token,这样对服务端而言无疑是压力巨大的

后来出现了 JWT,这种方法可以把 token 保存在客户端
JWT 相当于把数据转换成 JSON 对象,这个特殊的 JSON 对象分为三部分:头部、负载、签名,他们之间分别用.区分开

  • 头部(header)
    保存的是JWT 的元数据,表明所使用的 hash 算法,以 JSON 对象的方式存储,然后转换成 Base64URL 的格式
  • 负载(payload)
    也是 JSON 对象格式,用来存放自己的数据
  • 签名(Signature)
    确保消息的完整性

###############美丽的分割线##################

Vue系列面试题

在这里插入图片描述

Vue双向绑定

数据劫持: vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
阐述一下你所理解的MVVM响应式原理⭐⭐⭐⭐⭐

vue是采用数据劫持配合发布者-订阅者的模式的方式,通过Object.defineProperty()来劫持各个属性的getter和setter,在数据变动时,发布消息给依赖收集器(dep中的subs),去通知(notify)观察者,做出对应的回调函数,去更新视图

MVVM作为绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer,Compile之间的通信桥路,达到数据变化=>视图更新;视图交互变化=>数据model变更的双向绑定效果。

Vue 如何监听数组的?

首先第一点是要看数组里面是不是还存在对象,如果存在对象的话在进行深层遍历是否还依然存在对象,再把对象进行 defineProperty监听。然后数组,数组的改变实质上只是几个方法,什么 popunshiftpush…Vue 重写了这几个方法,只要在调用这些方法的时候做出回调更新就可以了

为什么 Vue 要采用异步更新

因为首先 Vue 本身是组件级更新的,更改数据如果非常多,更新非常频繁,如果不采用异步更新的话每次都需要重新渲染。

每次有数据需要更新的时候,Vue 会把它放在一个队列中,等最后的时候会调用 nexttick 方法。nexttick就会清空这个队列。

用户也可以手动调用 nexttick(callback) 方法,会同样把callback 回调函数放入队列中,保证视图更新完之后被调用(因为会把 callback 放进队列的最后),并且是依次链式调用。

Vue中的nextTick

nextTick

解释
nextTick:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
应用
想要在Vue生命周期函数中的created()操作DOM可以使用Vue.nextTick()回调函数
在数据改变后要执行的操作,而这个操作需要等数据改变后而改变DOM结构的时候才进行操作,需要用到nextTick

Vue中的nextTick是微任务还是宏任务⭐⭐⭐⭐

nextTick的内部实现如果支持 promise 那就使用 promise,没有就用MutationObserver(微任务),在没有就用 setImmediate(宏任务),还没有就用 setTimeOut;所以nextTick 有可能是宏任务,也有可能是微任务
面试官:说说vue的生命周期⭐⭐⭐⭐⭐

  • beforeCreate 创建之前,此时还没有data和Method
  • Created 创建完成,此时data和Method可以使用了
    在Created之后beforeMount之前如果没有el选项的话那么此时生命周期结束,停止编译,如果有则继续
  • beforeMount 在渲染之前
  • mounted 页面已经渲染完成,并且vm实例中已经添加完$el了,已经替换掉那些DOM元素了(双括号中的变量),这个时候可以操作DOM了(但是是获取不了元素的高度等属性的,如果想要获取,需要使用nextTick())
  • beforeUpdate data改变后,对应的组件重新渲染之前
  • updated data改变后,对应的组件重新渲染完成
  • beforeDestory 在实例销毁之前,此时实例仍然可以使用
  • destoryed 实例销毁后

面试官:vue中父子组件的生命周期⭐⭐⭐⭐⭐

  • 父子组件的生命周期是一个嵌套的过程
  • 渲染的过程
    beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
  • 子组件更新过程
    beforeUpdate->子beforeUpdate->子updated->父updated
  • 父组件更新过程
    beforeUpdate->父updated
  • 销毁过程
    beforeDestroy->子beforeDestroy->子destroyed->父destroyed

面试官:computed 、watch、method的区别⭐⭐⭐⭐⭐

  • computed 计算属性,依赖其他属性,当其他属性改变的时候下一次获取computed值时也会改变,computed的值会有缓存
  • watch
    • 类似于数据改变后的回调
    • 如果想深度监听的话,后面加一个deep:true
    • 如果想监听完立马运行的话,后面加一个immediate:true
  • method 在使用 method 的时候,是这样使用的{ {fn{xx}}},渲染的时候如果没有发生变化,这个也是会被执行的。而 computed 是有缓存的,如果没有变化就不用再去执行了

面试官:Vue-router的模式⭐⭐⭐⭐⭐

  • hash模式
    监听hashchange事件实现前端路由,利用url中的hash来模拟一个hash,以保证url改变时,页面不会重新加载。
  • history模式
    利用pushstate和replacestate来将url替换但不刷新,但是有一个致命点就是,一旦刷新的话,就会可能404,因为没有当前的真正路径,要想解决这一问题需要后端配合,将不存在的路径重定向到入口文件。

面试官:MVC与MVVM有什么区别⭐⭐⭐⭐⭐

  • MVC

    • Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。处理数据的crud
    • View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。视图层,前端
    • Controller(控制器)是应用程序中处理用户交互的部分。一般包括业务处理模块和router路由模块,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
  • mvvm
    mvvm是前端图层的概念,mvvm是双向的,视图层可以通过 ViewModel 转换成模型层,模型层也可以通过 ViewModel 转换成视图层

    • Model(每个页面的单独的数据)
    • ViewModel (双向绑定,M和V之间的枢纽)
    • View(视图,相当于HTML结构)

面试官:讲讲diff算法⭐⭐⭐⭐⭐

diff算法是指对新旧虚拟节点进行对比,并返回一个patch对象,用来存储两个节点不同的地方,最后利用patch记录的消息局部更新DOM

diff 算法

  • diff算法是虚拟节点的比较

  • 先进行key值的比较

  • 先进行同级比较,

  • 然后再比较是不是一方有儿子,一方没儿子。如果是这样,直接在旧节点中插入或删除儿子即可

  • 在比较两方都有儿子的情况

    • 情况一:旧:ABCD,新:ABCDE;从头向尾比较,最后插入即可
    • 情况二:旧 :ABCD,新:EABCD;从尾向头比较,最后插入即可
    • 情况三:旧:ABCD,新:DABC;头和尾先进行一次比对,发现D 时,把 D 移至前面,再继续从头向尾比较,
    • 情况四:旧:ABCD,新 BCDA;从头向尾比较后发现不对,就会从尾向头比,把 A 移至最后,再继续比较
    • 情况五:旧 :ABCD,新CDME;从头向尾比较,把 CD 移至前面,最后 新建 ME,再把 CD 至为空
      递归比较子节点

虚拟DOM的优缺点⭐⭐⭐⭐⭐
缺点
首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢
优点
减少了dom操作,减少了回流与重绘
保证性能的下限,虽说性能不是最佳,但是它具备局部更新的能力,所以大部分时候还是比正常的DOM性能高很多的

Vue的Key的作用 ⭐⭐⭐⭐
key主要用在虚拟Dom算法中,每个虚拟节点VNode有一个唯一标识Key,通过对比新旧节点的key来判断节点是否改变,用key就可以大大提高渲染效率,这个key类似于缓存中的etag。

**为什么 v-for 会要有key?**⭐⭐⭐⭐⭐
因为在 vue 中会有一个 diff 算法,假如子节点 AB 调换了位置,它会比较 key 值,会直接调换,而不是一个销毁重新生成的过程

Vue组件通信⭐⭐⭐⭐⭐

父组件向子组件传值

  • 父组件发送的形式是以属性的形式绑定值到子组件身上。
  • 然后子组件用属性props接收
  • 在props中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制

子组件向父组件传值

  • 子组件用$emit()触发事件
  • $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据 $(event)来接收
  • 父组件用v-on 缩写为@ 监听子组件的事件

兄弟之间的传递

  • 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
    提供事件中心 var hub = new Vue()
  • 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
  • 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名

Vue中key是用来做什么的?为什么不推介使用index作为key?⭐⭐⭐⭐⭐
1、key的作用主要是为了高效的更新虚拟DOM(使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素)

2、当以数组的下标index作为index值时,其中一个元素(如增删改查)发生了变化就有可能导致所有元素的key值发生变化

Vue导航守卫的钩子函数有哪些?⭐⭐⭐⭐⭐
全局守卫

  • router.beforeEach:全局前置守卫,进入路由之前
  • router.beforeResolve:全局解析守卫,在beforeRouteEnter调用之后调用
  • router.afterEach:全局后置钩子,进入路由之后

路由组件内的守卫

  • beforeRouteEnter():进入路由前
  • beforeRouteUpdate():路由复用同一个组件时
  • beforeRouteLeave():离开当前路由时

vue 常见的性能优化⭐⭐⭐⭐⭐

  • spa 使用 keep-alive
  • key 的使用
  • v-if 和v-show
  • v-if 不要和 v-for 一起使用
  • v-for 的优先级要早于 v-if,如果一起使用的话,会先遍历在判断 v-if,会造成性能问题;
  • 使用Object.freeze()方式冻结data中的属性,从而阻止数据劫持
  • 组件销毁的时候会断开所有与实例联系,但是除了addEventListener,所以当一个组件销毁的时候需要手动去removeEventListener
  • 图片懒加载
  • 路由懒加载
  • 防抖节流
  • 长列表固定个数
  • 为减少重新渲染和创建dom节点的时间,采用虚拟dom

vue3 相比于vue2有什么升级⭐⭐⭐⭐

  • 采用 ts 编写
  • composition API
  • 响应式原理使用的 proxy
    ##################美丽的分割线#################

Webpack

webpack常用字段及解释⭐⭐⭐⭐⭐
在这里插入图片描述

##################美丽的分割线#################

css系列面试题

在这里插入图片描述

1、对BFC规范(块级格式化上下文)的理解
BFC 块级格式化上下文 一块独立的区域,有自己的规则,bfc中的元素与外界的元素互不影响

BFC是一块用来独立的布局环境,保护其中内部元素不受外部影响,也不影响外部。

怎么触发BFC

  • float的值left或right
  • overflow的值不为visible(默认)
  • display的值为inline-block、table-cell、table-caption
  • position的值为absolute(绝对定位)或fixed固定定位

规则:

1、BFC的区域不会与float box重叠。
2、BFC是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。
3、计算BFC的高度时,浮动元素也会参与计算。
4、内部的Box会在垂直方向上一个接一个放置。
5、Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠。

BFC的应用
1、可以用来自适应布局
利用BFC的这个原理可以实现两栏布局,左边定宽,右边自适应。不会相互影响,哪怕高度不相等。
给左边盒子加浮动,右边盒子加overflow:hidden;变成BFC,就可以消除外部左边盒子因浮动对他的影响

2、可以清除浮动

一个父元素中的子元素,设置浮动时,父元素没有设置高度,这时子元素脱离文档流,父元素感知不到子元素的高度,造成父元素的塌陷。 这时候给父元素添加overflow:hidden / auto,变成BFC就可以解决这种问题。

3、解决垂直边距重叠
1.父子关系的边距重叠

父子关系,如果子元素设置了外边距,在没有把父元素变成BFC的情况下,父元素也会产生外边距。

解决办法: 是给父元素添加一个 overflow:hidden,这样父元素就变为BFC,不会随子元素产生外边距

2.同级兄弟关系的重叠

同级元素在垂直方向上外边距会出现重叠现象,最后外边距的大小取两者绝对值大的那个

可通过添加一个空元素或伪类元素,设置overflow:hidden;解决

2、什么是渐进增强优雅降级
渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后在针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

3、CSS优化、提高性能的方法有哪些?

  • 避免过度约束
  • 避免后代选择符
  • 避免链式选择符
  • 使用紧凑的语法
  • 避免不必要的命名空间

避免不必要的重复

最好使用表示语义的名字。一个好的类名应该是描述他是什么而不是像什么

避免!important,可以选择其他选择器 尽可能的精简规则,你可以合并不同类里的重复规则

4、CSS特性:继承性,层叠,优先级
1、继承性:子标签会继承父标签的某些样式,如文本颜色和字号。(text- font- color)

2、层叠性:样式冲突,遵循的原则是就近原则。

3、优先级:定义CSS样式时,经常出现两个或更多规则应用在同一元素上,此时,谁的权重高显示谁的样式。

(选择器相同,则执行层叠性;选择器不同,就会出现优先级的问题。)

 !Important > 行内式 > id > 类/伪类/属性 > 标签选择器  >  全局
(对应权重:无穷大∞>1000>100>10>1>0)

5、定位有哪几种?分别举例?Z-index熟悉在使用的时候注意什么 ?
static: 默认值 没有定位,元素出现在正常的流中

relative(相对定位):生成相对定位的元素,相对于其正常(原先本身)位置进行定位

absolute(绝对定位):生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位

fixed(固定定位):生成绝对定位的元素,相对于浏览器窗口进行定位

sticky 粘性定位 当前元素设置了粘性定位,滚动到顶部就会吸附顶部,往下滑还回到原来位置。

z-index规则

1、值可以是正整数、负整数或0,数值越大,盒子越靠上;

2、如果属性值相同,则按照书写顺序,后来居上;

3、数字后面不能加单位。

4、z-index 只能应用于相对定位、绝对定位和固定定位的元素,其他标准流、浮动和静态定位无效

6、页面导入时,使用link和@import有什么区别
页面中使用CSS的方式主要有3种:行内添加定义style属性值,页面头部内嵌调用和外面链接调用,其中外面引用有两种:Link引入和@import导入,两者都是外部引用CSS的方式,但是存在一定的区别:

1、从属关系: link是标签,@import是css提供的.

  1. 加载差异: link: 结构和样式同时加载;而@import 先加载结构,后加载样式

  2. 兼容性:link没有兼容问题,@import不兼容ie5以下的浏览器.

4.可操作性: link可以通过js操作dom插入link标签改变样式,而@import不能

7、简述src和href的区别
src用于替换当前元素 ​

href用于在当前文档和引用资源之间确立联系.

扩展: ​ src是source的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置 ​ href是Hypertext Reference的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接

8、上下margin重合的问题
1、相邻块元素垂直外边距的合并

解决方案:尽量给只给一个盒子添加margin值

2、嵌套块元素垂直外边距的合并(塌陷)

解决方案:

可以为父元素定义上边框。
可以为父元素定义上内边距
可以为父元素添加overflow:hidden。

9、浏览器常见的兼容性问题?
1、不同浏览器margin和padding不同

2、ie6中,父级元素浮动以后,内部元素内容撑不开宽度

3、标签嵌套不规范,如p和h1-h6里面嵌套div

4、ie6小于19px,会当成19px处理,也就元素宽高小于19px的bug

5、图片3像素问题

6、IE8下给图片添加超链接时,图片会有蓝色边框

7、鼠标滑过时,不显示小手

10、li与li之间有看不见的空白间隔是什么原因引起的?有什么解决办法?
1、浏览器的默认行为是把inline元素间的空白字符(空格换行tab)渲染成一个空格

解决方案:

为li设置左浮动

将li写在同一行 中间不要有空格

将ul内font-size:0,但是单独li设置文字大小

将ul的letter-spacing:-8px,但是单独li设置字符间距normal

11、Html5新增的语义化标签。
头部标签:

导航标签:

内容区块表签:

页脚标签:

侧边栏:

页面内独立的内容区域:

12、flex弹性盒布局与传统盒模型布局的区别和优点?以及Flex布局哪些属性失效?
区别:

  1. 普通盒模型中的子元素分配其父元素的空间,而弹性盒模型中的子元素分配其父元素的可用空间。

  2. 普通盒模型主要针对块级元素和行级元素的布局,而弹性盒是建立在弹性流上,也就是元素可以随着可视区域的变化而呈现流式布局。

弹性盒的优点:

能为盒模型提供最大的灵活性,即使是不定宽高的元素依然好用,可以简便、完整、响应式地实现各种页面布局。

传统布局的特点:兼容性好、布局繁琐、局限性,不能在移动端很好的布局

设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效

13、 什么是rem、px、em区别。
rem是一个相对单位,rem的是相对于html元素的字体大小,没有继承性

em是一个相对单位,是相对于父元素字体大小有继承性

px是一个“绝对单位”,就是css中定义的像素,利用px设置字体大小及元素的宽高等,比较稳定和精确。

14、什么是视口
在pc端中,视口指的是在pc端中浏览器的可视区域;

在移动端中,它涉及3个视口:1是布局视口,2是视觉视口,3是理想视口

移动端指的视口就是布局视口

15、什么是媒体查询。
媒体查询是CSS3新语法。

使用媒体查询,可以针对不同的媒体类型定义不同的样式

媒体查询可以针对不同的屏幕尺寸设置不同的样式

当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面

目前针对很多苹果手机、Android手机,平板等设备都用得到多媒体查询

16、响应式布局有哪些实现方式?什么是响应式设计?响应式设计的基本原理是什么?
1.百分比布局,但是无法对字体,边框等比例缩放

2.弹性盒子布局 display:flex

3.rem布局,1rem=html的font-size值的大小

  1. css3媒体查询 @media screen and(max-width: 750px){}

5.vw+vh

6.使用一些框架(bootstrap,vant)

什么是响应式设计:响应式网站设计是一个网站能够兼容多个终端,智能地根据不同设备环境进行相对应的布局

响应式设计的基本原理:基本原理是通过媒体查询检测不同的设备屏幕尺寸设置不同的css样式 页面头部必须有meta声明的

17、什么叫CSS盒模型?有哪几种盒模型?有什么区别?box-sizing属性有什么用?
1、什么是CSS盒模型?

​ 在我们的HTML页面中,每一个元素都可以被看成一个盒子,而这个盒子由:内容(content)、内边距(padding)、 ​ 边框(border)、外边距(margin) 四部分组成.

2、有哪几种盒模型? ​

对于盒模型,分为标准盒模型和怪异盒模型一下两种

标准(W3C)盒模型的范围包括margin、border、padding、content,并且宽高只包含content,不包含其他部分 ​

怪异(IE)盒模型的范围包括margin、border、padding、content,和标准盒模型不同的是,怪异盒模型的宽高包含了padding和 border

box-sizing作用

用来控制元素的盒子模型的解析模式,默认为content-box ​ context-box标准盒模型 ​ border-box怪异盒模型

18、 Doctype作用? 标准模式与兼容模式(兼容模式)如何区分?
文档声明;用于告知浏览器该以何种模式来渲染文档.

严格模式和混杂模式的区别:

严格模式:页面排版及 JS 解析是以该浏览器支持的最高标准来执行

混杂模式:不严格按照标准执行,主要用来兼容旧的浏览器,向后兼容

19、 为什么会出现浮动?浮动会带来哪些问题?清除浮动的方式有哪些?哪种最好?
1、为什么会出现浮动:

由于浮动元素脱离了文档流,所以文档流的块框表现得就像浮动框不存在一样。浮动元素会漂浮在文档流的块框上.

2、浮动带来的问题:

父元素的高度无法被撑开,影响与父元素同级的元素

若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构.

与浮动元素同级的非浮动元素(内联元素)会跟随其后

3、清除浮动的方式:

父级div定义height

结尾处加空div标签clear:both

父级div定义伪类:after、before

父级div定义overflow:hidden

父级div定义overflow:auto。

父级div也浮动,需要定义宽度。

父级div定义display:table。

结尾处加br标签clear:both

比较好的是第3种,无需多余标签,方便维护,通过伪类就可以解决

20、元素的alt和title有什么异同
不同点: 元素的alt是表示图片加载失败显示的文本内容,而title是表示鼠标悬停图片时显示的文本内容.

相同点: 在alt和title同时设置的时候,alt作为图片的替代文字出现,title是图片的解释文字

21、Div+CSS较table相比有什么样的优点?
正常场景一般都适用div+CSS布局,Div+CSS优点:

开发中结构与样式分离,便于后期项目的维护和迭代

代码语义性好

更符合HTML标准规范

SEO友好

table缺点:

太深的嵌套,比如table>tr>td>h3,会导致搜索引擎读取困难,而且,最直接的损失就是大大增加了冗余代码量

灵活性差,比如要将tr设置border等属性,是不行的,得通过td

代码臃肿,当在table中套用table的时候,阅读代码会显得异常混乱

混乱的colspan与rowspan,用来布局时,频繁使用他们会造成整个文档顺序混乱,不够语义化。

22、 ::before和:before有何异同?
单冒号(:)用于CSS3伪类,

双冒号(::)用于CSS3伪元素。伪元素和伪类之所以这么容易混淆,是因为他们的效果类似而且

伪类: 用于已有元素处于某种状态时为其添加对应的样式,这个状态是根据用户行为而动态变化的。

例如: 当用户悬停在指定元素时,可以通过:hover来描述这个元素的状态,虽然它和一般css相似,可以为已有元素添加样式,但是它只有处于DOM树无法描述的状态下才能为元素添加样式,所以称为伪类。

伪元素: 用于创建一些不在DOM树中的元素,并为其添加样式。

例如: 我们可以通过:before来在一个元素之前添加一些文本,并为这些文本添加样式,虽然用户可以看见这些文本,但是它实际上并不在 DOM文档中。

23、什么是回流什么是重绘以及区别?
回流:

当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree.

重绘:

当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘.

区别:

回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流,当页面布局和几何属性改变时就需要回流

24、.简单说一下H5新增了哪些新特性
语义化标签:header、footer、section、nav、aside、article

增强型表单:input 的多个 type calendar、date、time、url、search、tel、file、number 新增表单属性:placehoder、required、min 和 max

音频视频:audio、video

canvas 画布

kan wa si 地理定位(Geolocation)

拖拽释放:拖拽是一种常见的特性,即抓取对象以后拖到另一个位置,在HTML5中,

本地存储: localStorage 没有时间限制的数据存储; sessionStorage, session 的数据存储,当用户关闭浏览器窗口后,

数据会被删除 新事件:onresize、ondrag、onscroll、onmousewheel、onerror、onplay、onpause

WebSocket:建立持久通信协议,新的技术:webworker、websocket、Geolocation

25、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(线性渐变):

eg: background-image: linear-gradient(100deg, #237b9f, #f2febd);

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-size

14、弹性布局:flex

26、浏览器是如何渲染页面的
浏览器将获取的HTML文档解析成DOM树。

处理CSS标记,构成层叠样式表模型CSSOM(CSS Object Model)。

将DOM和CSSOM合并为渲染树(rendering tree),代表一系列将被渲染的对象。

渲染树的每个元素包含的内容都是计算过的,它被称之为布局layout。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。

将渲染树的各个节点绘制到屏幕上,这一步被称为绘制painting。

构建对象模型(DOM,CSSOM)

构建渲染树(RenderTree)

布局

渲染

27、元素居中的方式、以及垂直上下居中
方法一:给父元素设置成弹性盒子,子元素横向居中,纵向居中

方法二:父相子绝后,子部分向上移动本身宽度和高度的一半,也可以用transfrom:translate(-50%,-50%)(最常用方法)

方法三:父相子绝,子元素所有定位为0,margin设置auto自适应

28、两/三栏布局(圣杯双飞翼)
两栏布局,左边定宽,右边自适应

三栏布局、圣杯布局、双飞翼布局

圣杯布局和双飞翼布局是前端工程师需要日常掌握的重要布局方式。两者的功能相同,都是为了实现一个两侧宽度固定,中间宽度自适应的三栏布局。(中间先加载渲染)

  1. 首先要给两侧设置padding预留出相应的空间

  2. 随后分别为三列设置宽度与浮动,同时对footer设置清除浮动

  3. 根据浮动的特性,由于center的宽度为100%,即占据了第一行的所有空间,所以left和right被“挤”到了第二行。

  4. 接下来的工作是将left放置到之前预留出的位置上,这里使用负外边距

  5. 这里使用position: relative和right: 200px将left的位置在原有位置基础上左移200px,以完成left的放

三栏布局两栏布局css代码
29、flex布局属性以及使用场景
Flex 布局,可以简便、完整、响应式地实现各种页面布局,任何一个容器都可以指定为 Flex 布局,行内元素也可以使用 Flex 布局。

我在项目中常用到的有九宫格布局,列表布局等,都会经常用到。

flex的属性:

flex-direction :设置主轴的方向

justify-content :设置主轴上的子元素排列方式

flex-wrap :设置子元素是否换行

align-content :设置侧轴上的子元素排列方式(多行)

align-items :设置侧轴上的子元素排列方式(单行)

flex-flow :复合属性,相当于同时设置了flex-direction和flex-wrap

flex:1;的原理
flex-grow:1;flex-shrink:1;flex-basis:auto; 这三个样式的和写
flex: 1 1 auto; 简写 flex:1;

flex-grow:0; 扩展比率
默认值为0,容器中项目没有占满时,不分配剩余空间。
flex-shrink:1; 收缩比率
默认值为1,容器中项目超出容器大小时,把项目平均压缩到容器内。
flex-basis:auto; 伸缩基准值
默认值为auto,定义容器中项目的占据空间,一般用百分数设值
30、常见的块级、行级、空元素
在CSS中规范规定,每个元素都有display属性,确定该元素的类型,每个元素都有默认的display值,比如div默认display属性值为“block”,成为“块级”元素;span默认display属性值为“inline”,是“行内”元素。

我们在平常的项目中经常使用到的有

· 行内元素有:span a b i img input select strong

· 块级元素有:div p h1-h6 ul table form ul ol li dl dt dd…

· 空元素(没有内容):


31、css hack
概念:CSS hack是通过在CSS样式中加入一些特殊的符号,让不同的浏览器识别不同的符号(什么样的浏览器识别什么样的符号是有标准的,CSS hack 就是让你记住这个标准),以达到应用不同的 CSS 样式的目的

1、 条件hack

条件注释只有在IE浏览器下才能执行,这个代码在非IE浏览下被当做注释视而不见。可以通过IE条件注释载入不同的CSS、JS、HTML和服务器代码等。

2、 选择符Hack

比如IE6能识别 html .class{},IE7能识别+html .class{}

3、属性Hack 比如IE6能识别下划线和星号,IE7能识别星号,但不能识别下划线,而firefox两个都不能认识。

1、写CSS hack需要遵循以下三条原则:

· 有效: 能够通过 Web 标准的验证

· 只针对太古老的/不再开发的/已被抛弃的浏览器, 而不是目前的主流浏览器

· 代码要丑陋。让人记住这是一个不得已而为之的 Hack, 时刻记住要想办法去掉它。现在很多hacks已经抛弃了最初的原则,而滥用hack会导致浏览器更新之后产生更多的兼容性问题。因此,并不推荐使用CSS hack来解决兼容性问题。

32、html和XML
html被称为超文本标记语言, 是一种描述性语言,用html 可以创建能在互联网上传输的信息页,是构成网页文档的主要语言,它是由很多的标签组成

xml 即可扩展标记语言,是Internet环境中跨平台的、依赖于内容的技术,是当前处理结构化文档信息的有力工具,满足了Web内容发布与交换的需要,适合作为各种存储与共享的通用平台。

都可以通过DOM 变成方式来访问。

都可以通过CSS来改变外观。

html和xml 都是标记语言,都是基于文本编辑和修改的。

xml不是要来取代html的,是对html的补充,用来与html协同工作的语言,基于上面这些优势,xml将来成为所有的数据处理和数据传输的常用工具非常可观。

34、毛玻璃效果
background: rgba(244, 243, 244, 0.18);
box-shadow: 0 0.3px 0.7px rgba(0, 0, 0, 0.126),
0 0.9px 1.7px rgba(0, 0, 0, 0.179), 0 1.8px 3.5px rgba(0, 0, 0, 0.224),
0 3.7px 7.3px rgba(0, 0, 0, 0.277), 0 10px 20px rgba(0, 0, 0, 0.4);
backdrop-filter: blur(10px);
35、web worek
新开了一个子线程,而且子线程不受线程的影响

大数据处理,耗费时间较长的操作

36、canvas 常用api有哪些
常用API:

  1. fillRect(x,y,width,height) 实心矩形;
  2. strokeRect(x,y,width,height) 空心矩形;
  3. fillText( “Hello world” , 200 , 200 ) 实心文字;
  4. strokeText( “Hello world” , 200 , 300 ) 空心文字;
    37、语义化的好处
    在我们开发中,语义化让,页面结构更加清晰,便于后期的维护,便于浏览器,搜索引擎解析

理由搜索引擎的爬取,利于seo

38、浏览器兼容性的问题
在不同的浏览器中,浏览器的内核都是不相同的,所以各个浏览器对网页的解析存在一定的差异。

简单来说就是写的代码在各个浏览器上显示不同的效果

解决:

1、css3新属性,加浏览器前缀兼容早期浏览

-moz- 火狐浏览器

-webkit- Safari, 谷歌浏览器等使用Webkit引擎的浏览器

-o- Opera浏览器(早期)

-ms- IE

2、css hack解决浏览器兼容性不同浏览器,识别不同的样式,css hack本身就是处理浏览器兼容的

3、图片默认有间距:

几个img标签放在一起的时候,有些浏览器会有默认的间距,通配符清除间距也不起作用。 可以通过使用float属性为img布局(所有图片左浮)

4、不同浏览器的标签默认的 margin 和 padding 不同

解决办法:可以通过设置全局样式来解决这个问题,这样所有的样式都会重置,初始值都会相同了。

39. 用纯CSS实现三角形的原理是什么?
首先,需要把元素的宽度、高度设为0。然后设置边框样式为透明,代码如下:

​
div{
    
    width: 0;height: 0;border-top: 40px solid transparent;border-left: 40px solid transparent;border-right: 40px solid transparent;border-bottom: 40px solid #ff0000;
}
​
​
2种更简单
​
 div{
    
    width: 0;height: 0;border: 100px solid transparent;border-bottom-color:red;}

40. style标签写在body前和body后有什么区别?
页面加载自上而下 当然是先加载样式.
写在body标签后由于浏览器以逐行方式对HTML文档进行解析,当解析到写在尾部的样式表(外联或写在style标签)会导致浏览器停止之前的渲染,等待加载且解析样式表完成之后重新渲染,在windows的IE下可能会出现FOUC现象(即样式失效导致的页面闪烁问题)​​​​

41. px,em,rem,vw,vh,rpx等单位的特性
px:像素
em:当前元素的字体大小
rem:根元素字体大小
vw:100vw是总宽度
vh:100vh是总高度
rpx:750rpx是总宽度

猜你喜欢

转载自blog.csdn.net/tianlu930/article/details/127322582