前两篇详细讲解了 HTML 、CSS 、JavaScript 、计算机网络知识、React 、git 、webpack等方面的内容,本文将详细讲解 有关 vue 等内容,预祝各位成功上岸!
1、说一下 vue 的两个特性
(1)数据驱动视图:
数据的变化会驱动视图自动更新;
好处:程序员只管把数据维护好,那么页面结构会被 vue 自动渲染出来!
(2)双向数据绑定:
在网页中,form 表单负责采集数据,Ajax 负责提交数据
- js 数据的变化,会被自动渲染到页面上;
- 页面上表单采集的数据发生变化的时候,会被 vue 自动获取到,并更新到 js 数据中;
2、谈一谈对 MVVM 的理解?
MVVM 是 Model-View-ViewModel 的缩写。MVVM 是一种设计思想。
(Mode 数据源、View 视图、ViewModel 就是 vue 得实例)
- 数据驱动视图和双向数据绑定的底层原理是 MVVM
- Model 表示当前页面渲染时所依赖的数据源。
- View 表示当前页面所渲染的 DOM 结构。
- ViewModel 表示 vue 的实例,它是 MVVM 的核心,把当前页面的数据源和页面结构连在了一起。
在 MVVM 架构下,View 和 Model 之间并没有直接的联系,而是通过 ViewModel 进行双向交互, 因此 View 数据的变化会自动同步到 Model 中,而 Model 数据的变化也会立即反应到 View 上,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作 DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
优点:
- 低耦合 :View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 可重用性 : 可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
- 独立开发 : 开发人员可以专注于业务逻辑和数据的开发,设计人员可以专注于页面的设计。
3、vue 组件生命周期
生命周期总共分为四个阶段:创建(前/后), 挂载(前/后),更新(前/后),销毁(前/后);
- beforeCreate,创建之前 ,在当前阶段 data、methods、***puted 以及 watch 上的数据和方法都不能被访问。
- created:创建之后【重要】,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发 updated 函数。可以在这个生命周期中调接口获取数据;在当前阶段无法与 DOM 进行交互,如果非要想,可以通过 vm.$nextTick 来访问 DOM 。
- beforeMount:挂载之前,在这之前 template 模板已导入渲染函数编译。而当前阶段虚拟 DOM 已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发 updated。
- mounted:挂载成功后【重要】,在当前阶段,真实的 DOM 挂载完毕,数据完成双向绑定,可以访问到 DOM 节点,使用 $refs 属性对 DOM 进行操作。
- beforeUpdate:更新之前,也就是响应式数据发生更新,虚拟 DOM 重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。
- updated:更新完成后,当前阶段组件 DOM 已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。
- beforeDestroy:销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。
- destroyed:销毁之后,这个时候只剩下了 DOM 空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁;
注意:
1、除了更新阶段的两个钩子函数,其他的都只执行一次;
2、第一次页面加载会触发的 4 个钩子函数分别是:beforeCreate、created、beforeMount、mounted;
3、DOM 渲染是在 mounted 阶段完成的,此阶段真实的 DOM 挂载完毕,数据完成双向绑定,可以访问到 DOM 节点。
4、多组件(父子组件)中生命周期的调用顺序:
组件的调用顺序都是先父后子;渲染完成的顺序是先子后父;组件的销毁操作是先父后子;销毁完成的顺序是先子后父。
加载渲染过程:父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount- >子mounted->父mounted
子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程:父 beforeUpdate -> 父 updated
销毁过程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
5、created 和 mounted 的区别:
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
4、vue 框架实现数据双向绑定的原理是什么?
vue2 Object.defineProperty 实现的,为对象定义属性的时候注册 setter 和 getter 方法,在这两个方法上进行监听,对属性的改变或者获取的时候同时进行页面更新。
v-model 用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
v-bind 绑定一个 value 属性;v-on 指令给当前元素绑定 input 事件。
vue3 中使用的是 proxy 代理;所以 vue 项目不能在 ie8 以下的浏览器使用。因为不支持
5、vue 组件传参
1、父传子使用props属性
子组件在props中创建一个属性,用来接收父组件传过来的值;在父组件中注册子组件;
在子组件标签中添加子组件props中创建的属性;把需要传给子组件的值赋给该属性
2、子传父使用事件派发
子组件中需要以某种方式(如点击事件)的方法来触发一个自定义的事件;将需要传的值作为$emit的第二个参数,该值将作为实参传给响应事件的方法;在父组件中注册子组件并在子组件标签上绑定自定义事件的监听。
3、非相关组件使用事件总线或者vuex
什么是事件总线:我们在vue项目中定义一个空白的vue实例,所有的事件派发和监听都在这个空白的vue实例上进行
$emit事件派发$on事件监听
4、vue3中实现跨组件传参使用provider和inject
6、 组件传参值改变的问题
父子组件之间父子组件之间,当传值为object类型时,传值之后数据源会被改变,最好的解决办法是:传值的时候不要直接传数据源,而且经过使用深拷贝和浅拷贝或者定义新变量等。
data 是一个 function,可以保证每一个组件中的数据是一个唯一的实例。可以保证所有的组件在复用的时候互不影响;
7、vuex 状态管理
是 vue 中的状态管理插件,主要用来做数据共享的;
- - state 存储数据
- - actions 处理异步操作
- - mutations 用来改变数据,所有的数据改变都在这里进行。每一次的数据改变都会被开发者工具记录下来
- - modules 模块化拆分
- - getters 计算属性
8、actions 中也能改变数据,为什么不建议这样做?
因为每一次的数据改变需要可以被追踪到,但是 action 中改变的数据是没有办法被追踪的;
在 vuex 中的数据流向:组件中通过 disptatch 派发一个 action,在 action 中调接口获取数据,获取数据成功之后提交(***mit)一个 mutation 改变数据,数据改变之后组件重新更新;
如果不牵涉异步操作,可以在组件中 ***mit 提交一个 mutation 直接改变数据
9、vue 中如何保证页面切换之后数据还在?
比如列表页跳转详情页之后,返回列表的时候以前加载的数据还在;
keep-alive 可以对组件做缓存;或者使用 vuex 实现数据共享;以上两者实现的都是数据的临时存储,如果页面刷新了,数据还会消失。为了解决刷新之后数据不消失的问题,可以使用 localstorage 本地存储,或者刷新之后重新加载数据的方案实现;
10、Vuex 可以直接修改 state 的值吗?
可以直接修改,但是极其不推荐,state的修改必须在mutation来修改,否则无法被devtool所监测,无法监测数据的来源,无法保存状态快照,也就无法实现时间漫游/回滚之类的操作。
11、vuex 和 redux 有什么区别?
vuex 只能在 vue 中使用;redux 可以在任何一个框架中使用;它们两个都是基于单向数据流的;
12. vuex 是什么?怎么使用它?什么场景下我们会使用到 vuex
vuex 是什么?
vuex 是一个专为 Vue 应用程序开发的状态管理器,采用集中式存储管理应用的所有组件的状态。每一个 vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着应用中大部分的状态 (state)。
为什么需要 vuex?
由于组件只维护自身的状态(data),组件创建时或者路由切换时,组件会被初始化,从而导致 data 也随之销毁。
使用方法:
在 main.js 引入 store,注入。只用来读取的状态集中放在 store 中, 改变状态的方式是提交 mutations,这是个同步的事物,异步逻辑应该封装在 action 中。
什么场景下会使用到 vuex?
如果是 vue 的小型应用,那么没有必要使用 vuex,这个时候使用 vuex 反而会带来负担。组件之间的状态传递使用 props、自定义事件来传递即可。
但是如果涉及到 vue 的大型应用,那么就需要类似于 vuex 这样的集中管理状态的状态机来管理所有组件的状态。例如登录状态、加入购物车、音乐播放等,总之只要是开发 vue 的大型应用,都推荐使用 vuex 来管理所有组件状态。
13. 说一下 v-for 与 v-show 的区别
共同点:都是动态显示 DOM 元素
区别点:
手段:
v-if 是动态的向 DOM 树内添加或者删除 DOM 元素;
v-show 是通过设置 DOM 元素的 display 样式属性控制显隐;
编译过程:
v-if 切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;
v-show 只是简单的基于 css 切换;
编译条件:
v-if 是惰性的,如果初始条件为假,则什么也不做。只有在条件第一次变为真时才开始局部编译;
v-show 是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且 DOM 元素保留
性能消耗:
v-if 有更高的切换消耗;
v-show 有更高的初始渲染消耗;
使用场景:
v-if 适合运营条件不大可能改变;
v-show 适合频繁切换;
14、路由拦截和路由守卫
beforeEach 路由前置守卫,可以用来做登录判断
- vue 路由以及路由嵌套和路由守卫
路由嵌套使用 children 属性实现
beforeEach,在所有的页面跳转之前执行,可以做登陆判断
15、在项目中用户的登陆判断是怎么实现的?
我们会把用户的登陆信息存储在本地,在每一次路由跳转之前判断是否存的有登陆信息。如果有那表示登陆过了,同时我们还会做网络请求全局拦截,我们的登陆信息传递给服务器的时候,服务器接口会验证用户的登陆数据是否有效,根据验证结果返回我们对应的状态码。我们会更具返回的状态码做不同的处理提示
16、项目打包优化
- - 路由懒加载
- - 使用 cdn 的方式引入外部资源,减少打包之后的文件大小,需要修改 vue 项目的配置文件
- - 把自己项目的资源文件放在 cdn 服务器上
- - 减少首页网络请求次数
17、vue 项目如何做性能优化,或者解决首页白屏问题
1. 对资源文件进行压缩合并,使用 cdn 的方式引入资源
2. 使用路由懒加载的方式加载路由对应的组件,初始化的时候第一次不加载所有的路由文件,当访问对应页面的时候再加载
3. 使用 cdn 的方式引入外部资源,把我们项目中的一些第三方插件使用外部引入的方式进行引入。不打包在生成的 js 文件中
4.v-for 循环的时候加上 key
5.使用路由懒加载
推荐观看:vue打包优化_哔哩哔哩_bilibili
18、watch 和计算属性以及 method 方法调用的区别
- - watch 表示监听一个数据的改变,数据改变之后调用一个回调函数;
- - ***puted,表示依赖的数据改变之后重新计算一个结果。计算属性具有缓存功能,依赖数据不改变的时候计算属性不会重新执行;
- - method,方法调用,使用的时候需要加括号,每一次页面更新的话都会重新执行;
- - ***puted:多个数据改变之后引起一个计算结果 eg:购物车的结算;
- watch:一个数据改变之后,可以触发的其他影响 eg:搜索;
19、vue 中的数据改变是异步的,如何获取改变之后的最新的数据?
$nextTick,可以获取最新的改变之后的结果。页面在下一次渲染之后会触发它的回调函数;
20、 $set 有没有了解过,有什么作用?
我们在 vue 中动态为 data 添加的数据是不能做到响应式的,可以使用$set 为其设置为响应式;
21、虚拟 dom 和 diff 算法
虚拟 dom,就是一个用 js 表达的 dom 树结构,最终会生成真实的 dom 树。它是一个 js 对象,所以更新比较的效率很高,在渲染生成真实的 dom 树的时候会进行局部更新,而不是更新整个页面。这样子便于提升页面的渲染速度和优化页面性能
diff 算法,是一个虚拟 dom 节点改变的查找算法,可以快速的定位到发生改变的节点。找到哪一个位置发生了改变,进行替换操作。它是按照逐层进行比较的,遇到改变的节点,直接替换整棵树
diff 算法按照逐层比较,如果当前层有改变,那么所有的子节点自动全部替换
22、vue 中如何获取 dom 元素?
(1)通过 $refs 获取元素;
<template>
<div>
<input type="text" ref="myInput">
<button @click="handleClick">获取值</button>
</div>
</template>
<script>
export default {
methods: {
handleClick() {
console.log(this.$refs.myInput.value);
},
},
};
</script>
使用ref,给相应的元素加ref="name", 然后再this.$refs.name获取到该元素
(2)通过事件参数 $event 获取元素;
<template>
<div>
<input type="text" @blur="handleBlur">
</div>
</template>
<script>
export default {
methods: {
handleBlur(event) {
console.log(event.target.value);
},
},
};
</script>
添加了一个事件监听器,并将其绑定到handleBlur方法。当输入框失去焦点时,handleBlur方法被触发。该方法接受一个事件参数event,并使用event.target.value获取输入框的值。
23、vue 中如何解决 v-for 中使用 v-if 的问题?
在 v-for 循环之前多数据先做过滤处理(只循环需要展示的数据)
v-for 的优先级高于 v-if
24、$route 和 $router 的区别
$route用来获取路由的信息的,它是路由信息的一个对象,里面包含路由的一些基本信息,包括name、meta、path、hash、query、params、等。
而$router主要是用来操作路由的,它是VueRouter的实例,包含了一些路由的跳转方法,钩子函数等
25、对比 jQuery,Vue 有什么不同?
jQuery 专注视图层,通过直接操作 DOM 去实现页面的一些逻辑渲染;Vue 专注于数据层,通过数据的双向绑定,最终表现在 DOM 层面,减少了 DOM 操作;
Vue 使用了组件化思想,使得项目子集职责清晰,提高了开发效率,方便重复利用,便于协同开发
26、Vue-router 使用 params 与 query 传参有什么区别?
// 用法上
1:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name;
// 展示上
2:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示;
3:params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系;
4:params、query不设置也可以传参,params不设置的时候,刷新页面或者返回参数会丢失;
27、用过插槽吗?用的是具名插槽还是匿名插槽?
用过,都使用过。插槽相当于预留了一个位置,可以将我们书写在组件内的内容放入,写一个插槽就会将组件内的内容替换一次,两次则替换两次。为了自定义插槽的位置我们可以给插槽取名,它会根据插槽名来插入内容,一一对应。
28、用过 beforeEach 吗?
每次通过vue-router进行页面跳转,都会触发beforeEach这个钩子函数,这个回调函数共有三个参数,to,from,next这三个参数,to表示我要跳转的目标路由对应的参数,from表示来自那个路由,就是操作路由跳转之前的,即将离开的路由对应的参数,next是一个回调函数,一定要调用next方法来resolve这个钩子函数;
29、常见的事件修饰符及其作用
-
.stop
:等同于 JavaScript 中的event.stopPropagation()
,防止事件冒泡; -
.prevent
:等同于 JavaScript 中的event.preventDefault()
,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播); -
.capture
:与事件冒泡的方向相反,事件捕获由外到内; -
.self
:只会触发自己范围内的事件,不包含子元素; -
.once
:只会触发一次。
30、谈一下你对keep-alive的理解
如果需要在组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件。
keep-alive有以下三个属性:
- include 字符串或正则表达式,只有名称匹配的组件会被匹配;
- exclude 字符串或正则表达式,任何名称匹配的组件都不会被缓存;
- max 数字,最多可以缓存多少组件实例。
注意:keep-alive 包裹动态组件时,会缓存不活动的组件实例。
keep-alive 组件是 vue 的内置组件,用于缓存内部组件实例。这样做的目的在于,keep-alive 内部的组件切回时,不用重新创建组件实例,而直接使用缓存中的实例,一方面能够避免创建组件带来的开销,另一方面可以保留组件的状态。
keep-alive 具有 include 和 exclude 属性,通过它们可以控制哪些组件进入缓存。另外它还提供了 max 属性,通过它可以设置最大缓存数,当缓存的实例超过该数时,vue 会移除最久没有使用的组件缓存。
受keep-alive的影响,其内部所有嵌套的组件都具有两个生命周期钩子函数,分别是 activated 和 deactivated,它们分别在组件激活和失活时触发。第一次 activated 触发是在 mounted 之后
在具体的实现上,keep-alive 在内部维护了一个 key 数组和一个缓存对象
// keep-alive 内部的声明周期函数
// keep-alive 内部的声明周期函数
created () {
this.cache = Object.create(null)
this.keys = []
}
key 数组记录目前缓存的组件 key 值,如果组件没有指定 key 值,则会为其自动生成一个唯一的 key 值
cache 对象以 key 值为键,vnode 为值,用于缓存组件对应的虚拟 DOM
在 keep-alive 的渲染函数中,其基本逻辑是判断当前渲染的 vnode 是否有对应的缓存,如果有,从缓存中读取到对应的组件实例;如果没有则将其缓存。
当缓存数量超过 max 数值时,keep-alive 会移除掉 key 数组的第一个元素。
31、Vue-router 导航守卫有哪些
- 全局前置/钩子:beforeEach、beforeResolve、afterEach;
- 路由独享的守卫:beforeEnter;
- 组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave;
32、vue3 和 vue2 的区别?
vue3 数据双向绑定的原理是 proxy 代理和 vue2 不一样。vue3 中引入了很多 hooks 的写法,vue3 中新增了组合式 api,写法更像 react;
vue3 中移除了 filter 过滤器功能;vue3 中跨组件之间传参使用 provider/inject 实现;
(1)监测机制的改变
- 3.0 将带来基于代理 Proxy的 observer 实现,提供全语言覆盖的反应性跟踪。
- 消除了 Vue 2 当中基于 Object.defineProperty 的实现所存在的很多限制:
(2)只能监测属性,不能监测对象
- 检测属性的添加和删除;
- 检测数组索引和长度的变更;
- 支持 Map、Set、WeakMap 和 WeakSet。
(3)模板
- 作用域插槽,2.x 的机制导致作用域插槽变了,父组件会重新渲染,而 3.0 把作用域插槽改成了函数的方式,这样只会影响子组件的重新渲染,提升了渲染的性能。
- 同时,对于 render 函数的方面,vue3.0 也会进行一系列更改来方便习惯直接使用 api 来生成 vdom 。
(4)对象式的组件声明方式
- vue2.x 中的组件是通过声明的方式传入一系列 option,和 TypeScript 的结合需要通过一些装饰器的方式来做,虽然能实现功能,但是比较麻烦。
- 3.0 修改了组件的声明方式,改成了类式的写法,这样使得和 TypeScript 的结合变得很容易
(5)其它方面的更改
- 支持自定义渲染器,从而使得 weex 可以通过自定义渲染器的方式来扩展,而不是直接 fork 源码来改的方式。
- 支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。
- 基于 tree shaking 优化,提供了更多的内置功能。
推荐阅读:
前端面试:前端面试八股文(详细版)—中_前端面试八股文在哪刷-CSDN博客
Vue2重点笔记:Vue2快速上手指南,重点笔记整理-CSDN博客
Vue3重点笔记: Vue3快速上手指南,重点知识内容总结_vue3 中 v-phone-hide:name_旺旺大力包的博客-CSDN博客