Vue的面试题库
1、vue中 key
值的作用
key的特殊性主要用在Vue的虚拟DOM算法,再新旧nodes对比时辨别VNodes。如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。
有相同父元素的子元素必须有独特的key。重复的key会造成渲染错误。
最常见的用例是结合 v-for:
1 <ul> 2 <li v-for="item in items" :key="item.id">... 3 </li> 4 </ul>
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
完整地触发组件的生命周期钩子 触发过渡
1 <transition> 2 <span :key="text">{{ text }}</span> 3 </transition>
当 text 发生改变时,<span> 会随时被更新,因此会触发过渡。
2.vue中子组件调用父组件的方法
子组件调用父组件的方法可以使用this.$emit()
第一种方法是在子组件里用$emit
向父组件触发一个事件,父组件监听这个事件就行了。
$emit
父组件
1 <template> 2 <div> 3 <child @fatherMethod="fatherMethodOther"></child> 4 </div> 5 </template> 6 <script> 7 import child from './child'; 8 export default { 9 components: { 10 child 11 }, 12 methods: { 13 fatherMethodOther(str) { 14 console.log(str); 15 } 16 } 17 }; 18 </script>
子组件
1 <template> 2 <div> 3 <button @click="childMethod">点击</button> 4 </div> 5 </template> 6 <script> 7 export default { 8 methods: { 9 childMethod() { 10 this.$emit('fatherMethod', 'hello'); 11 } 12 } 13 }; 14 </script>
第二种方法是直接在子组件中通过this.$parent.event来调用父组件的方法
$parent
父组件
1 <template> 2 <div> 3 <child></child> 4 </div> 5 </template> 6 <script> 7 import child from './child'; 8 export default { 9 components: { 10 child 11 }, 12 methods: { 13 fatherMethod(str) { 14 console.log(str); 15 } 16 } 17 }; 18 </script>
子组件
1 <template> 2 <div> 3 <button @click="childMethod">点击</button> 4 </div> 5 </template> 6 <script> 7 export default { 8 methods: { 9 childMethod() { 10 this.$parent.fatherMethod('hello'); 11 } 12 } 13 }; 14 </script>
-
vue等单页面应用及其优点
优点:
1.具有桌面应用的及时性,网站的可移植性和可访问性。
2.用户体验好,块,内容改变不需要重新加载整个页面
3.基于上面一点,SPA相对对服务器压力小。
4.良好的前后端分离。SPA和RESTful架构一起使用,后端不再负责模板渲染、
输出页面工作,web前端和各种移动终端地位对等,后端API通用化。
5.同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端;缺点:
1、不利于SEO。(如果你看中SEO,那就不应该在页面上使用JavaScript,
你应该使用网站而不是Web应用)
2、初次加载耗时相对增多。
3、导航不可用,如果一定要导航需要自行实现前进、后退。4.vue.js的两个核心是什么?
数据驱动和组件化。
5.vue的双向绑定的原理是什么?
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。具体实现过程:
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
流程图如下:
二. v-show和v-if指令的共同点和不同点?
-
v-show指令是通过修改元素的display的css属性达到让其显示或者隐藏
-
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
-
(注意:v-if 可以实现组件的重新渲染)
三. 如何让CSS只在当前组件中起作用?
将当前组件<style>修改为<style scoped>
四. <keep-alive></keep-alive>的作用是什么?
<keep-alive></keep-alive>
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
对列表组件使用<keep-alive></keep-alive>
进行缓存, 这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
五. Vue中引入组件的步骤?
六.请列举出3个Vue中常用的生命周期钩子函数?
vue的生命周期分为8个阶段,创建前/后,载入前/后,更新前/后,销毁前/后。
第一次页面加载需要beforeCreate,created,beforeMount,mounted四个钩子函数。
1) beforeCreate---创建前
组件实例被创建,组件属性计算之前,数据对象data都为undefined,未初始化。
2)created---创建后
组件实例创建完成,属性已经绑定数据对象data已存在,但DOM未生成,$el未存在。
3)beforeMount---挂载前
vue实例的$el和data都已初始化,挂载之前为虚拟的dom节点,data.message未替换。
4)mounted---挂载后
vue实例挂载完成,data.message替换,ajax请求等一系列操作。
5)beforeUpdate---更新前
当data发生变化,会触发此方法。
6)updated---更新后l
当data发生变化,会触发此方法。
7)beforeDestory--销毁前
组件销毁前调用。
8)destoryed---销毁后
组件销毁后调用,对data的改变不会再触发周期函数,vue实例已解除事件监听和dom绑定,但dom结构依然存在。
七.请简述下Vuex的原理和使用方法
数据单向流动
一个应用可以看作是由上面三部分组成: View, Actions,State,
数据的流动也是从View => Actions => State =>View 以此达到数据的单向流动.
但是项目较大的, 组件嵌套过多的时候, 多组件共享同一个State会在数据传递时出现很多问题
.Vuex就是为了解决这些问题而产生的.
Vuex可以被看作项目中所有组件的数据中心,我们将所有组件中共享的State抽离出来,
任何组件都可以访问和操作我们的数据中心
Vuex的组成:一个实例化的Vuex.Store由state, mutations和actions三个属性组成:
1. state中保存着共有数据
2. 改变state中的数据有且只有通过mutations中的方法,且mutations中的方法必须是同步的
3. 如果要写异步的方法,需要些在actions中, 并通过commit到mutations中进行state中数据的更改.
八.为什么v-if和v-for不能连用?
-
v-for优先级高于v-if,如果连在一起使用的话会把v-if给每一个元素都添加上,
重复运行于每一个v-for循环中,会造成性能浪费
-
可以将v-if写在v-for的外层
九.定义vue-router的动态路由?怎么获取传过来的动态参数?
设置:在router目录下的index.js文件中,对path属性加上/:id
获取:使用router对象的params.id
十.v-for中为什么要用key
因为vue组件高度复用,增加Key可以标识组件的唯一性,key的作用主要是为了高效的更新虚拟DOM,
-
无key时,会存在“就地复用”的问题。(同一组件标签相同,key相同就会复用)
-
有key时,只需移动无需重新创建dom。
十一.Vue中v-html会导致那些问题?
-
-
但是有的时候我们需要渲染的html片段中有插值表达式,或者按照Vue模板语法给dom元素绑定了事件。
-
在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局 <style>元素手动设置类似 BEM 的作用域策略。
-
后台返回的html片段,以及css样式和js,但是返回的js是不执行的,因为浏览器在渲染的时候并没有将js渲染,这时要在$nextTick中动态创建script标签并插入
十二.Vue组件如何通信?
https://www.cnblogs.com/fundebug/p/10884896.html
十三.什么是作用域插槽?
插槽可以控制html模板的显示与不显示。作用域插槽其实就是带数据的插槽。
原来父组件可以通过绑定数据传递给子组件。作用域插槽就可以通过子组件绑定数据传递给父组件。
十四.vue-router有哪几种路由守卫?
路由守卫为: 全局守卫:beforeEach 后置守卫:afterEach 全局解析守卫:beforeResolve 路由独享守卫:beforeEnter
十五.组件中的data为什么是一个函数?
在 new Vue()
中,data
是可以作为一个对象进行操作的,然而在 component
中,data
只能以函数的形式存在,不能直接将对象赋值给它。
当data选项是一个函数的时候,每个实例可以维护一份被返回对象的独立的拷贝,这样各个实例中的data不会相互影响,是独立的。
vue核心知识——vuex
十六.不用Vuex会带来什么问题?
一、可维护性会下降,你要想修改数据,你得维护三个地方
二、可读性会下降,因为一个组件里的数据,你根本就看不出来是从哪来的
三、增加耦合,大量的上传派发,会让耦合性大大的增加,本来Vue用Component就是为了减少耦合,
现在这么用,和组件化的初衷相背。
1.vuex有哪几种属性?
有五种,分别是 State、 Getter、Mutation 、Action、 Module。
2、vuex的State特性是?
一、Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于与一般Vue对象里面的data 二、state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新 三、它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
3、vuex的Getter特性是?
一、getters 可以对State进行计算操作,它就是Store的计算属性 二、 虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用 三、 如果一个状态只在一个组件内使用,是可以不用getters
4、vuex的Mutation特性是?
一、Action 类似于 mutation,不同在于: 二、Action 提交的是 mutation,而不是直接变更状态。 三、Action 可以包含任意异步操作
5、Vue.js中ajax请求代码写在组件的methods中还是vuex的actions中?
一、如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。 二、如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。如果不要复用这个请求,那么直接写在vue文件里很方便。
十七.Ajax请求放在那个生命周期中?
答案:mounted
vue本身不支持发送AJAX请求,需要使用vue-resource、axios等插件实现
等到异步渲染开启的时候,created 就可能被中途打断,中断之后渲染又要重做一遍,想一想,在 created 中做ajax调用,代码里看到只有调用一次,但是实际上可能调用 N 多次,这明显不合适。 相反,若把发ajax 放在 mounted,因为 mounted 在第二阶段,所以绝对不会多次重复调用,这才是ajax合适的位置.
十八.v-model中的实现原理级如何自定义v-model?
VUE中的v-model可以实现双向绑定,但是原理是什么呢?往下看看吧
根据官方文档的解释,v-model其实是一个语法糖,它会自动的在元素或者组件上面解析为 :value="" 和 @input="", 就像下面这样
1 // 标准写法 2 <input v-model="name"> 3 4 // 等价于 5 <input :value="name" @input="name = $event.target.value"> 6 7 // 在组件上面时 8 <div :value="name" @input="name = $event"></div>
1.当在input输入框输入内容时,会自动的触发input事件,更新绑定的name值。
2.当name的值通过JavaScript改变时,会更新input的value值
根据上面的原理,vue就通过v-model实现双向数据绑定
看了前面的解释,对于v-model有了一定的理解。下面我们就来实现自己组件上面的v-model吧
需求:实现一个简单的点击按钮,每次点击都自动的给绑定值price加100。 组件名为 AddPrice.vue
1 // AddPrice.vue 2 // 通过props接受绑定的value参数 3 <template> 4 <div @click="$emit('input',value + 100 )">点击加钱<div> 5 </template> 6 7 <script> 8 export default { 9 props: ['value'] 10 } 11 12 </script> 13 14 // 在父组件中调用 15 <add-price v-model="price"></add-price>
组件中使用props接受传入的参数值value, 组件点击事件触发并 使用$emit调用父组件上的input事件,实现了自定义的双向绑定
十九.响应式数据的原理是什么?
1、声明式
只需要声明在哪里where,做什么what,而无需关系如何实现how
1 //此map方法就是,声明式的,只告诉map要实现获取2倍,然后map具体怎么实现不关心 2 var arr = [1,2,3,4]; 3 var newArr = arr.map((item,index)=>{ 4 return item*2; 5 })
2、命令式
需要以具体的代码表达在哪里where,做什么what,以及如何实现how
1 //forEach就是命令式,会具体操作数组,还有如何得到结果push 2 var arr = [1,2,3,4]; 3 var newArr = []; 4 arr.forEach((item,index)=>{ 5 newArr.push(item*2); 6 })
声明式的理解:
1)DOM状态只是数据状态的一种映射
2)所有的逻辑尽可能在状态的层面去进行
3)当状态变化了,View会被框架自动更新到合理的状态
3、响应式数据原理
vue响应式的核心就是Object.defindProperty
作用:直接在一个对象上定义一个新的属性,或者修改一个对象的现有属性
语法:Object.definProperty(obj,prop,descriptor)
参数:obj要在其上定义属性的对象,prop要定义的或要修改的属性的名称,descriptor将被定义或修改的属性描述符
数据描述
configurable:是否可以删除属性,默认false
enumberable:此属性是否可以被枚举,默认false
value: 该属性对应的值,默认undefined
writable: 属性的值是否可以被重写,默认false
访问器描述
getter:是一种获得属性值的方法
setter:是一种设置属性值的方法
1 //数据劫持,转成getter和setter 2 function observer(obj){ 3 Object.keys(obj).forEach((item)=>{ 4 defineReactive(obj,item,obj[item]) 5 }) 6 } 7 8 function defineReactive(obj,key,value){ 9 Object.defineProperty(obj,key,{ 10 enumerable:true, 11 configurable:true, 12 get(){ 13 return value; 14 }, 15 set(newValue){ 16 if(value == newValue){return} 17 //value相当于是一个公用的存储空间,把最新的值存进去;访问也是访问这里面的最新的值 18 value=newValue; 19 //此处还会放一些其他复杂的操作,收集依赖,通知变化等 20 } 21 }) 22 }
vue响应式原理理解:
1、把一个普通的js对象传给Vue实例的data选项对象
2、Vue将遍历此对象的所有的属性,并使用Object.defineProperty把这些属性全部转换为getter/setter
3、Vue内部会对数据进行劫持操作,进而追踪依赖,在属性被访问和修改时通知变化
二十.Vue中是如何检查数组变化?
1.使用函数劫持的方式,重写了数组的方法 2.vue 将 data 中的数据,进行了原型链重写,指向了自己定义的数组原型方法,这样当调用数组 api 的时候,可以通知依赖更新,如果数组中包含着引用类型,则会对数组中的引用类型再次进行监控。
二十一.Vue中Computed的特点?
在computed中,可以定义一些属性,这些属性,叫做计算属性。计算属性的本质就是一个方法,只不过,我们在使用这些计算属性的时候,是把它们的名称,直接当做属性来使用,并不会把计算属性当做方法来使用。
三个注意事项:
一、计算属性在引用的时候,一定不要加()去调用,直接把它当作普通的属性去使用就好了;
二、只要计算属性这个function内部所用到的data中的数据发生了变化,就会立即重新计算这个计算属性的值;
三、计算属性的求值结果,会被缓存起来,方便下次继续使用;如果计算属性方法中,所依赖的任何数据,都没有发生过变化,则不会重新对计算属性求值。