Vue面试题总结

web前端面试题

    • 1.Vue解决了什么问题
    • 2.MVVM的理解
    • 3.自定义组件
    • 4.nextTick的理解
    • 5.Vue的生命周期函数
    • 6.虚拟dom的原理
    • 7.双向数据绑定的原理
    • 8.Vue中双向数据绑定是如何实现的
    • 9.Proxy相比于defineProperty的优势
    • 10.watch、computed和methods的区别
    • 11.virtual-dom原理实现(虚拟dom)
    • 12.vue-router
    • 13.vuex的理解
    • 14.vue从初始化页面–>修改数据–>刷新页面UI过程?
    • 15.Vue的响应式原理
    • 16.Vue.js的特点
    • 17.插槽的理解
    • 18.vue-router有哪几种导航钩子
    • 19.vue组件中的data为什么是一个函数
    • 20.路由懒加载
    • 21.Vue.js是什么?
    • 22.scoped原理及穿透方法
    • 23.vue.cli项目中src目录每个文件夹和文件的用法
    • 24.Vue中key值的作用
    • 25.Vue怎么重置data
    • 26.组件中写name选项有什么作用
    • 27.route和router
    • 28.Vue和React的区别
    • 29.标题首屏加载优化
    • 30.Vue3.0的简单了解
    • 31.vue-cli 替我们做了哪些工作
    • 32.vue-cli完成的功能:
    • 33.v-for 与 v-if 的优先级
    • 34.vue怎么兼容IE
    • 35.$set是干嘛用的
    • 36.vue中"dependencies","devDependencies"是什么?
    • 37.怎么创建vue的实例
    • 38.列举常用指令以及作用
    • 39.列举出常用的修饰符
    • 40.v-if和v-show的区别及使用场景
    • 41.自定义指令的语法是什么?请举例说明一个带参数的自定义指令怎么定义
    • 42.渐进式框架的理解

1.Vue解决了什么问题

虚拟dom:dom操作时非常消耗性能,不再使用原生的dom操作,极大的释放了dom操作,但本质还是操作dom,只是换了一种方式。
视图,数据,结构分离:使数据的修改变得更为简单。不需要修改逻辑代码只需要操作数据即可
组件化:将一个单页面的各种模块拆分到不同的组件中,便于开发以及后期的维护管理

2.MVVM的理解

model-view-viewmodel的缩写,mvvm把视图和逻辑代码区分开。

在mvvm的框架下,view和model没有直接的交互,是通过view-model进行数据的双向交互。
viewmodel通过双向数据绑定,将model和view连接起来,因此model和view的数据同步工作时完全自动的。
开发者只需要关注业务逻辑,不需要手动操作dom,也不需要关注数据的同步问题,这些由mvvm统一管理

1、简述MVVM和MVC

MVC:
Model(模型)
View(视图)
Controller(控制器)
简单的理解:视图请求数据,将请求发送至控制器,控制器再将请求发送给模型,模型去查找数据,找到之后传给控制器,控制器再传给视图进行渲染。

MVVM
Model 代表数据模型
View 代表UI视图
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新(桥梁,可以理解成mvc中的控制器)
简单理解:视图请求数据,将请求发送至控制器,在控制器的两端具有监听机制,直接调用模型的数据,一端改变全部改变,利用数据劫持,结合订阅者和发布者模式,实现数据的双向绑定

3.自定义组件

在子组件中创建模板,在props中接受父组件传递的数据,在父组件中引入子组件,然后在components中创建子组件,挂载到父组件的template
props 父传子使用 $emit(参1,参2)子传父时使用 参1是自定义的事件名,参2是要传递的数据,在父组件的子组件中绑定自定义事件名,调用一个函数,函数的形参就是传递的数据

$children 获取的是一个数组 $parent 获取的是一个对象

	this.$children[0].msg = "hello world" //父组件修改子组件data中的数据
    this.$parent.msg //子组件拿到父组件data中的数据

eventBus 总线程

兄弟传参时使用 在传数据的一方引入bus,通过函数调用
this.emit(参1,参2),参1是自定义的事件名,参2是要传递的数据,
在接收的一方引入bus,在created中调用this.$on(自定义事件名,回调函数(data){})data就是传递的数据

父传递子如何传递
(1)在父组件的子组件标签上绑定一个属性,挂载要传输的变量
(2)在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用 props:["属性 名"] props:{属性名:数据类型}

子传递父如何传递
(1)在父组件的子组件标签上自定义一个事件,然后调用需要的方法
(2)在子组件的方法中通过 this.$emit("事件")来触发在父组件中定义的事件,数据是以参数的形式进行传递的

兄弟组件如何通信
(1)在src中新建一个Bus.js的文件,然后导出一个空的vue实例
(2)在传输数据的一方引入Bus.js 然后通过Bus.$emit(“事件名”,"参数")来来派发事件,数据是以$emit()的参数形式来传递
(3)在接受的数据的一方 引入 Bus.js 然后通过 Bus.$on("事件名",(data)=>{data是接受的数据})

ref/refs
区别在于ref绑定在dom元素上,引用的就是dom元素,refs在组件的实例化调用获取到ref传递的dom元素内容

$attrs / $listeners

将数据挂在到子组件的标签上去后,在子组件中使用this.$attrs直接获取到所有挂载的数据,返回的是一个对象

4.nextTick的理解

使用的原因是Vue是异步修改DOM的,并不鼓励开发者直接接触DOM
但有时需要对数据更改后的DOM元素做相应的处理,但获取的数据不是修改之后的,所以要使用this.$nextTick()
原理是Vue通过异步队列控制DOM的更新和nextTick回调函数的先后执行顺序

<button @click="change()">按钮</button>
<h1 ref="gss">{{msg}}</h1>//JS
export default{
    name:"app",
    data(){
        return {
            msg:"123"
        }
    },
    methods:{
        change(){
            this.msg = "456";
            console.log(this.refs["gss"].innerHTML)//123
            this.$nextTick(function(){
                console.log(this.refs["gss"].innerHTML)//456
            })
        }
    }
 }

5.Vue的生命周期函数

beforeCreate(创建前):在此生命周期函数里,data 和 methods 的数据还没有初始化
created(创建后):在此生命周期内,data和methods中的数据已经初始化完毕,最早使用data数据的钩子函数
beforeMount(载入前):在此生命周期函数里,模板已经在内存中编译好了,但还没有挂载到页面,页面此时是旧的
mounted(载入后):此时页面已经渲染完毕,这个是最早可以操作dom的钩子函数
beforeUpdate(修改前):页面显示的数据旧的,data的数据是新的
updated(修改后):页面于data的数据已经同步
beforeDestroy(销毁前):该钩子函数执行的时候,数据还可以使用
destroyed(销毁后):数据已经销毁完毕
activated(keep-alive组件激活调用)
deactivated(keep-alive组件停用调用)
errorcapture(捕获来自子孙组件错误是调用)

6.虚拟dom的原理

虚拟dom就是用对象的方式区代真实的dom操作。
当页面打开时浏览器解析HTML元素,构建一个dom树,将状态保存起来,在内存中模拟dom操作,又会生成一个dom树,两个进行比较,根据diff算法找出不同的地方,之渲染一次不同的地方

虚拟dom是利用js描述元素与元素的关系。
好处:是可以快速的渲染和高效的更新元素,提高浏览器的性能

7.双向数据绑定的原理

vue的双向数据绑定只要是采用数据劫持结合开发者和订阅者方式

vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式。
通过Object.defineProperty()来劫持各个属性的settergetter, 在数据变动时发布消息给订阅者,触发相应监听回调

vue的数据双向绑定 将MVVM作为数据绑定的入口,整合ObserverCompileWatcher三者。 通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令。
最终利用watcher搭起observerCompile之间的通信桥梁,达到数据变化 —>视图更新;。

数据劫持:当我们访问或设置对象的属性的时候,都会触发相对应的函数,然后在这个函数里返回或设置属性的值。我们可以在触发函数的时候动一些手脚做点我们自己想做的事情,这也就是“劫持”操作

8.Vue中双向数据绑定是如何实现的

vue中的v-model可以实现双向绑定,其核心思想通过Object.definePropery来对Vue的数据进行数据劫持,
主要分为三部分
observer主要是负责对Vue数据进行数据劫持,使其数据拥有get和set方法
指令解析器负责绑定数据和指令,绑定试图更新方法
watcher负责数据监听,当数据发生改变通知订阅者,调用视图更新函数更新视图

9.Proxy相比于defineProperty的优势

Proxy相比于defineProperty的优势 Vue3.0摒弃了Object.defineProperty,改为基于Proxy的观察者机制探索
Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实施响应。
Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。 如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象才是更好的选择。
而要取代它的Proxy有以下两个优点: 可以劫持整个对象,并返回一个新对象。 有多种劫持操作(13种)

10.watch、computed和methods的区别

methods在重新渲染的时候每次都会被重新的调用
computed 是自动监听依赖值的变化,从而动态返回内容,主要目的是简化模板内的复杂运算
watch也可以影响数据的变化,当绑定的数据方法变化时触发响应的函数, 需要在数据变化时执行异步或开销较大的操作时使用watch。

11.virtual-dom原理实现(虚拟dom)

virtual-dom(简称vdom)的概念得益于react的出现react这个框架的非常重要的特性之一。

相比于频繁的手动去操作dom而带来性能问题,vdom很好的将dom做了一层映射关系 进而将在我们本需要直接进行dom的一系列操作,映射到了操作vdom,而vdom上定义了 关于真实dom进行的创建节点,删除节点,添加节点等一系列复杂的dom操作, 并将这些操作放到vdom中进行,这样就通过操作vdom来提高直接操作的dom的效率和性能。

在vue的整个应用生命周期当中,每次需要更新视图的时候便会使用vdom
vdom算法是基于snabbdom算法所做的修改。

实现:
①用js对象构造一个虚拟的dom树,插入到文档中;
②状态变更时,记录新树和旧树的差异;
③把上面的差异构建到真正的dom中

12.vue-router

单页面的跳转
hash:使用URLhash 的值来作为路由
history:依赖于HTML5 History API和服务器配置
abstract:严格模式支持所有的JavaScript运行环境根据model参数来决定时那种方式
原理是更新视图但不重新请求页面

13.vuex的理解

vuex是专门为vue.js应用程序开发的状态管理工具。
它采用集中式储存管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
优点: 当state中定义一个数据后,可以在所在项目的任何组件中进行获取,修改,修改可以得到全局的变更
运行机制:vue提供数据来驱动试图,听过dispath派发actions,通过commit调用mutations的方法,修改state的数据

①state:定义初始数据。
②mutations:更改Vuex的store中的状态的唯一方法是提交mutation
③getters:可以对 state 进行计算操作,它就是 store 的计算属性虽然在组件内也可以做计算属性
④actions:异步操作初始数据,其实就是调用mutations里面的方法。
⑤module:面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。

Vuex的映射: state getters需要映射在computed实例中,mutations actions 等需要放在methods实例中

14.vue从初始化页面–>修改数据–>刷新页面UI过程?

当vue进入初始化页面的时候会遍历data的属性,通过object.defineproperty转换成getet/setter形式,实现数据劫持,
compile对元素的指令进行解析,初始化视图,watcher来更新视图,watcher会添加到Dep中,初始化完毕数据发生改变时,触发observersetter方法,
调用Dep.notfiy(),Dep数组开始遍历所有的订阅者,调用update方法,在通过diff算法,完成视图的改变

15.Vue的响应式原理

Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录作为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

16.Vue.js的特点

轻量级的框架组件化 和 响应式设计实现数据与结构的分离数据的双向绑定 优点是减少了dom操作数据驱动

17.插槽的理解

插槽就是子组件中的提供给父组件使用的一个占位符,用标签接收,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。

子组件

<template>    
	<div>        
		<h1>商品列表</h1>        
		<solt></solt>    
	</div>
</template>
<script>
	export default {    
		name:'child',
	}
</script>

父组件

<template>    
	<div>      
		<h1>商品列表</h1>        
		<child>            
			<div>苹果,香蕉</div>        
		</child>    
	</div>
</template>

18.vue-router有哪几种导航钩子

① 全局导航钩子:一般用来判断权限,以及页面丢失时需要执行的操作;
beforeEach()每次路由进入之前执行的函数。
afterEach()每次路由进入之后执行的函数。
beforeResolve()2.5新增

② 单个路由(实例钩子)
beforeEnter()
beforeLeave()

③ 组件路由钩子:
beforeRouteEnter()
beforeRouteLeave()
beforeRouteUpdate()

19.vue组件中的data为什么是一个函数

data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。
Object是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了

20.路由懒加载

在单页应用中,如果没有应用懒加载,运用webpack打包后的文件很大,进入首页时,加载的内容过多,不利于用户体验。而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力。

原理:vue异步组件技术:异步加载,vue-router配置路由 , 使用vue的异步组件技术 , 实现按需加载
1

component:(resolve) => {
    require(["@/components/HelloWorld"],resolve);
 }

2

const info = () => import("@/components/info");

3

const info = (resolve) => {
    import("@/components/info").then(modul => {
        resolve(modul);
    }
)}

4

const info = r => require.ensure([],() => r(
    require("@/components/info")
    ),"info");

21.Vue.js是什么?

vue就是一个js库,并且无依赖别的js库。
vue的核心库只关注视图层,非常容易与其它库或已有项目整合。
Vue.js是一个轻巧、高性能、可组件化的MVVM库,同时拥有非常容易上手的API。

22.scoped原理及穿透方法

vue中的scoped通过在DOM结构以及css样式上加唯一不重复的标记:data-v-hash的方式,以保证唯一,达到样式私有模块化的目的。

scoped穿透:/deep/ >>>

23.vue.cli项目中src目录每个文件夹和文件的用法

asstes 静态资源文件
components 组件
router 路由的配置
view 视图
app.vue 应用主组件
main.js 入口文件

24.Vue中key值的作用

主要是为了高效的更新虚拟DOM。

25.Vue怎么重置data

使用Object.assign()vm.$data可以获取当前状态下的data,
vm.$options.data可以获取到组件初始化状态下的data。

Object.assign(this.$data, this.$options.data())

26.组件中写name选项有什么作用

项目使用keep-alive时,可搭配组件的name进行缓存过滤。
DOM做递归组件时需要调用自身name
vue-devtools调试工具里显示的组件名称是由vue中组件name决定的

27.route和router

route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。router是“路由实例对象”,包括了路由的跳转方法(push、go),钩子函数等。

28.Vue和React的区别

监听数据变化的实现原理不同:Vue通过getter/setter以及函数的劫持,能快速的计算出Vdom的差异,这是它在渲染的过程中,会跟踪每个组件的依赖关系,不需要重新渲染组件树。react是默认通过比较的引用方式进行,如果不优化,每当应用的状态被改变时,所有的子组件页时重新渲染,导致大量的不必要的vdom重新渲染
数据流的不同:Vue默认双向绑定数据,组件和dom动过v-model双向绑定。但是父子组件之间,props在2x版本中时单项的数据流,react一直提倡单向数据流
模板渲染的方式不同:react是通过JSX渲染模板,vue是通过拓展HTML语法进行渲染

29.标题首屏加载优化

不长改变的库放到index.html中,用cdn引入然后找到 build/webpack.base.conf.js 文件,
在 module.exports = { } 中添加以下代码:
externals: {
  'vue': 'Vue',
  'vue-router': 'VueRouter',
  'element-ui': 'ELEMENT',
 }

路由懒加载

vue的组件尽量不要全局引入使用更轻量级的工具库

开启gzip压缩:这个优化是两方面的,前端将文件打包成.gz文件,然后通过nginx的配置,让浏览器直接解析.gz文件。

不生成map文件,找到config/index.js文件,修改为productionSourcceMap:false

30.Vue3.0的简单了解

新的API
setup()函数
关于Typescript的支持
替换Object.defineProperty为 Proxy 的支持。关于Proxy代替带来的性能上的提升,因为传统的原型链拦截的方法,无法检测对象及数组的一些更新操作,但使用Proxy又带来了浏览器兼容问题。

31.vue-cli 替我们做了哪些工作

vue-cli是基于 Vue.js 进行快速开发的完整系统,也可以理解成是很多 npm 包的集合。

32.vue-cli完成的功能:

.vue 文件 --> .js 文件
ES6 语法 --> ES5 语法
Sass,Less,Stylus --> CSS
对 jpg,png,font 等静态资源的处理
热更新
定义环境变量,区分 dev 和 production 模式
如果开发者需要补充或修改默认设置,需要在 package.json 同级下新建一个 vue.config.js 文件

33.v-for 与 v-if 的优先级

v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。

34.vue怎么兼容IE

使用babel-polyfill插件

35.$set是干嘛用的

<template>
    <h1>{{arr}}</h1>
    <button @click="change()">点击</button>
</template>
<script>
		export default {
		    data(){
		        return {
		            arr:[1,2,3]
		        }
		    },
		    methods:{
		        change(){
		            this.arr[1]=0;
		            console.log(this.arr);  //[1,0,3]
		        }
		    }
		}
</script>

当我们点击按钮想要根据数组arr的下标改变其元素的时候,你会发现data中的数据改变了,但是页面中的数据并没有改变。这时候就需要$set出场了。

change(){
    this.$set(this.list,1,0);
}

改变/添加 对象属性的时候:

this.$set(data实例,“属性名(添加的属性名),“属性值(添加的属性值))

改变/添加 数组属性的时候:

this.$set(data实例,数组下标,“改变后的元素(添加的元素))

vue在创建实例的时候把data深度遍历所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter

让 Vue 追踪依赖,在属性被访问和修改时通知变化。

所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

当你在对象上新加了一个属性newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制,vue.$set是能让vue知道你添加了属性, 它会给你做处理

36.vue中"dependencies","devDependencies"是什么?

dependencies 是生产环境
devDependencies 是开发测试环境

37.怎么创建vue的实例

 new Vue({
      el: "#app",
      data:{

      },
      methods:{

      }
 })
 

38.列举常用指令以及作用

	v-html 解析输出变量 能解析html
​	v-text 解析输出变量
​	v-bind 给标签绑定属性 可以简写为 :属性名=“变量”
​	v-on 给元素绑定事件   用法 v-on:事件名=“方法名” 可以简写为@事件名=“方法”
​	v-pre 跨过当前的标签不解析 用法 :<标签 v-pre></标签>
​	v-cloak 解决差值表达式闪烁的问题
​	v-model 实现数据的双向绑定  只能适用于表单元素
​	v-for 可以循环遍历数据
​	v-if 条件输出
​	v-show条件输出

39.列举出常用的修饰符

   .stop  阻止事件冒泡
   .capture 设置事件捕获
   .self  只有当事件作用在元素本身才会触发
   .prevent 阻止默认事件,比如超链接跳转
   .once 事件只能触发一次
   .keyup.enter 
   .keyup.space

40.v-if和v-show的区别及使用场景

区别:
1、当条件为真的时候 没有区别 当条件为假的时候 v-if是不创建元素 v-show 渲染元素然后隐藏掉
2、v-if更适合数据的筛选和初始渲染 v-show更适合元素的切换

41.自定义指令的语法是什么?请举例说明一个带参数的自定义指令怎么定义

 bind(){} 只调用一次,指令第一次绑定到元素时调用
 inserted(){}被绑定元素插入父节点时调用
 update(){}被绑定元素所在的模板更新时调用,而不论绑定值是否变化
 componentUpdated(){}被绑定元素所在模板完成一次更新周期时调用
 unbind(){}只调用一次, 指令与元素解绑时调用

42.渐进式框架的理解

Vue是一个MVVM的渐进式框架,,渐进式指的是先使用Vue的核心库,然后再根据需求逐渐增加所需要的插件,慢慢的组织成自己的项目,
我们在使用过程中主张最小化,Vue没有强主张,插件使用比较灵活,也就是没有做职责之外的事。

你可能感兴趣的:(vue)