在这些题目中,我涵盖了各种不同的主题,包括vue2的基本概念、指令、组件、生命周期、状态管理等等。我也包括了一些常见的面试题目,例如vue2与其他框架的比较、vue2的优化等等。
区别
总结:v-if判断是否加载,可以减轻服务器的压力,在需要时加载,但有更高的切换开销;v-show调整DOM元素的CSS的dispaly属性,可以使客户端操作更加流畅,但有更高的初始渲染开销。如果需要非常频繁地切换,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好。
可以,利用对象设置的方式设置多个监听事件
v-model绑定的修饰符主要包括:lazy、trim、number
不管是class类样式还是style行内样式,要进行动态样式绑定都需要进行表达式的返回操作,而class绑定时表达式返回的结果可以是:字符串、对象、数组,并且数组中可以包含的内容包括字符串与对象类型。
而style绑定时表达式返回的结果是:对象、数组,数组中包含的是对象。
不能
key值在列表渲染的时候,能够提升列表渲染性能,为什么呢?首先得想想Vue的页面是如何渲染的,主要分为以下几步:
key值的作用就在第二步,当数据改变触发渲染层重新渲染的时候,会校正带有key的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。key值如果不指明,默认会按数组的索引来处理,因而会导致一些类似input等输入框组件的值出现混乱的问题。
因而,在做list渲染时,如果list的顺序发生变化时,最好增加key,且不要简单的使用数组索引当做key,需要用唯一值当成key。
如果后台接口返回的循环数据没有唯一值,那么可以在客户端利用map循环对原数组内容进行遍历,然后返回经处理过带有唯一值的数组列表,那么在v-for循环的时候依旧设置的是唯一值数据。
methods,watch和computed都是以函数为基础的,但各自却都不同
总结:在computed、methods、watch方面,一个是计算,一个是调用、一个是观察,在语义上是有区别的。计算是通过变量计算来得出数据,调用是方法的重复执行,而观察是观察一个特定的值。
可以
{{compuntedFn(arg)}}computed:{compuntedFn:function(){returnfunction(arg){return"compuntedResult"};},},15.Vue实例中最为重要的三大部分是什么?不管是Vue也好或者其它的框架也罢,基本上面向对象以及组件化开发中实例对象都包含三个主要部分内容:
属性、事件是对象本身的操作,而方法一般交由第三方去操作对象本身内容,比如点击按钮去修改对象的属性操作。
块状内容在页面中将不会进行块状标签的输出
在进行组件化项目开发的时候都会存在一个组件的生命周期概念,像Vue、React、小程序等等,无一例外,而通常情况组件的生命周期主要分成三个阶段,包括:创建、更新以及销毁阶段。
Vue的生命周期钩子函数主要包括:
我们通常在created()/mounted()进行发送ajax请求,启动定时器等异步任务,而在beforeDestory()做收尾工作,如:清除定时器操作。
不过需要注意的是mounted生命周期钩子中并不代表界面已经渲染成功,因为mounted不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在mounted内部使用vm.$nextTick。
Vue的生命周期钩子函数又分为了:单个组件生命周期、父子组件的生命周期、带缓存的路由组件生命周期等不同的状态,在不同的状态下所拥有的生命周期内容是不相同的。
单个组件生命周期初始化:
更新:
销毁:
beforeDestroy
destroyed
父子组件的生命周期初始化:
beforeCreate
created
beforeMount
mounted
更新:
beforeUpdate
--childbeforeUpdate
--childupdated
updated
销毁:
带缓存的路由组件生命周期初始化:
...
activated
路由离开
路由回来
--Childactivated
捕获子组件错误的勾子子组件执行抛出错误
errorCaptured
不能。
所有生命周期钩子函数都可以找到this对象内容,但却并不一定能够访问到想要的this对象属性,在beforeCreate实例初始化之后调用,data和methods都还没有初始化完成,通过this不能访问响应式数据与对应的方法内容,但因为store、router等对象内容是在入口文件中进行挂载的,那么在组件的beforeCreate钩子函数中是通过获取到对应的对象内容的,所以可以在beforeCreate钩子函数中进行类似route当前路由对象的参数内容获取操作。
ref与Dom对象需要在mounted钩子函数中才能找到,而在mounted钩子函数中并不能确保页面都已经被渲染成功,所以还需要利用nextTick来进行DOM对象是否最终存在,而在destroyed钩子函数中因为组件的销毁,ref以及dom对象内容将不再能够获取。
组件间的关系主要分成:父与子、子与父、祖与孙以及非父子之间的关系,正是因为存在组件之间的不同关系也就意味着它们之间会存在一定的数据传递操作,而组件之间的数据传递方式主要可以归纳为如下10多种实现:
不同于$parent、$children、$refs,$root获取的并不是VueComponent组件实例,而是Vue实例对象,所以我们不能够直接获取到this.$root的data数据内容以及调用this.$root的方法
Vue的动画方式主要分成两大类,一类是CSS动画,一类是JS动画
CSS动画中包含transition以及animation,但在Vue中只需要通过transition封装组件实现。
CSS动画的类名主要包括:v-enter、v-enter-active、v-enter-to、v-leave、v-leave-active、v-leave-to
transition只允许有一个元素内容,appear、type、duration、mode等属性可以进行动画操作的设置
in-out:新元素先进行过渡,完成之后当前元素过渡离开。
out-in:当前元素先进行过渡,完成之后新元素过渡进入。
一般情况下可以利用animate.css动画库内容进行CSS动画功能的实现
JS动画仍旧操作的是transition组件
列表动画可以利用transition-group进行实现
组件、过滤器、自定义指令的注册方式都包含全局与局部注册两种
定义filter过滤器的函数第一个参数是需要过滤的对象内容,但假若在使用filter过滤器方法的时候想要传递参数,那么定义的filter过滤器的函数参数将从第一个参数内容开始获取。
过滤器可以进行多个拼接使用,利用|管道符进行拼接,需要注意的是后面的过滤器操作的主体是前一个过滤器操作的结果值,特别需要注意前一个过滤结果的数据类型内容,以免引起类型操作错误。
个指令定义对象可以提供如下几个钩子函数(均为可选):bind、inserted、update、componentUpdated、unbind
对应钩子函数的参数主要包括:el、binding(属性:name、value、oldValue、expression、arg、modifiers)、vnode、oldVnode
static和assets的区别,原理就在于webpack是如何处理静态资源的
总结:assets里面的资源会被webpack打包进代码,static里面的资源就直接引用了,一般在static里放一些类库的文件,assets放属于项目的资源文件。
Vue中的表单重置不像HTML的表单重置,只需要对form表单进行reset即可,因为Vue中的表单重置可能需要显示初始化的表单数据内容。
如果需要需要重置某个data的节点属性,那么可以指明对应的节点内容Object.assign(this.$data.formSelectObj,this.$options.data())
插槽是一种组件间html传递的策略,实现父组件向子组件传递标签内容。插槽的类型主要包括:普通插槽、具名插槽以及作用域插槽
对于作用域插槽是在父组件需要向子组件传递标签结构内容,但决定父组件传递怎样标签结构的数据是在子组件中。在Vue2.6版本以后,新版本插槽的语法比起老版本区别略有区别,主要可以利用#slotName={property}的方式进行简化缩写。
slot="插槽的名字"+slot-scope="{要收集的数据-1,要收集的数据-2}"=v-slot:插槽名字="{要收集的数据-1,要收集的数据-2}"=#插槽名字="{要收集的数据-1,要收集的数据-2}"34.组件的类型及特点有哪些?如果想要对组件进行类型划分,从实现的功能以及所具备的特点来划分,大致可以归纳为:动态组件、缓存组件、异步组件、函数式组件+JSX、递归组件等
动态组件:通过动态确定要显示的组件,is指定要显示组件的组件名
缓存组件:即可以利用component,也可以使用router-view
路由组件对象什么时候死亡
异步组件
函数式组件+JSX,与Vue的Component概念有明显不同,更雷同于React中的函数式组件
exportdefault{functional:true,//当前是函数组件render(createElement,context){return要显示界面的虚拟DOM}}递归组件,组件内部有自己的子组件标签,简单的说就是组件自已调用自身
在以往的项目开发中,包括使用不同技术栈的项目内容,例如nodejs的express、Vue项目、React项目、小程序项目等都涉及到了路由的概念与操作。虽然这些项目归属于不同的技术体系,但路由的核心概念都是一致的,我也做了相应的归纳,总结出5个词进行了概括:静态路由表、分配地址、统一入口、寻址渲染,过滤判断。当然,对于不同的技术体系,路由的表现与配置方式会有所差异与不同。
路由的具体操作又表现在:操作模式、跳转方式、参数的传递、嵌套处理、守卫管理、懒加载及动态路由等方面。
导航守卫是什么
导航守卫分类主要包括:
当点击切换路由时:beforeRouterLeave-->beforeEach-->beforeEnter-->beforeRouteEnter-->beforeResolve-->afterEach-->beforeCreate-->created-->beforeMount-->mounted-->beforeRouteEnter的next的回调
当路由更新时:beforeRouteUpdate
最为常用的路由守卫应当是全局守卫中的beforeEach,因为在用户权限认证操作过程中都会需要该守卫操作的处理,而用户权限又是每个项目中不可缺少的一部分。
答:vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要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变更的双向绑定效果。
keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。它有两个属性:include(包含的组件缓存)与exclude(排除的组件不缓存,优先级大于include)。
使用方法
使用示例
scrollBehavior:function(to){if(to.hash){return{selector:to.hash}}},42.你如何理解vuex?vuex的5大属性:内容作用映射位置调用其它state设置状态mapStatecomputedgetters获取内容mapGetterscomputed计算数据后返回mutations修改数据mapMutationsmethodscommit可以异步但不建议,不利调试actions异步操作mapActionsmethodsdispatchmodules模块拆分namespaced43.vuex中的namespaces是什么?它的主要作用是什么?在Vuex模块中开启namespaced以后,确定该模块为带命名空间的模块。当模块被注册后,它的所有state、getter、action及mutation都会自动根据模块注册的路径调整命名。
刷新页面Vuex的state会丢失,可以利用vuex-persist、vuex-persistedstate状态持久化插件将state数据存储于本地存储对象当中,比如localStorage。
项目的发解、学习与掌握也是有一定的顺序与方法的,主要的流程包括如下几个步骤:
项目性能优化的方面包含很多,针对Vue项目的优化可以介绍几种类型的内容,主要包括:Vue代码层面的优化、webpack配置层面的优化、基础的Web技术层面的优化、用户体验优化等
代码层面的优化:
Webpack层面的优化
基础的Web技术层面的优化
不可以,只能用name和params配置的组合,query配置可以与path或name进行组合使用
path:'/search/:keyword',利用号设定
不指定params或者指定params参数值为undefined
可以:可以将query或params参数映射成props传递给路由组件对象
//在routes中配置props:route=>({keyword1:route.params.keyword,keyword2:route.query.keyword})55.编程式路由跳转到当前路由(参数不变),会抛出NavigationDuplicated的警告错误面试问题::在做项目时有没有遇到比较难的问题(可做回答)
回答步骤:
我的问题:我在上一个项目时没有问题,后面再做一个新的项目时就有了问题
原因分析:vue-router3.1.0之后,引入了push()的promise的语法,如果没有通过参数指定回调函数就返回一个promise来指定成功/失败的回调,且内部会判断如果要跳转的路径和参数都没有变化,会抛出一个失败的promise
解决办法:解决1:在跳转时指定成功或失败的回调函数,通过catch处理错误
解决2:修正Vue原型上的push和replace方法(优秀)
//缓存原型上的push方法constoriginPush=VueRouter.prototype.pushVueRouter.prototype.push=function(location,onComplete,onAbort){console.log('push()',location,onComplete,onAbort)//this是路由器对象$router//如果调用push,传递了成功或者失败的回调函数if(onComplete||onAbort){//让原来的push方法进行处理originPush.call(this,location,onComplete,onAbort)//不用返回,因为执行的结果返回是undfined}else{//如果调用push,没传递了成功或者失败的回调函数,可能会抛出失败的promise,需要catch一下returnoriginPush.call(this,location).catch(()=>{console.log('catcherror')})//必须返回产生的promise对象}}56.是否有对axios进行二次封装?主要的封装功能包括哪些?
配置通用的基础路径和超时:
axios.create({baseURL,timeout})
显示请求进度条
显示:准备发请求前显示,在请求拦截器中执行NProgress.start()
隐藏:请求结束隐藏,在响应拦截器成功/失败回调中NProgress.done()
携带token数据
在请求拦截器中,将token添加到请求头中
成功返回的数据不再是response,而直接是响应体数据response.data
响应拦截器成功的回调中:returnresponse.data
统一处理请求错误,具体请求也可以选择处理或不处理
在响应拦截器失败的回调中:alert提示错误信息,returnPromise.reject(error)
问题:针对某个swiper界面创建一个swiper对象,它会影响了其它界面的swiper界面
原因:newSwiper('.swiper-container'),类名选择器匹配了页面中所有的swiper界面,都产生了效果
解决:使用ref技术:通过ref标识swiper的根div,newSwiper(this.$refs.swiper)
场景:当我们需要覆盖element-ui等UI框架中组件的样式时可以通过深度作用选择器
.a>>>.b{...}style使用css的预处理器(less,sass,scss)的写法如下/deep/.a{...}/*/deep/在某些时候会报错,::v-deep更保险并且编译速度更快*/::v-deep.a{...}60.利用深拷贝解决修改不能取消的问题在对某数据进行修改时考虑还需要进行“确认”、“取消”操作,那么在取消时就需要返回保留的数据内容,那么如何将原有数据保留一份则是关键性问题。
mounted(){consttimer=setInterval(()=>{console.log(1)},1000)this.$once('hook:beforeDestroy',()=>{//监听beforeDestroy这个钩子函数clearInterval(timer)})}65.请说一下computed中的getter和settercomputed中可以分成getter(读取)和setter(设值),一般情况下是没有setter的,computed预设只有getter,也就是只能读取,不能改变设值。
默认只有getter的写法
setter的写法,可以设值
注意:并不是触发了setter也就会触发getter,他们两个是相互独立的。我们这里修改了fullName会触发getter是因为setter函数里有改变firstName和lastName值的代码,这两个值改变了,fullName依赖于这两个值,所以便会自动改变。
可以利用监控或者组件的路由守卫功能实现
监控模式:
可以,利用vuex-router-sync可以将vuex与router对象进行同步,将当前的$route同步为vuex状态的一部分,我们甚至可以利用修改vuex的路由状态来进行路由地址的跳转与参数传递
commit('route/ROUTE_CHANGED',{to:{path:'/b'}})73.如何对lodash库实现按需引入import_from'lodash'//引入整体lodash==>打包了没用的工具函数,打包文件变大importthrottlefrom'lodash/throttle'//只引入我需要的工具函数打包文件减少1.4M74.如何实现跨域配置在vue.config.js中对devServer进行属性配置
如果向外暴露对象的话,对象中必须有install方法
如果向外暴露的是函数的话,那么该函数本身就是install方法
当Vue.use()的时候,会自动调用install方法,并且将Vue对象作为实参传入到install方法中
通过配置webpack来解决:在devServer中加historyApiFallback:true
webpack.config.js需要output上增加publicPath:'/'
通过设置路由的meta属性,添加路由title标题
利用路由全局守卫可以进行拦截并修改标题设置
router.beforeEach=((to,from,next))=>{ window.document.title=to.meta.title; next();});79.什么是Props传递数据防脏所有的props都使得其父子组件形成一个单向下行绑定,父级props的更新会流动到子组件中,但反过来不行。这种设计办法是为了防止子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解。另外,如果该数据还被其他子组件使用,也将受影响,产生洪水式灾难。因此不应该在子组件中设计修改props数据的操作。
利用update:myPropName的方式进行数据防脏处理
/*动态加载vuex中所有的modules模块不再需要通过import手动一个一个引入*/constcontext=require.context('./modules',false,/\.js$/)constmodules=context.keys().reduce((modules,modulePath)=>{//'./app.js'=>'app'constmoduleName=modulePath.replace(/^\.\/(.*)\.\w+$/,'$1')modules[moduleName]=context(modulePath).defaultreturnmodules},{})85.addRoutes的作用与应用场景addRoutes可以实现动态路由的添加操作
应用场景:根据用户权限判断展示不同路由菜单项
router.addRoutes([...asyncRoutes,lastRoute]);86.不同路由同一组件的重用如果设置不同的路由,但指向的是同一组件,那么因为组件性能考虑及缓存策略,组件并不会刷新,那么如何实现组件的刷新重用呢?
alertType:{validator:value=>['signup','login','logout'].includes(value)}88.如何实现组件的刷新?一般情况组件的state状态或者是props发生改变时就会进行刷新渲染,但有时需要进行用户控制,那么有哪些方法呢:
location.reload()这种也是一样,画面一闪,体验不是很好,相当于页面刷新
推荐解决方法:用provide/inject组合
注入reload方法
exportdefault{inject:['reload'],}在需要重载的地方直接调用
this.reload()90.表单提交时如何阻止页面刷新?表单提交时为了防止页面刷新需要进行默认事件的阻止处理,可以利用submit.prevent进行实现。
所谓的动态表单就是根据数据库动态获取的字段配置信息生成表单模块,这一操作在产品的SKU管理,还有OA,ERP系统中应用广泛。
比如有父组件Parent和子组件Child,如果父组件监听到子组件挂载mounted就做一些逻辑处理,可以通过以下写法实现:
修改vue.config.js配置,configureWebpack属性中加入externals,将对应的类库抽离,需要在index.html中加入对应的cdn文件。
module.exports={publicPath:'./',configureWebpack:{//此处可以配置cdn配置//需要在index.html中引入cdn文件externals:{vue:'Vue','vue-router':'VueRouter',vuex:'vue','element-ui':'ELEMENT'}}}95.首屏性能优化一般有哪些方案?异步路由加载不打包库文件关闭sourcemap开启gzip压缩单独SSR页面生成96.什么是XSRF攻击,Vue中如何做好相应的安全策略?Cross-siterequestforgery跨站请求伪造,也被称为“OneClickAttack”或者SessionRiding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。CSRF定义的主语是”请求“,是一种跨站的伪造的请求,指的是跨站伪造用户的请求,模拟用户的操作。
SPU=StandardProductUnit(标准化产品单元)
SPU是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。通俗点讲,属性值、特性相同的商品就可以称为一个SPU。
SKU=stockkeepingunit(库存量单位)
SKU即库存进出计量的单位,可以是以件、盒、托盘等为单位。
SKU是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。在服装、鞋类商品中使用最多最普遍。
直接利用store进行单个调用:this.$store.dispatch(‘moduleName/run’,command);
利用mapActions映射,空间模块直接映射方式
mapActions(['some/nested/module/foo','some/nested/module/bar'])空间模块调用方式:
this['some/nested/module/foo']()this['some/nested/module/bar']()