常见的 vue面试题目

常见的 vue面试题目 1、请讲述下VUE的MVVM的理解MVVM 是 Model-View-ViewModel的缩写即将数据模型 与数据表现层通过数据驱动进行分离从而只需要关系数据模型的开发而不需要考虑页面的表现具体说来如下Model代表数据模型主要用于定义数据和操作的业务逻辑。View代表页面展示组件即dom展现形式负责将数据模型转化成UI 展现出来。ViewModel为model和view之间的桥梁监听模型数据的改变和控制视图行为、处理用户交互。通过双向数据绑定把 View 层和 Model 层连接了起来而View 和 Model 之间的同步工作完全是自动的无需人为干涉在MVVM架构 下View 和 Model 之间并没有直接的联系而是通过ViewModel进行交互Model 和 ViewModel 之间的交互是双向的 因此View 数据的变化会同步到Model中而Model 数据的变化也会立即反应到View 上。2、VUE的生命周期及理解答总共分为8个阶段具体为创建前/后载入前/后更新前/后销毁前/后。创建前/后 在beforeCreated阶段ue实例的挂载元素e l 和数据对象 d a t a 都为 u n d e f i n e d 还未初始化在 c r e a t e d 阶段 v u e 实例的数据对象 d a t a 有了 el和数据对象data都为undefined还未初始化在created阶段vue实例的数据对象data有了el和数据对象data都为undefined还未初始化在created阶段vue实例的数据对象data有了el还没有。载入前/后在beforeMount阶段vue实例的$el和data 都初始化了但还是挂载之前为虚拟的dom节点data.message还未替换在mounted阶段vue实例挂载完成data.message成功渲染。更新前/后当data变化时会触发beforeUpdate和updated方法。**销毁前/后**在执行destroy方法后对data的改变不会再触发周期函数说明此时vue实例已经解除了事件监听以及和dom的绑定但是dom结构依然存在。具体讲解及应用**beforeCreate**在new一个vue实例后只有一些默认的生命周期钩子和默认事件其他的东西都还没创建data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法**create**data 和 methods都已经被初始化好了如果要调用 methods 中的方法或者操作 data 中的数据最早可以在这个阶段中操作**beforeMount**执行到这个钩子的时候在内存中已经编译好了模板了但是还没有挂载到页面中此时页面还是旧的不能直接操作页面的dom和获取dom对象**mounted**执行到这个钩子的时候就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段进入到了运行阶段。如果我们想要通过插件操作页面上的DOM节点最早可以在和这个阶段中进行beforeUpdate 当执行这个钩子时页面中的显示的数据还是旧的data中的数据是更新后的页面还没有和最新的数据保持同步**updated**页面显示的数据和data中的数据已经保持同步了都是最新的**beforeDestory**Vue实例从运行阶段进入到了销毁阶段这个时候上所有的data和 methods、指令、过滤器 ……都是处于可用状态。还没有真正被销毁destroyed 这个时候上所有的data和methods、指令、过滤器 ……都是处于不可用状态。组件已经被销毁了。3、v-if和v-show的区别**共同点**都能控制元素的显示和隐藏**不同点**实现本质方法不同v-show 本质就是通过控制css中的display设置为none控制隐藏只会编译一次v-if是动态的向DOM树内添加或者删除DOM元素若初始值为false就不会编译了。而且v-if不停的销毁和创建比较消耗性能。如果要频繁切换某节点使用v-show(切换开销比较小初始开销较大)。如果不需要频繁切换某节点使用v-if初始渲染开销较小切换开销比较大。4、v-if和v-for同时使用在同一个标签上的表现当v-if与v-for一起使用时v-for具有比v-if更高的优先级这意味着v-if将分别重复运行于每个v-for循环中。所以不推荐v-if和v-for同时使用。如果v-if和v-for一起用的话vue中的的会自动提示v-if应该放到外层去5、v-for中的key的理解需要使用key来给每个节点做一个唯一标识Diff算法就可以正确的识别此节点。主要是为了高效的更新虚拟DOM。6、vue中transition的理解1定义transition时需要设置对应的name具体语法为需要动画的内容或者组件或者页面2过渡动画主要包含6个class分别为v-enter定义元素进入过渡的初始状态在元素插入前生效插入后一帧删除v-enter-active在元素插入前生效在动画完成后删除v-enter-to在元素插入后一帧生效在动画完成后删除v-leave离开过渡的初始状态在元素离开时生效下一帧删除v-leave-active在离开过渡时生效在动画完成后删除v-leave-to离开过渡结束状态在离开过渡下一帧生效在动画完成后删除⚠️v会转化为对应的transition的name值3当然我们也可以自定义这六个class 可以直接在transition中设置对应的属性为对应的class名称属性有enter-classenter-active-classenter-to-classleave-classleave-active-classleave-to-class4在同时使用过渡和css动画的时候 可以设置type 属性来制定vue内部机制监听transitioned或者animationed事件来完成过渡还是动画的监听5如果需要设置对应的过渡时间可以直接设置属性duration可以直接接收一个数字单位为毫秒也可以接收一个对象{enter:1000,leave:300}6也可以设置过渡的钩子函数具体有before-enterenterafter-enterenter-cancelledbefore-leaveleaveafter-leaveleave-cancelled7、vue的自定义指令自定义指令分为全局指令和组件指令其中全局指令需要使用directive来进行定义组件指令需要使用directives来进行定义具体定义方法同过滤器filter或者其他生命周期具体使用方法如下全局自定义指令 directive(name,{})其中name表示定义的指令名称定义指令的时候不需要带v-但是在调用的时候需要哦带v-第二个参数是一个对象对象中包括五个自定义组件的钩子函数具体包括bind函数只调用一次指令第一次绑定在元素上调用即初始化调用一次inserted函数并绑定元素插入父级元素即new vue中el绑定的元素时调用此时父级元素不一定转化为了domupdate函数在元素发生更新时就会调用可以通过比较新旧的值来进行逻辑处理componentUpdated函数元素更新完成后触发一次unbind函数在元素所在的模板删除的时候就触发一次钩子函数对应的参数el,binding,vnode,oldnode,具体参数讲解如下a、el指令所绑定的元素 可以直接操组dom元素b、binding一个对象具体包括以下属性1name定义的指令名称 不包括v-2value指令的绑定值如果绑定的是一个计算式value为对应计算结果3oldvalue指令绑定元素的前一个值只对update和componentUpdated钩子函数有值4expression指令绑定的原始值 不对值进行任何加工5arg传递给指令的参数6modifiers指令修饰符如v-focus.show.async 则接收的modifiers为showtrueasynctruec、vnodevue编译生成的虚拟domd、oldVnode上一个vnode只在update和componentUpdated钩子函数中有效⚠️如果不需要其他钩子函数可以直接简写为directive(“focus”,function(el,binding){})8、vue的实现原理vue.js 是采用数据劫持结合发布者-订阅者模式的方式通过Object.defineProperty()来劫持各个属性的settergetter在数据变动时发布消息给订阅者触发相应的监听回调。具体步骤第一步需要observe的数据对象进行递归遍历包括子属性对象的属性都加上setter和getter这样的话给这个对象的某个值赋值就会触发setter那么就能监听到了数据变化第二步compile解析模板指令将模板中的变量替换成数据然后初始化渲染页面视图并将每个指令对应的节点绑定更新函数添加监听数据的订阅者一旦数据有变动收到通知更新视图第三步Watcher订阅者是Observer和Compile之间通信的桥梁主要做的事情是:1、在自身实例化时往属性订阅器(dep)里面添加自己2、自身必须有一个update()方法3、待属性变动dep.notice()通知时能调用自身的update()方法并触发Compile中绑定的回调则功成身退。第四步MVVM作为数据绑定的入口整合Observer、Compile和Watcher三者通过Observer来监听自己的model数据变化通过Compile来解析编译模板指令最终利用Watcher搭起Observer和Compile之间的通信桥梁达到数据变化 - 视图更新视图交互变化(input) - 数据model变更的双向绑定效果。9、vue的diff算法理解**1diff算法的作用**用来修改dom的一小段不会引起dom树的重绘**2diff算法的实现原理**diff算法将virtual dom的某个节点数据改变后生成的新的vnode与旧节点进行比较并替换为新的节点具体过程就是调用patch方法比较新旧节点一边比较一边给真实的dom打补丁进行替换3具体过程详解a、在采用diff算法进行新旧节点进行比较的时候比较是按照在同级进行比较的不会进行跨级比较b、当数据发生改变的时候set方法会调用dep.notify通知所有的订阅者watcher订阅者会调用patch函数给响应的dom进行打补丁从而更新真实的视图c、patch函数接受两个参数第一个是旧节点第二个是新节点首先判断两个节点是否值得比较值得比较则执行patchVnode函数不值得比较则直接将旧节点替换为新节点。如果两个节点一样就直接检查对应的子节点如果子节点不一样就说明整个子节点全部改变不再往下对比直接进行新旧节点的整体替换d、patchVnode函数找到真实的dom元素判断新旧节点是否指向同一个对象如果是就直接返回如果新旧节点都有文本节点那么直接将新的文本节点赋值给dom元素并且更新旧的节点为新的节点如果旧节点有子节点而新节点没有则直接删除dom元素中的子节点如果旧节点没有子节点新节点有子节点那么直接将新节点中的子节点更新到dom中如果两者都有子节点那么继续调用函数updateChildrene、updateChildren函数抽离出新旧节点的所有子节点并且设置新旧节点的开始指针和结束指针然后进行两辆比较从而更新dom调整顺序或者插入新的内容 结束后删掉多余的内容10、vue组件的通信父子组件和非父子组件父子组件通信传递参数可以使用props传递函数可以直接在调用子组件的时候传递自定义事件并使用$emit来调用例如//父组件div classsparentchild getinfomyname :userinfousermessage/childdivexport default {data(){return {usermessage:我是父亲}},methods:{myname(name){console.log(我的名字叫name)}}}//子组件div classschild来源{{userinfo}}button clickgetname显示我的名字/buttondivexport default {props:[userinfo],methods:{getname(){this.$emit(getinfo,bilibili)}}}兄弟组件通信首先建立一个vue实例空白页js文件import Vue from vueexport default new Vue()组件a数据发送方通过使用 $emit 自定义事件把数据带过去templatedivspanA组件-{{msg}}/spaninput typebutton value把a组件数据传给b click send/div/templatescriptimport vmson from ../../../util/emptyVueexport default {data(){return {msg:{a:111,b:222}}},methods:{send:function(){vmson.$emit(aevent,this.msg)}}}/script组件b数据接收方使用而通过 $on监听自定义事件的callback接收数据templatedivspanb组件,a传的的数据为-{{msg}}/span/div/templatescriptimport vmson from ../../../util/emptyVueexport default {data(){return {msg:}},mounted(){vmson.$on(aevent,(val){//监听事件aevent回调函数要使用箭头函数;console.log(val);//打印结果我是a组件的数据this.msg val;})}}/script11、vue的路由模式及区别hash模式在浏览器中符号“#”#以及#后面的字符称之为hash用window.location.hash读取特点hash虽然在URL中但不被包括在HTTP请求中用来指导浏览器动作对服务端安全无用hash不会重加载页面。history模式history采用HTML5的新特性提供了两个新方法pushStatereplaceState可以对浏览器历史记录栈进行修改以及popState事件的监听到状态变更。history 模式下前端的 URL必须和实际向后端发起请求的URL一致否则会报404错误12、vue与react、angular的比较Vue轻量级框架只关注视图层是一个构建数据的视图集合大小只有几十kb简单易学国人开发中文文档不存在语言障碍 易于理解和学习双向数据绑定保留了angular的特点在数据操作方面更为简单组件化保留了react的优点实现了html的封装和重用在构建单页面应用方面有着独特的优势视图数据结构分离使数据的更改更为简单不需要进行逻辑代码的修改只需要操作数据就能完成相关操作虚拟DOMdom操作是非常耗费性能的 不再使用原生的dom操作节点极大解放dom操作但具体操作的还是dom不过是换了另一种方式运行速度更快:相比较与react而言同样是操作虚拟dom就性能而言vue存在很大的优势。React相同点React采用特殊的JSX语法Vue.js在组件开发中也推崇编写.vue特殊文件格式对文件内容都有一些约定两者都需要编译后使用中心思想相同一切都是组件组件实例之间可以嵌套都提供合理的钩子函数可以让开发者定制化地去处理需求都不内置列数AJAXRoute等功能到核心包而是以插件的方式加载在组件开发中都支持mixins的特性。不同点React采用的Virtual DOM会对渲染出来的结果做脏检查Vue.js在模板中提供了指令过滤器等可以非常方便快捷地操作Virtual DOM。Angular相同点都支持指令内置指令和自定义指令都支持过滤器内置过滤器和自定义过滤器都支持双向数据绑定都不支持低端浏览器。不同点AngularJS的学习成本高比如增加了Dependency Injection特性而Vue.js本身提供的API都比较简单、直观在性能上AngularJS依赖对数据做脏检查所以Watcher越多越慢Vue.js使用基于依赖追踪的观察并且使用异步队列更新所有的数据都是独立触发的。13、vue-roter的钩子函数vue路由钩子大致可以分为三类:全局钩子主要包括beforeEach和aftrEach,beforeEach函数有三个参数to:router即将进入的路由对象from:当前导航即将离开的路由next:Function,进行管道中的一个钩子如果执行完了则导航的状态就是 confirmed 确认的否则为false终止导航。afterEach函数不用传next()函数这类钩子主要作用于全局,一般用来判断权限,以及以及页面丢失时候需要执行的操作,例如://使用钩子函数对路由进行权限跳转router.beforeEach((to, from, next) {const role localStorage.getItem(ms_username);if(!role to.path ! /login){next(/login);}else if(to.meta.permission){// 如果是管理员权限则可进入这里只是简单的模拟管理员权限而已role admin ? next() : next(/403);}else{// 简单的判断IE10及以下不进入富文本编辑器该组件不兼容if(navigator.userAgent.indexOf(MSIE) -1 to.path /editor){Vue.prototype.$alert(vue-quill-editor组件不兼容IE10及以下浏览器请使用更高版本的浏览器查看, 浏览器不兼容通知, {confirmButtonText: 确定});}else{next();}}})2单个路由里面的钩子主要用于写某个指定路由跳转时需要执行的逻辑3组件路由主要包括beforeRouteEnter和beforeRouteUpdate,beforeRouteLeave,这几个钩子都是写在组件里面也可以传三个参数(to,from,next),作用与前面类似.beforeRouteEnter(to, from, next) {next(vm {if (vm.$route.meta.hasOwnProperty(auth_key) vm.$route.meta.auth_key ! ) {if (!vm.hasPermission(vm.$route.meta.auth_key)) {vm.$router.replace(/admin/noPermission)}}})}14、vuex的使用Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态并以相应的规则保证状态以一种可预测的方式发生变化具体包括1stateVuex 使用单一状态树,即每个应用将仅仅包含一个store 实例但单一状态树和模块化并不冲突。存放的数据状态不可以直接修改里面的数据。2getterstate的计算属性类似vue的计算属性主要用来过滤一些数据。3actionactions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。可以异步函数调用4mutationmutations定义的方法动态修改Vuex 的 store 中的状态或数据5modules项目特别复杂的时候可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰方便管理。15、vue的filter的理解与用法1全局过滤器必须写在vue实例创建之前Vue.filter(testfilter, function (value,text) { // 返回处理后的值return valuetext})AI写代码12342局部写法在组件实例对象里挂载。filters: {changemsg:(val,text)\{ return val text}}3使用方式只能使用在{{}}和v-bind中定义时第一个参数固定为预处理的数后面的数为调用时传入的参数调用时参数第一个对应定义时第二个参数依次往后类推h3 :titletest|changemsg(1234){{test|changemsg(4567)}}/h3//多个过滤器也可以串行使用h2{{name|filter1|filter2|filter3}}/h24vue-cli项目中注册多个全局过滤器写法//1.创建一个单独的文件定义并暴露函数对象const filter1 function (val) {return val --1}const filter2 function (val) {return val --2}const filter3 function (val) {return val --3}export default {filter1,filter2,filter3}//2.导入main.js(在vue实例之前)import filters from ./filter/filter.js//3.循环注册过滤器Object.keys(filters).forEach(key{Vue.filter(key,filters[key])})16、vue的keep-alive的理解keep-alive 是Vue内置的一个组件可以使被包含的组件保留状态或避免重新渲染页面第一次进入钩子的触发顺序:created- mounted- activated退出时触发 deactivated ,当再次进入前进或者后退时只触发activated事件挂载的方法等只执行一次的放在 mounted 中组件每次进去执行的方法放在 activated 中其有几个属性如下1include - 字符串或正则表达式只有名称匹配的组件会被缓存2exclude - 字符串或正则表达式任何名称匹配的组件都不会被缓存3include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“”分隔字符串、正则表达式、数组。当使用正则或者是数组时要记得使用v-bind 。!-- 逗号分隔字符串只有组件a与b被缓存。--keep-alive includea,bcomponent/component/keep-alive!-- 正则表达式 (需要使用 v-bind符合匹配规则的都会被缓存) --keep-alive :include/a|b/component/component/keep-alive!-- Array (需要使用 v-bind被包含的都会被缓存) --keep-alive :include[a, b]component/component/keep-alive17、如何封装一个vue组件根据业务需求建立组件的模板先把架子搭起来写写样式考虑好组件的基本逻辑。准备好组件的数据输入。即分析好逻辑定好 props 里面的数据、类型。准备好组件的数据输出。即根据组件逻辑做好要暴露出来的方法。封装完毕了直接调用即可18、vue首屏白屏如何解决1路由懒加载2vue-cli开启打包压缩 和后台配合 gzip访问3进行cdn加速4开启vue服务渲染模式5用webpack的externals属性把不需要打包的库文件分离出去减少打包后文件的大小6在生产环境中删除掉不必要的console.logplugins: [new webpack.optimize.UglifyJsPlugin({ //添加-删除console.logcompress: {warnings: false,drop_debugger: true,drop_console: true},sourceMap: true}),7开启nginx的gzip ,在nginx.conf配置文件中配置http { //在 http中配置如下代码gzip on;gzip_disable msie6;gzip_vary on;gzip_proxied any;gzip_comp_level 8; #压缩级别gzip_buffers 16 8k;#gzip_http_version 1.1;gzip_min_length 100; #不压缩临界值gzip_types text/plain application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;}8添加loading效果给用户一种进度感受19、vue中的v-cloak的理解使用 v-cloak 指令设置样式这些样式会在 Vue 实例编译结束时从绑定的 HTML 元素上被移除。一般用于解决网页闪屏的问题在对一个的标签中使用v-cloak然后在样式中设置[v-cloak]样式,[v-cloak]需写在 link 引入的css中或者写一个内联css样式写在import引入的css中不起作用。20、vue中template编译的理解答就是先转化成AST树再得到的render函数返回VNodeVue的虚拟DOM节点具体为首先通过compile编译器把template编译成AST语法树abstract syntax tree 即 源代码的抽象语法结构的树状表现形式compile是createCompiler的返回值createCompiler是用以创建编译器的。另外compile还负责合并option。然后AST会经过generate将AST语法树转化成render funtion字符串的过程得到render函数render的返回值是VNodeVNode是Vue的虚拟DOM节点里面有标签名、子节点、文本等等21、v-model的理解答v-model用于表单数据的双向绑定其实它就是一个语法糖这个背后就做了两个操作1v-bind绑定一个value属性2v-on指令给当前元素绑定input事件22、computed和watch的用法和区别computed1变量不在 data中定义而是定义在computed中写法跟写方法一样有返回值。函数名直接在页面模板中渲染不加小括号 。2根据传入的变量的变化 进行结果的更新。3计算属性基于响应式依赖进行缓存。如其中的任意一个值未发生变化它调用的就是上一次计算缓存的数据因此提高了程序的性能。而methods中每调用一次就会重新计算一次为了进行不必要的资源消耗选择用计算属性。watch1计算属性的时候 初始化的时候就可以被监听到并且计算 但是watch是发生改变的时候才会触发。2当有一些数据需要随着其它数据变动而变动时或者当需要在数据变化时执行异步或开销较大的操作时使用 watch。总结1计算属性变量在computed中定义属性监听在data中定义。2计算属性是声明式的描述一个值依赖了其他值依赖的值改变后重新计算结果更新DOM。属性监听的是定义的变量当定义的值发生变化时执行相对应的函数。23、$nextTick的使用答在vue中理解修改数据后对应的dom需要一定的时间进行更新因此为了能够准确的后去更新后的dom可以采用延迟回调的方法进行更新dom的获取所以出现了$nextTick来进行延迟回调。即在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法获取更新后的 DOM。24、data为什么是一个函数答这是有JavaScript的特性所导致在component中data必须以函数的形式存在不可以是对象。组建中的data写成一个函数数据以函数返回值的形式定义这样每次复用组件的时候都会返回一份新的data相当于每个组件实例都有自己私有的数据空间它们只负责各自维护的数据不会造成混乱。而单纯的写成对象形式就是所有的组件实例共用了一个data这样改一个全都改了。25、vue单页面和传统的多页面区别单页面应用SPA通俗一点说就是指只有一个主页面的应用浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候还是会分开写页面片段然后在交互的时候由路由程序动态载入单页面的页面跳转仅刷新局部资源。多应用于pc端。多页面MPA指一个应用中有多个页面页面跳转时是整页刷新单页面的优点用户体验好快内容的改变不需要重新加载整个页面基于这一点spa对服务器压力较小前后端分离页面效果会比较炫酷比如切换页面内容时的专场动画。单页面缺点不利于seo导航不可用如果一定要导航需要自行实现前进、后退。由于是单页面不能用浏览器的前进后退功能所以需要自己建立堆栈管理初次加载时耗时多页面复杂度提高很多。26、vue常用的修饰符**.stop**等同于JavaScript中的event.stopPropagation()防止事件冒泡**.prevent**等同于JavaScript中的event.preventDefault()防止执行预设的行为如果事件可取消则取消该事件而不停止事件的进一步传播**.capture**与事件冒泡的方向相反事件捕获由外到内**.self**只会触发自己范围内的事件不包含子元素**.once**只会触发一次。