前端面试题收集

HTML和CSS

H5的新特性

  • 语义化标签
    • header,头部标签
    • footer,尾部标签
    • article,文章主体标签
    • section,内容块
    • nav,导航栏
    • aside,侧边栏
  • 媒体标签
    • audio,音频标签
    • video,视频标签
  • 地理定位API
  • WebStorage
    • localStorage,本地存储,相比cookie,大很多
    • sessionStorage,会话存储
  • WebSocket,全双工协议,一般用于作为即时通信
  • Canvas绘图

CSS3新增的特性

  • 弹性布局Flex
  • 媒体查询
  • 结构伪类选择器
    • first-child
    • last-child
    • nth-child(n)
  • 伪元素选择器
    • 元素::before
    • 元素::after

盒子、图片水平、垂直居中

  • 使用Flex布局,justify-contentalign-center都设置为center
  • 使用子绝父相,子元素绝对定位,父元素相对定位,子元素top:50%left:50%,让子盒子向右、向下移动父盒子宽高的一半,再通过transform-translate(-50%, -50%),向左、向上移动自身的一半

CSS盒模型

  • 默认CSS盒模型,box-sizing的值是content-box,元素的宽高只是指内容的宽度、高度
  • 怪异盒模型,也叫IE盒模型,box-sizing的值是border-box,元素的宽高,除了包含内容的宽高,还包含内边距和边框

块级元素和行内元素的特点和区别

  • 块级元素
    • 独占一行
    • 可以设置宽高
    • 可以设置内、外边距和边框
  • 行内元素
    • 一行显示多个
    • 宽高由内容撑开
    • 只能设置内边距、边框,设置外边距无效

CSS选择器权重值

  • !important > 行内样式 > id选择器 > 类选择器 > 标签选择器 > 通配符选择器

H5的事件有哪些?

  • input标签
    • input,输入改变事件
    • focus,获取焦点事件
    • blur,失去焦点事件
    • keydown,键盘按键按下事件
    • keyup,键盘按键弹起事件
  • mouseover,鼠标移入事件(mouseover支持冒泡,mouseenter不支持冒泡)
  • mousemove,鼠标移动事件
  • mouseout,鼠标移出事件

H5的input标签的type值有哪些?

  • text,文本框
  • password,密码框
  • radio,单选框
  • checkbox,复选框
  • button,按钮
  • submit,提交按钮
  • date,日期选择
  • color,颜色选择

JavaScript

JS数据类型

  • 基础数据类型
    • 字符串 String
    • 数字 Number
    • 布尔 Boolean
    • undefined 未定义的值
    • null 空值
    • Symbol 标识,Symbol对象永远不相等,创建时传入的名称字符串,只是用来在debugger时用来区分,应用场景是给对象设置独一无二的属性,避免属性被覆盖和把原有属性覆盖
    • BigInt 大整数,拥有比Number类型更大的数值范围
  • 引用数据类型
    • 对象 Object(包含:函数 Function、数组 Array)

回流和重绘

  • 回流:元素的大小、布局发生改变时,浏览器需要进行回流进行调整布局
  • 重绘:元素的颜色、字体等其他外观属性发生改变,浏览器需要进行重绘来更新外观
  • 回流和重绘都有一定的开销,因此应该要避免不必要的回流和重绘,可以通过优化后的CSS选择器,来减少回流的次数。或者使用缓存来避免重复的重绘
  • 可以使用requestAnimationFrame()函数来在浏览器的下一次重绘之前回调,实现特定的业务逻辑,例如可以在更新页面元素的外观时,将多个操作合并为一次重绘,减少重绘的次数

原型和原型链

  • 每个构造函数都有一个prototype属性,指向一个原型对象,原型对象中,一般存放该构造函数的共享方法
  • 每个对象上,都有一个__proto__属性,指向了构造器的原型对象
  • 原型链,对象的成员查找提供的一种机制。当访问一个对象的某个成员时,优先查找对象本身,如果没有则查找该对象的的原型对象(也就是proto属性指向的原型对象),如果也没有找到,则查找原型对象的原型对象,依次类推,直到找到Object为止,也就是为null,就会报错

this指向的问题

  • 在全局中调用函数,this指向window
  • 对象内的this,this指向对象本身
  • 在构造函数中的this,this指向该构造函数准备要构造出来的实例
  • 在事件回调函数中,this为触发该事件的DOM元素
  • 箭头函数中的this,箭头函数没有this,沿用它上一级的作用域的this
  • 可以通过call、apply、bind,改变this的指向

forEach和map的区别

  • 作用不同:forEach是遍历数组,map是映射数组
  • 返回值不同:forEach没有返回值,map有返回值,返回的是映射后的新数组
  • 处理流程不同:forEach是按顺序遍历每个元素,并执行回调函数。map是除了按顺序遍历元素,执行回调函数外,还会把回调函数的返回值存到一个新数组中,并返回

call、bind、apply的区别

  • call、bind、apply都可以改变函数的this指向
  • call和apply,都是改变this指向后,马上调用原函数,区别是函数的参数,call是一个接一个的传入,而apply是将参数放到数组中再传入函数
  • bind是改变完this后,不会立即调用函数,而是返回一个新函数,我们在调用新函数,参数也是一个接一个的传入

浅拷贝和深拷贝

  • 浅拷贝,拷贝基础数据类型是值拷贝,而拷贝引用数据类型时,拷贝的是对象的内存地址,堆内存中依旧只有一个对象,所以原对象和克隆对象的引用类型属性,指向的是同一个内存地址的对象,修改其中一方会互相影响
  • 深拷贝,让引用类型数据的拷贝是完全的复制,在堆内存中是2个对象,修改其中一方不会互相影响
  • 浅拷贝,基础数据类型和引用数据类型,都可以使用...展开运算符来浅拷贝。引用数据,对象可以使用Object.assign(),数组可以使用Array.prototype.concat()
  • 深拷贝,可以使用JSON序列化和反序列化来实现,但会丢失掉undefind、Function类型的属性,并且不能处理环形结构的数据
  • 工作中,一般使用第三方库lodash,该库提供了浅拷贝、深拷贝的方法,并且能支持undefind、Function属性,环形结构的数据

防抖和节流

  • 防抖和节流是常见性能优化手段,可以控制函数的执行频率
  • 防抖是一定时间内,只执行最后一次事件,一般使用延时器实现,每次调用都清除掉上一次的延时器,所以只有当用户停止操作,一定时间后才会执行,例如DOM元素点击事件、输入框自动联想搜索
  • 节流是单位事件内,控制事件以一定频率触发,一般使用延时器实现,控制事件在一个时间范围内,只触发一次,例如在处理窗口大小变化事件、页面滚动事件、音、视频的进度改变事件等时,需要频繁发送请求、读写localStorage

ES6新特性

  • let和const,let拥有块级作用域,不存在变量提升,const是常量,赋值了就不能改变
  • 箭头函数,简化函数声明,箭头函数没有this,沿用上一级作用域的this
  • 模板字符串,比字符串拼接更简洁、更直观
  • 解构赋值,数组解构、对象解构
  • 剩余参数
  • 函数形参默认值
  • 类,引入类的改变,更加容易维护

ES6新增方法

  • 数组
    • find(),查找元素
    • findIndex(),查找元素的下标
    • includes,判断元素是否包含
    • sort,排序
  • 对象
    • Object.keys(),获取对象的所有属性名
    • Object.values(),获取对象的所有属性值
    • Object.assign(),对象浅拷贝

点击穿透现象以及解决方法

  • 点击穿透,指的是点击上层元素,下层元素也响应事件
  • 防止点击穿透:监听点击事件,在回调函数中,阻止默认点击行为
    • event.stopPropagation();
    • event.preventDefault();

如何理解Promise

  • 一套异步编程的解决方案
  • 将异步操作的结果,封装为成功(fulfilled)、失败(rejected)和等待(pending),并且状态一经更改,就不可逆,如网络请求、读取
  • 解决回调函数嵌套地狱问题,提供链式编程来解决回调地狱的问题
  • Promise上有3个静态方法,Promise.all()、Promise.allSettled()、Promise.race()、Promise.any()
    • Promise.all(),需要传入一个数组,存放多个Promise,组合多个Promise为一个Promise,全部Promise都成功,才算成功,但有一个Promise失败,就当全部失败(请求商品三级分类,获取到商品一级分类后,并发请求所有二级分类)
    • Promise.allSettled(),也是传入多个Promise,组合为一个Promise,所有Promise都执行完毕,不管成功还是失败,才会进行回调(多个异步请求,都结束后,关闭Loading圈)
    • Promise.race(),赛跑机制,也是传入多个Promise,组合为一个Promise,但只要第一个Promise成功,就为成功,其他Promise的结果就不管了(并发请求缓存和发出请求,谁先获取到,就用谁的)
    • Promise.any(),同样将多个Promise包装为一个Promise,只要有一个Promise成功,就为成功,全部Promise失败时,才算失败

async和await的理解

  • async和await是Promise的语法糖,async用于修饰方法,代表是异步方法,await是阻塞等待Promise的成功结果,如果失败会抛出异常,要使用try-catch进行捕获处理
  • async和await,将异步代码写法转变回同步写法,相比Promise更加直观

sessionStorage和localStorage的区别

  • sessionStorage和localStorage都是用来存储数据到本地,存储大小大概有5M左右,而Cookie只能存储4k的大小
  • sessionStorage在浏览器关闭后,自动清除。而localStorage是永久持久化,除非用户手动删除
  • localStorage的存储容量,一般比sessionStorage大,不同浏览器可能有差异

rem和em的区别

  • rem和em都是字体大小的单位,但计算方式不同
  • rem是相对于html根标签的font-size字体大小的比例计算
  • em是相对于父元素的字体大小的计算

响应式布局

  • 响应式布局,根据用户的设备,手机、平板、PC等不同尺寸的设备,进行自适应,都能有良好的显示效果
  • 常见的响应式布局方式
    • 使用流式布局,用百分比设置元素的宽高,让元素在不同尺寸的设备上自动调整大小
    • 使用媒体查询,定义不同尺寸下元素的尺寸和样式,动态应用不同的样式
    • 使用Flex布局,让元素在一个容器中按照一定的规则进行布局

视频控件

  • 视频控件,通常使用HTML5的video标签
  • 使用时,需要指定视频的地址、视频的宽高、是否自动播放
  • 可以控制播放、暂停、快进、快退

什么是同源?

  • 协议、域名(IP)、端口号,3者都完全相同,才为同源
  • 3者有一部分不一样,都为不同源
  • 不同源时,发送ajax请求,产生跨域,请求会被浏览器拦截

为什么会跨域?

  • 是浏览器的一种同源安全手段
    • 浏览器要求网页地址和请求地址,3部分都必须相同,否则就会产生跨域
    • 协议相同,例如http、https
    • 主机相同,域名、IP地址
    • 端口号相同
  • 以下3个标签,不受到跨域限制
    • img标签
    • link标签
    • script标签

跨域怎么处理?

  • 使用代理服务,在本地搭建一个代理服务器,如Nginx,它负责转发请求,解决跨域问题
  • 使用JSONP,通过动态插入script标签的方式事件跨域访问,只支持GET请求,是一种很老的方式
  • 通过服务端配置CROS,CROS是一种跨域资源共享方式,服务端配置HTTP头信息,让浏览器允许跨域

ES6中的var、let、const的区别

  • var,在ES6之前使用,存在变量提升、没有块级作用域等问题
  • let,用于替代var,没有变量提升,有块级作用域
  • const,用于定义常量,赋值后就不能修改

怎么改变this指向

  • 通过call、apply、bind来改变函数的this指向
  • 如果想沿用上一级的this,可以使用箭头函数,或者在函数调用前先用一个变量that保存this

for of 和 for in 的区别

  • for-of,遍历数组的值
  • for-in,遍历对象的属性名

什么是同步和异步

  • JavaScript是单线程语言,同一时间只能执行一个任务,如果同步执行一个耗时任务,会阻塞执行,导致界面卡顿
  • 因此出现了异步编程,通过将耗时任务交给浏览器或操作系统去执行,任务结果通过回调函数或事件机制,回调通知或事件,通知主线程,不会阻塞执行

宏任务和微任务

  • 宏任务和微任务,都用于处理耗时任务,有单独的任务队列来存放任务
  • 宏任务,例如交互事件、定时器、延时器、script标签的解析
  • 微任务,Promise.then()
  • 优先级:当队列,存在宏任务和微任务时,优先执行完微任务,再执行宏任务
  • 执行流程,JS解析器运行时,遇到同步代码,直接交给执行栈直接执行,如果遇到宏任务,则放入到宏任务队列,遇到微任务则放入到微任务队列。当执行完执行栈中的同步任务后,就会去微任务瞄一眼,如果有微任务则将微任务挪到执行栈,在执行栈中执行微任务,执行完所有的微任务,则再去宏任务队列瞄一眼。如有宏任务,则将宏任务挪到执行栈,执行宏任务。执行完一个宏任务后,又会去微任务瞄一眼,发现有微任务就执行。(总之,微任务的优先级比宏任务高,执行完一次宏任务都要去将微任务队列中,执行完所有的微任务,再执行下一个宏任务,这样设计,就让微任务有了插队的可能)这种不断往复的执行的流程,就是事件循环EventLooper

什么是闭包

  • 闭包,具体表现形式:外层函数嵌套内层函数,内层函数使用外层函数的变量,外层函数返回内层函数
  • 作用:保护私有数据,防止全局变量污染
  • 问题:闭包会导致内存泄漏,需要手动将返回的内层函数的引用设置为null,置空引用,来防止内存泄漏

介绍一下作用域

  • 全局作用域,在全局作用域下声明的变量和函数,在任何位置都能访问
  • 局部作用域,在函数内或块级作用域中可访问,出了函数作用域或块级作用域就访问不到了

深拷贝,为什么能做到拷贝后互不影响

  • 因为深拷贝是将引用数据类型的属性,进行完整拷贝,而不是值的拷贝,也就是不是拷贝对象内存地址,是在堆内存中真的创建了一个新的对象

说一下事件委托的应用场景

  • 事件委托的原理是事件冒泡,如果没有事件冒泡,就无法实现事件委托
  • 事件委托一般用于给动态生成的元素,绑定事件,例如列表或表格的列表项、表格项,绑定点击事件
  • 给父元素绑定一个事件处理函数,不需要给所有子元素绑定,能节省内存,提高性能

什么是纯函数

  • 纯函数,只依赖传入的形参,不依赖函数外部的变量,传入相同的形参,总能得到相同的结果
  • 纯函数没有副作用
  • 如果传入相同的形参,得到不同的结果,那么就不是纯函数

数组去重

  • Array.from() + new Set()
  • 拓展运算符 + 新数组 + new Set()
  • for循环 + indexOf() + 新数组push()
  • forEach循环 + indexOf() + 新数组push()
  • forEash循环 + includes() + 新数组push()

什么是递归

  • 函数调用自身,就叫递归
  • 必须有终止条件,否则死循环会栈溢出

封装axios的步骤

  • 创建一个request.js,引入axios
  • 使用axios.create()创建axios的实例,配置基地址和超时时间
  • 配置请求拦截器和响应拦截器,然后默认导出
  • 一般在请求拦截器中,添加token到请求头
  • 一般在响应拦截器中,判断服务端返回的状态码,例如判断登录状态失效,就跳转到登录页,或者解构固定的服务端响应解构数据,result.data.data

JS怎么判断数据的类型

  • 使用typeof,只适用于基础数据类型
    • 基础数据类型,判断不了null,判断null会返回object
    • 判断NaN,判断的是number
    • 引用数据类型,只能判断Function,数组和其他都返回object
  • 使用instanceof,只能用于判断引用数据类型,不能判断基础数据类型
  • 使用Object.prototype.toString.call(),该方式兼容性最好,既能判断基础数据类型,也能判断引用数据类型

图片懒加载的底层原理

  • img标签的src属性,设置为空字符串,将真实的图片地址放在一个自定义属性,例如data-origin中
  • 监听页面滚动事件,判断img标签是否可见,可见再把自定义属性中的值,设置到src属性中

Git

Git的常用命令

  • git add,添加到暂存区
  • git commit,提交代码到版本库
  • git push ,推送代码到远程仓库
  • git pull,拉取代码
  • git clone,克隆代码
  • git checkout,签出代码
  • git checkout -b,签出或创建新分支
  • git merge,合并分支

Webpack

Webpack的版本号

  • 2018,webpack4,可零配置运行,打包(构建)速度提高80%
  • 2020,webpack5,打包速度更快,开启文件缓存,明显提升打包速度

HTTP协议

HTTP有了解过吗?

  • HTTP协议,基于TCP\IP,是基于请求、响应模型,一个无状态的协议
  • HTTP协议,请求报文分为请求行、请求头、请求体。响应分为响应行(状态行)、响应头、响应体
  • HTTP协议可传输超文本HTML,也可以传输XML、JSON,目前常用是JSON
  • 常用请求方式:GET获取、POST提交、PUT更新、DELETE删除
  • 常见状态码:200成功,304读取缓存、401没有登录、403权限不足、500服务器内部错误

HTTP不写端口时,默认是多少

  • HTTP默认端口为80
  • HTTP默认端口为443

HTTP有哪些请求方法

  • GET 获取
  • POST 提交
  • PUT 更新
  • DELETE 删除

HTTP常用状态码

  • 200成功
  • 304读取缓存
  • 401没有登录
  • 403权限不足
  • 500服务器内部错误

HTTP的三次握手过程

HTTP的四次挥手过程

说一下在页面中输入URL到加载完成的过程

HTTP和HTTPS的区别

  • 2者都是传输协议
  • 安全性:HTTPS在传输数据的基础上,增加了加密,防止数据不被窃取和修改
  • 证书,HTTP要求服务端安装SSL证书,验证服务端的身份,确保用户访问的是真实的网站
  • 端口号:HTTP的默认端口号是80,HTTPS的默认端口是443
  • HTTP协议的URL以http开头,HTTPS协议的URL以https开头

MVVM

说一下你对MVVM的理解

  • M是Model模型,是应用程序中的数据和逻辑
  • V是View视图,是用户看见的界面
  • VM是视图模型,数据驱动视图的框架
  • 优点:将视图和业务逻辑分离,以数据驱动视图变化,易维护和拓展

Vue

Vue的插槽

  • 默认插槽
    • 组件中只有一个插槽,父组件只能传递一个内容给子组件,其实默认插槽也是具名插槽,只是名字叫default
  • 具名插槽
    • 子组件可以有多个插槽,父组件可以传入多个内容给子组件,子组件需要指定插槽的名字
    • 作用域插槽,在具名插槽的基础上,让子组件传出数据给父组件,例如表格项-按钮组件,点击时,需要将当前项的数据,传出给表格父组件使用,例如删除数据、显示表格项详情等

Vue的data,为什么一定是要一个函数

  • 因为组件复用时,每个组件都应该有自己的状态,如果data不是一个函数返回的新对象,而是同一个对象,则每个组件都公用一个数据对象,就会导致组件的状态混乱,互相影响

Vue双向绑定的原理

  • 双向绑定的原理是数据劫持和观察者模式来实现的,大概分为2步:
    • 通过Object.defineProperty来劫持数据,收集依赖
    • 当数据变更时,通知依赖去响应视图的变化
  • 当Vue实例被创建时,会在内部遍历所有数据,并使用Object.defineProperty来对每个属性添加getter和setter。这样,当数据被改变时,Vue就可以捕获数据,并通知观察者,重新渲染页面

使用Vuex的完整步骤

  • 导入vuex依赖
  • 创建store.js文件,创建vuex实例,并通过Vue.use(),使用Vuex插件,再挂载到Vue实例上
  • 创建module文件夹,配置模块的store.js
  • 配置state、mutations、actions、getters

v-model的实现原理

  • v-model,其实是一种语法糖,作用是将数据和表单元素进行双向绑定,数据改变时更新视图,表单元素内容更新时,更新数据
  • 数据改变时,更新视图,其实是v-bind
  • 视图内容改变时,更新数据,其实是v-on
  • 例如input标签使用v-model,就是v-bind:value="",v-on:onclick="",也就是:value和@click

什么是单页面应用

  • 单页面应用,也就是在HTML页面加载所有页面,通过JS切换视图达到切换页面的效果,而不需要像多页面应用需要重新发起请求由服务端进行渲染
  • 单页面应用的性能高,切换页面时,一些通用的头部、尾部等通用样式,不需要重复发出请求来获取,减轻服务端的负载
  • 单页面应用的SEO比较差,因为视图都是通过JS动态渲染的,搜索引擎爬虫无法运行JS脚本,只能抓取HTML里面的标签和文本来决定这个站点的价值。
  • 单页面应用可以通过服务端渲染SSR来解决单页面应用SEO差的问题

如何解决单页面应用SEO难度大的问题

  • 单页面应用可以通过服务端渲染SSR来解决单页面应用SEO差的问题

谈谈你对vue的理解

  • Vue,一个渐近式的UI视图框架,理念是使用数据驱动视图,不需要开发者手动操作DOM,让开发者更加关注数据和具体业务

Vue中如何监听路由信息的改变

  • 通过watch监听器路由对象的变化
  • 使用路由提供的回调钩子函数

nextTick的理解

  • 当我们修改响应式变量时,并不会马上就根据变量,重新渲染DOM,而是异步更新
  • 因为响应式变量可能在短时间内,频繁修改,如果同步渲染DOM,模板比较复杂时,会导致卡顿,产生性能问题
  • 由于Vue的DOM更新是异步的,我们直接在修改响应式变量后,就直接通过ref操作DOM元素,会发现获取不到,而Vue提供了nextTick函数,该函数会在异步更新DOM完毕后回调,我们在这个回调中再通过ref操作DOM就肯定能获取到DOM元素

Vue中对象添加新属性,界面不自动刷新,怎么解决

  • 使用Vue实例的$set函数,this.$set(attr, index, val);,主动通知Vue劫持新的属性
  • 使用Vue包装过的数组方法,例如splice,arr.splice(index, 1, value);
  • 使用$fourceUpdate强制刷新
  • 使用中转变量,将新变量赋值原有响应式变量

v-for中的key

  • key是Vue框架内部使用的,用于Vue框架复用视图时使用,不会对我们业务逻辑产生影响
  • 如果不使用key,会导致Vue无法精确复用视图,例如ul中有多个li,当我们删除第一个li时,Vue会删除最后的一个li,然后将内容网上挪,如果第一个li中有一个背景色,就会发现我们虽然删除了数组的第一个元素,但Vue并不是相应的删除第一个li标签,就会导致视图复用出现问题
  • 而设置了key,让每个li标签都有一个唯一标识,就能让Vue知道我们删除的数组数据对应哪个视图,就能删对li标签了

说一下Vue组件通讯

  • 父、子组件传参
  • 父传子:props传参
  • 子传父:$emit(),发送自定义事件
  • 子孙通信:provide和inject
  • 跨组件通信:EventBus、Vuex

说几个Vue的指令

  • v-text,相当于innerText
  • v-html,相当于innerHTML
  • v-if、v-else-if、v-else,相当于if、else if和else,条件渲染
  • v-show,和v-if效果类似,都是显示隐藏某个元素,但v-if是直接将DOM元素直接从DOM树移除,v-show是通过切换元素的CSS-display属性来实现显示隐藏
  • v-bind,动态绑定属性,可以简写为:号
  • :class,动态绑定class,当某个条件为true时,添加指定的class类名给DOM元素,语法::class="{类名: 条件表达式}",或者::class=[类名1, 类名2, 类名3]
  • :style,动态样式,当只想改变DOM元素的某个样式属性,而不想使用类名时使用,语法::style="{color: activeColor, backgroundColor: bgColor}"
  • v-model,视图和数据双向绑定,是:value和@input的合写,要求子组件必须有一个名叫value的属性名,当子组件经过一些UI操作后,内容发生变化后,发出的自定义事件的名称必须叫input
  • sync修饰符,v-model要求子组件只能有一个属性可以进行双向绑定,并且子组件的属性名和发出的事件名都是固定的,不能修改。当子组件有多个属性都可以提供双向绑定时,就可以使用sync修饰符,它可以自定义子组件的属性名和发出的事件名,语法:v-bind:属性名.sync="值",发出的事件的格式:update:属性名="新值"

Vue的路由懒加载

  • 路由懒加载,可以让组件在路由被访问时,才加载对应的组件,也就是异步组件,避免一进入页面,就直接加载所有的路由组件,解决单页面应用首屏加载慢的问题

Vuex的核心属性

  • state,状态,也就是数据
  • mutations,同步修改state的函数
  • actions,异步修改state的函数(异步后调用mutation的函数来实现修改)
  • getters,计算state为一个新的state,或者合并多个state,相当于计算属性

Vue的路由模式

  • hash模式,使用H5的新特性,URL地址#/后路径变化时,浏览器不会发出请求,而是触发hashchange事件,但有#/,URL地址比较难看
  • history模式,浏览器一直都支持的模式,URL路径变化时,浏览器会发出请求,要求服务端返回新的页面,但单页面应用只有一个页面,URL的地址都没有对应的页面,只是用于VueRouter监听,切换对应的组件,从而显示不同的页面,该方式需要服务端进行配置,否则会出现404

Vue路由之间的跳转方式

  • 有4种方式
  • 声明式导航,也就是使用标签来跳转
    • 使用a标签,设置href属性为目标页面的路由路径,主要必须加上#/
    • 使用router-link标签,设置to属性为目标页面的路由路径,不需要加#/,点击发起路由跳转
  • 编程式导航,也就是使用使用JS来跳转
  • 使用this.$router.push,发起路由跳转
  • 使用this.$router.replace
  • 使用go(N),N为数字,正数则前进页面、负数则回退页面

Vue如何封装组件

  • 创建一个.vue的单文件
  • 通过props声明组件需要的参数
  • 组件进行一些UI操作后,使用$emit发送自定义事件,通知父组件更新数据
  • 父子组件通信,要遵守单向数据流,父组件传参给子组件,子组件使用事件通知父元素修改数据,不能子元素修改父元素的数据,要遵守数据谁持有,谁修改

v-show和v-if的区别

  • v-show,使用元素的display属性,设置为none来实现隐藏元素
  • v-if,条件渲染,将元素直接在DOM树中移除,来实现隐藏元素
  • 如果需要频繁显示、隐藏,一般使用v-show,因为v-if会频繁创建、销毁元素,对性能有影响
  • 需要身份校验后,根据角色才显示某些按钮,使用v-if,可以避免敏感数据的隐藏

Vue中v-for和v-if,为什么不能一起使用

  • 在Vue2中,v-for的优先级高于v-if,所以当2个指令放在同一个标签时,就是每次循环都要先判断,再决定显示或隐藏,会消耗很大的性能
  • 解决方案是多套一层div,将v-if放在外层,v-for放在里层,直接进行判断,为true再决定是否开始循环
  • Vue3解决了这个问题,将v-if优先级高于v-for

Vue的生命周期

  • beforeCreate,创建Vue实例前回调
  • created,创建Vue实例后回调,此时vue实例身上的data数据还没有处理成响应式变量,所以不能在这里操作data中的数据,一般在这个回调函数中,发出接口请求
  • beforeMount,挂载前回调,此时页面还是模板内容,Vue实例的data中的数据,还没有填充到视图,此时还不能操作DOM元素,因为挂载数据的时候,是重新替换视图标签,如果在此时查找DOM元素,并不是最终的DOM树
  • mounted,挂载后回调,此时data的数据已经渲染到视图,可以进行查找DOM元素,操作DOM元素等,或者使用Vue提供的refs获取DOM元素
  • beforeUpdate,Vue实例的响应式变量准备更新前回调,此时去拿响应式变量的值,还是旧值
  • updated,响应式变量更新后,此时获取data中的数据是新值,注意建议不要在该回调中更新响应式变量,容易更新后,又调用updated,产生递归,出现栈溢出
  • beforeDestroy,准备销毁前回调,一般在该回调中清除定时器、延时器、取消Ajax请求等异步任务
  • destroyed,销毁后回调,在该回调中,Vue会取消data中数据的响应式,解绑DOM元素的事件监听,所以不要在该回调中,再操作响应式变量,是不会更新DOM的
  • 如果组件被keep-alive标签组件包裹,则该进入、离开该组件时,不会销毁组件,所以上面的生命周期不会重复调用,而是会调用activateddeactivatedactivated是组件被激活,也就是页面可见,而deactivated是页面失活

Vue-Router的钩子函数

  • beforeEach,前置守卫,可以进行私有页面的权限判断,例如token为空,拦截掉跳转,跳转到登录页,强制用户登录

Vue-Router的传参方式有哪些

  • 查询参数跳转传参
  • 动态路由跳转传参

Vue-Router的前置守卫

  • 在路由跳转前,执行前置守卫,可以进行私有页面的权限校验,例如判断token是否为空,为空则拦截跳转,跳转到登录页

Vue计算属性与watch的区别

  • computed计算属性,每次获取计算属性时,如果计算属性的依赖项没有发生变化,计算属性会使用之前的缓存值,而不是每次都重新计算,提升性能
  • watch侦听器(监听器),监听属性值的变化,当变化时,执行handler回调,适用于数据变化时,更新DOM元素
  • immediate属性,是否在第一次渲染的时候就执行回调函数
  • deep属性,如果需要监听的变量是引用数据类型,要监听它内部的属性变化,就要将该属性设置为true

keep-alive,使用页面跳转后返回数据,原数据还在吗?

  • 使用keep-alive标签组件,包裹router-view路由视图组件,能让页面跳转,组件不被销毁,组件的data数据,自然就还在

使用Vuex时,怎么实现数据的持久化

  • 在vuex的mutation函数中,调用本地存储进行数据持久化,并在state初始化时从本地存储中获取数据来初始化state

前置守卫的应用场景

  • 私有页面的权限拦截,在前置守卫回调中,判断Token是否为空,不为空或白名单页面(注册、登录等),才放行,否则拦截,直接跳转到登录

优化

页面优化思路有哪些?

  • 路由懒加载
  • 图片懒加载
  • 排除掉Vue、React、ElementUI等常用的库,使用CDN地址,加速访问
  • 组件按需引入
  • 小图片使用base64内联到img标签
  • 纯色图标使用字体图标或者SVG图片,彩色图片使用精灵图
  • 使用GZIP压缩
  • 使用webpack的preview --report,查看包体积占用分析

项目的打包优化

  • 路由懒加载,让目标路由页面组件,在第一次加载时,才创建,避免单页面应用首屏加载慢的问题

Axios拦截器

  • 请求拦截器
    • 请求前,显示Loading的Toast提示,添加token到请求头
    • 请求后,隐藏Toast提示
  • 响应拦截器
    • 响应成功,对数据进行数据剥离,例如减少一层data(axios会给数据加多了一层data)
    • 响应失败,根据服务端的响应错误信息,弹出错误的Toast提示

Token失效的处理办法

  • 在axios的响应拦截器中,判断HTTP状态码,如果为和服务端约定的状态码,如约定是401,则为token过期,前端删除本地存储的过期token,弹出Toast提示用户当前登录状态已过期,再跳转到登录页面

UniApp

UniApp开发多端发布,要考虑哪些方面?

  • 多端兼容性问题(CSS、JS)
  • 不同小程序的配置问题

UniApp开发一般适合什么项目?

  • 跨端应用,H5、小程序、App

UniApp中父组件、子组件、兄弟组件的数据交互

  • 父传子,props
  • 子传父,$emit
  • 兄弟组件,provide和inject、EventBus、Vuex、Pinia

微信小程序

小程序扫码进来,一条链接如何获取参数

  • 在跳转的页面的onLoad中,解析传过来的options对象,获取跳转参数

小程序的生命周期

  • 生命周期分为3种,分别为:应用生命周期、页面生命周期、组件生命周期
  • 应用生命周期
    • onLaunch,小程序初始化,只会调用一次,一般在这里获取跳转参数、场景值、判断是否有新版本更新
    • onShow,小程序切换到前台时回调
    • onHide,小程序切换到后台时回调
    • onError,小程序发生错误时回调
  • 页面生命周期
    • onLoad,页面加载完成时回调,一般在这里获取跳转参数和发起网络请求
    • onShow,页面可见时回调
    • onReady,页面初次渲染完成时回调,只会调用一次
    • onHide,页面不可见时回调
    • onUnload,页面被卸载时回调,一般在这里清除定时器、解绑事件监听
  • 组件生命周期
    • created,组件创建时回调
    • attached,组件被挂载到DOM时回调
    • detached,组件被卸载时回调

小程序的跳转方式

  • navigationTo,保留当前页面,跳转到新页面
  • redirectTo,销毁当前页面,跳转到新页面
  • switchTab,跳转到TabBar页面,并销毁TabBar页以上的页面
  • reLaunch,关闭应用的所有页面,再跳转到一个新页面
  • navigateBack,关闭当前页面,回退到上一个页面

小程序的数据绑定和Vue的数据绑定有什么区别?

  • 小程序通过setData()函数,来通知渲染层,更新视图,setData()函数是同步的,应该避免频繁调用
  • 小程序也提供了简易的双向绑定,但是不支持嵌套对象,Vue支持嵌套对象
  • Vue和小程序都支持插值表达式,都是{{}},只是在单向绑定时,Vue的v-bind,不能用{{}}插值表达式,小程序则可以
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容