前端科举八股文-VUE篇
- Vue响应式的基本原理?
- computed和watch的区别
- computed和methods的区别
- [Slot是什么 ? 作用域插槽是什么?](#Slot是什么 ? 作用域插槽是什么?)
- [组件缓冲keep-alive是什么? 讲讲原理](#组件缓冲keep-alive是什么? 讲讲原理)
- v-if,v-show的区别
- v-modal如何实现双向绑定
- 组件中的data属性为什么是一个函数而不是对象?
- [nextTick的用法?](#nextTick的用法?)
- vue是如何实现数组的响应式的?追问:为什么不重写全部方法?
- 单页面应用和多页面应用?
- 追问为什么SPA应用不利于SEO
- vue如何解析template的。
- vue的自定义指令
- vue的单项数据流为什么不推荐子组件直接改变父组件数据?
- Vue的依赖收集过程
- [vue react的异同](#vue react的异同)
- 父子组件的生命周期执行顺序
- Vue之间的组件通信
- Vue路由懒加载原理
- 常见的路由守卫钩子
- Vue的基本概念
- 为什么不能在mutations里面进行异步操作?
- 什么是虚拟dom?
- 虚拟dom一定比真实dom性能更好吗?
- vue3.0和vue2.0的区别?
- v-for中key的作用?
Vue响应式的基本原理?
在vue2的版本中,是使用defineProperty的get和set方法来实现数据的响应式,具体实现是遍历data里面的每一个key,在get里面实现依赖收集,收集当前key关联的所有组件.在set方法里面调用key对应的更新方法来实现响应式更新.但是由于defineProperty的局限性.vue3的版本中使用proxy来取代definepropperty来实现响应式.局限性是vue2无法监听未初始化的key的响应式以及通过下标或者length直接操作的数组.
computed和watch的区别
Computed是计算属性,具有缓存性,computed依赖的响应式值不更新computed就不会更新会一直使用缓存值.
对于watch,它接受一个值,一个回调函数,不支持缓存,在响应式值改变时就会立即触发回调函数.
它们的适用场景不同
当一个复杂数据依赖其他数据计算的时候,为了避免每次渲染时候重复计算浪费性能应该使用computed计算属性
当需要在响应式数据改变时执行某些逻辑应该使用watch监听函数
computed和methods的区别
当一个值需要其他响应式对象配合来计算时可以同时使用computed计算属性或methods方法来实现,区别是computed具有缓存性,而methods每次都会重新计算.
Slot是什么 ? 作用域插槽是什么?
插槽,官方说明是一个内容分发机制,当需要在同一个组件内部展示不同的内容时可以使用slot插槽讲需要差异化显示的内容填充进去.
因为插槽默认的作用域是指向父组件,作用域插槽是指讲子组件的数据分发到外层供父组件使用的一个api.
组件缓冲keep-alive是什么? 讲讲原理
keep-alive是可以保存组件状态的一个api,缓存组件在显示和隐藏时不是走created和destroy生命周期,而是使用actived和deactive生命周期,它的作用是缓存组件的状态,比如输入框的值,响应式data等。
原理:keep-alive组件在使用的时候有3个props,includes,excludes,includes来过滤掉需要缓存和不需要缓存的组件,需要传入的是组件的name值,在底层会根据过滤之后来判断当前组件是否需要缓存,如果需要缓存就将name对应的组件写入缓存,等到使用的时候直接从缓存中拿出对应的vdom进行渲染,第三个参数是max,表示最大缓存实例。底层采用的是LRU算法,如果超过最大缓存实例,vue会将最不常用的组件踢出缓存同时将新组件写入缓存。
v-if,v-show的区别
两者都是条件渲染页面元素的api,区别是v-if是移除整个dom节点,v-show通过display来控制元素的渲染。所以v-show有更高的初始化开销,v-if 有更高的切换开销
v-modal如何实现双向绑定
v-modal实际上是v-bind:value和v-on:input的语法糖,v-modal实现原理实际上是通过v-on:input来监听输入事件,然后通过input的回调拿到最新的值复制给v-bind的value从而实现双向绑定
组件中的data属性为什么是一个函数而不是对象?
因为在js中,只有函数才能生成局部作用域,才能把每个组件的data相互隔离,如果直接使用对象的话,所有组件都会共享一个data属性从而造成污染。
$nextTick的用法?
在vue中数据更新引发的视图更新是异步的,所以在数据更新后立马操作dom是无法直接拿到最新的值的,所以如果有需要立马拿到更新之后的值的需求,可以通过$nextTick api。它的实现原理是通过H5的oberveMutation api,这是一个监听dom元素是否变化的api,然后根据兼容性依次取promise.then、 setTimeout来实现。它的本质是对js执行机制eventloop的一种应用
vue是如何实现数组的响应式的?追问:为什么不重写全部方法?
是通过重写数组的七个方法来实现数组的响应式。pop,shift,unshift,push,splice,sort,reverse。因为只有这七个方法改变了原数组
单页面应用和多页面应用?
单页面应用(SPA,SINGLE PAGE APPLICATION)顾名思义,整个应用只有一个页面,路由切换时根据url来切换到页面的不同锚点从而实现不同页面的渲染。多页面应该的实现是切换页面的时候再去加载页面所需要的资源,再去进行渲染。总体来说各有优劣,单页面应用由于首屏渲染需要加载页面全部的资源,所以spa的首屏加载是比较慢的。单页面应用页面切换会比多页面更加丝滑流畅,因为不需要再加载页面对应的资源。缺陷是SPA应用是不利于SEO的。
追问为什么SPA应用不利于SEO
这和SEO的工作方式有关,搜索引擎首先会用爬虫去爬取静态页面的内容,然后将网页存储到数据库,在用户搜索时在根据算法筛选出相关内容进行推送。但是由于SPA应用的网页内容是由JS生成的,比如Vue,所以在爬虫爬取网页的时候是爬不到具体内容的,现代的浏览器虽然也可以执行JS去生成动态内容,但是这个速度是比较慢的,所以说SPA是不利于SEO的。
vue如何解析template的。
vue官方有个webpack插件vue-loader,专门用来解析.vue后缀的文件,首先vue会将template模版转译成AST,也就是抽象语法书,再将ast作为参数传入render函数中,最终生成生成vdom进行渲染。
vue的自定义指令
就是一种让开发者自定义Vue-api的官方接口,可以让我们自己生成类似于v-bind,v-on之类的指令。他的语法是Vue.derective(),接收两个参数,第一个参数是指令名,第二个参数是生命周期hook,按顺序依次是bind,指令首次被绑定时,insert 组件插入父节点,update,组件更新时,unbind 组件卸载时
vue的单项数据流为什么不推荐子组件直接改变父组件数据?
因为在vue中是一个单向下行的数据流向,一个父组件的数组可能被多个自组件所引用,如果在子组件中改变数据引发父组件数据的变化可能会同时影响到其他子组件的数据渲染异常。为了避免这种不可控的情况,vue在子组件中改变props会爆出警告,正确的方法应该是emit一个事件,让父组件自己去执行。
Vue的依赖收集过程
在初始化组件的时候,会递归的遍历组件的data属性,通过defineproperty来实现数据的响应式,然后在渲染模版数据的时候会触发数据的get方法,从而完成依赖收集,所谓依赖收集就是把响应式数据以及相关的组件绑定,然后在更新数据触发set方法的时候触发绑定的更新函数完成视图的更新
vue react的异同
相同点
都把主要的功能放在核心库中 其他的路由或者状态管理放在第三方库中
都有自己的构建工具可以快速生成一个最佳项目模版
都使用了virtualdom提高渲染性能
都推荐将应用组件化编程,并且都实现了组件之间传参
不同
Vue有双向绑定的api,但是react实现双向绑定需要开发者手动实现
Virtualdom的实现方式不同,vue通过依赖收集可以在更新时更精确的更新对应的组件,而react会递归的更新组件以及所有子组件
编写模版的方式不同 vue使用更贴近于html语法的template模版语法,react通过jsx来编写组件结构.
由于react组件本质就是函数,所以可以轻易的实现高阶组件,而vue需要通过mixin来实现.
父子组件的生命周期执行顺序
创建
父beforeCreated
父created
父beforeMounted
子beforeCreated
子created
子beforeMounted
子mounted
更新
父beforeUpdate
子beforeUpdate
子updated
父updated
销毁
父beforeDestroyed
子beforeDestroyed
子destroyed
父destroyed
Vue之间的组件通信
父子之间的props通信
跨多层级的可以用attrs和$listener
跨层级还可以用inject和provider依赖注入
中央事件总线eventBus
vuex
Vue路由懒加载原理
利用webpack的代码分割 codeSplite和es6的动态加载实现
hash模式和history模式区别
Hash模式url上有#号符号, 它是利用路由的hash值去进行匹配显示页面.
History是利用h5的history Api来实现的,具体是利用pushState来实现页面跳转显示,会有兼容性的问题,如果服务端没有做兼容的话,刷新会造成404.
常见的路由守卫钩子
全局路由的有beforeEach afterEach
单个路由内的有beforeEnter
组件内的有beforeRouterEnter beforeRouteLeave
Vue的基本概念
States 状态库
mutations 同步改变状态
actions 异步改变状态
getters 状态的get方法
modules 模块化组件
为什么不能在mutations里面进行异步操作?
Vue中所有异步操作的唯一途径都是通过mutations,即使是action,也是在执行完异步任务之后通过mutation去改变状态,因为这样是能被devtool开发工具捕获到状态改变的流程,可以方便改变每一个状态的改变.
什么是虚拟dom?
本质上是一个描述真实dom节点的一个js对象,由于真实dom节点往往参杂了很多内置属性,导致节点比较"重",用虚拟dom来描述真实dom就会显得比较轻量化,而且在dom更新的时候使用虚拟dom结合diff算法来动态化的计算出需要更新的节点会使dom更新更加高效.
虚拟dom一定比真实dom性能更好吗?
不一定,只是说在绝大部分的业务场景下提供更好的性能,因为虚拟dom的会结合diff算法来计算页面的变更部分,有一个比较的过程,但是如果直接操作dom的话,innerHtml无疑会比diff算法更加高效,比如在首次渲染页面时,直接操作dom的渲染流程是浏览器接受到渲染任务-〉开始渲染,而接入了虚拟dom之后的流程之后变成了浏览器接受到了渲染任务-〉构建虚拟dom-〉开始渲染.
vue3.0和vue2.0的区别?
1、Vue3.使用proxy取代了defineproperty来实现了数据的响应式,原因是definproperty响应式对象有缺陷,而且vue2响应式数组需要通过重写数组方法,但是使用proxy可以不用对对象和数组响应式分开处理
2、vue3对diff算法进行了优化,vue2会同级的比较每一个vdom节点,vue3会把不存在动态更新的vdom打上静态标记,以便在diff算法比较的过程中跳过这些节点提高性能
Vue3使用了ES6的模块系统实现了模块的按需导入,不需要的部分被tree Shaking掉了,体积比Vue2更小了
Vue2只支持选项式新增组件,Vue3提供了组合式新增组件的api
v-for中key的作用?
Vue在执行diff算法比较vdom时,会执行patch方法,patch方法会接受两个参数,分别是更新前后的vdom.首先会比较两个vdom是否相同,相同的vdom就会走复用流程提高效率,而比较vdom是否相同仅仅就比较两者的type以及key,算法就会默认两者的key相同从而误判定复用导致页面渲染异常.