Vue学习总结(待补充)
1.说说vue的双向数据绑定实现原理(vue响应式原理)?
答:(初始化时通过解析器Compile初始化视图,并添加属性订阅、绑定更新函数)通过监听器Observer使用Object.definerProperty来劫持各个数据的属性,如果属性发上变化,就需要通过消息订阅器Dep告诉相应的订阅者Watcher属性变化,从而更新视图View(但是使用Object.definerProperty实现监听时是有一些痛点的,比如,①无法监测数组变化,导致数组使用删除或者插入元素方法时,数组的变化无法实时响应;Vue是通过重写数组的这些方法来实现数据的劫持的 ②必须遍历对象的每个属性来实现监听。vue3.0采用的Proxy,就完全避开了Object.definerProperty方法的这些痛)。
双向数据绑定简单实现
<body> <p id="p"></p> <input type="text" id="foo"> <script> var user = {} Object.defineProperty(user,'inputValue',{ configurable:true, get:function(){ return inputValue }, set:function(value){ inputValue = value } }) let p = document.getElementById('p') let foo = document.getElementById('foo') foo.addEventListener('input',function(e) { user.inputValue = e.target.value p.innerText = user.inputValue }) </script> </body>
2.vue如何在组件之间进行传值?
答:props(父组件向子组件传值,不能在子组件中改变props)、calback、$on、$emit(子组件调用父组件的方法并传递数据)、eventbus(事件总线,兄弟组件之间传值)、vuex
3.vuex和vue的双向数据绑定有什么冲突?
答:在vue中我们使用v-model来修改vuex.state中的数据,没有经过mutation函数.在严格模式中会抛出错误
解决方案:1.在input中value绑定(vuex中的state),然后监听input的change或者input事件,在事件回调中调用mutation修改state的值
2.使用带有setter的双向绑定计算属性
4.vue-router中的history模式和hash模式的区别?
答:hash
模式:#以及#后面的字符称之为hash
,用 window.location.hash
读取。特点:hash
虽然在URL
中,但不被包括在HTTP
请求中;用来指导浏览器动作,对服务端安全无用,hash
不会重加载页面。
history
模式:history
采用HTML5
的新特性;且提供了两个新方法: pushState()
, replaceState()
可以对浏览器历史记录栈进行修改,以及popState
事件的监听到状态变更
5.说一下vue的生命周期?
答:beforeCreate:组件实例被创建之初,组件属性生效之前。
created:组件实例已经完全创建,属性也绑定,但真实dom还没有生成,$el还不可用。
beforeMount:在挂载开始之前被调用,相关的render函数首次被调用。
mounted:DOM元素挂载到页面之后。
beforeUpdate: 数据更新之前调用,发生在虚拟DOM打补丁之前。
updated: 虚拟 DOM 重新渲染和打补丁之后调用。
activited:keep-alive专属,组件被激活时使用。
deactivated:keep-alive专属,组件被销毁时调用。
beforeDestroy:在组件实例销毁之前调用,所有实例仍可以调用。
destroyed:在实例销毁之后调用,所有实例被销毁。
6.路由懒加载的作用?
答:懒加载即在需要的时候才进行加载,随用随载。在单页面应用中,如果没有应用懒加载,webpack打包后的文件会非常大,导致第一次进入首页时,加载时间过长,不利于用户体验。而运用懒加载可以将页面进行划分,需要的时候才加载页面,可以有效的分担首页所承受的加载压力,有效减少了加载用时。
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus() } })
局部注册
directives: { focus: { // 指令的定义 inserted: function (el) { el.focus() } } }
8.混入(Mixin)?
答:混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
9.父子组件生命周期的执行顺序?
答:父beforeCreate-->父created-->父beforeMount-->子beforeCreate-->子created-->子beforeMount-->子mounted-->父mounted
父beforeUpdate->子beforeUpdate->子updated->父updated
父 beforeUpdate -> 父 updated
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
10.如何阻止组件间的样式相互干扰?
答:给style标签添加scoped属性
11.对虚拟dom的了解,说说实现原理?
答:可以看作是使用javascript模拟DOM结构的树形结构对象。对于开发者而言,频繁的操作DOM结构会造成浏览器的回流或者重绘,这些都是性能的杀手,而虚拟dom可以通过diff算法进行新旧DOM的对比,然后给真实DOM打补丁,从而减少实际操作DOM的次数,达到性能优化的目的。
12.什么是回流和重绘?它们的区别?
答:当render tree中的一部分因为布局改变而需要重新构建,这就是回流(reflow),每个页面在第一次加载时一定会回流,因为要构建render tree,在回流的时候浏览器会使渲染树中受到影响的一部分失效,重新进行构造,回流结束后,浏览器会重新绘制到屏幕中,这就是重绘,同样在render tree中只是改变风格样式,不改变布局的,也是重绘。也就是回流毕引起重绘,而重绘不一定会引起回流
13.vue的diff算法?
答:同级比较,再比较子节点。
先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)
比较都有子节点的情况
递归比较子节点
14.v-show和v-if的区别?
答:v-show和v-if都能控制元素的显示和隐藏,但是v-show本质就是通过设置css中的display控制元素的显示和隐藏。而v-if是动态的向DOM树内添加或者删除DOM元素.
v-if的切换开销比较高,而v-show初始渲染开销,所以看情况使用。
15.vue中如何监听数组的变化?
答:vue重写了数组的push、splice、pop等方法,通过执行ob.dep.notify()
将当前数组的变更通知给其订阅者,数组订阅者会将这边变化更新到页面中
16.谈谈keep-alive?
答:keep-alive
可以实现组件缓存,保留组件状态或避免重新渲染,当组件切换时不会对当前组件进行卸载。
17.为什么data要设置成函数?
答:一个组件被复用多次的话,也就会创建多个实例,因为都是同一个构造函数,而且data作为一个对象,如果不使用函数返回,则每个实例使用的都是同一个内存的引用地址,一个数据改变了其他也改变了,而js中只有函数构成作用域,每个实例的作用域都是独立的,互相不受影响。
18.Computed和Watch的区别?
答:computed
是计算属性,依赖其他属性计算值,并且 computed
的值有缓存,只有当计算值变化才会返回内容。
watch
监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。
所以一般来说需要依赖别的属性来动态获得值的时候可以使用 computed
,对于监听到值的变化需要做一些复杂业务逻辑的情况可以使用 watch
。
19.能讲一讲MVVM吗?
答:MVVM是Model-View-ViewModel
缩写,也就是把MVC
中的Controller
演变成ViewModel
。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。
$route
是“路由信息对象”,包括path
,params
,hash
,query
,fullPath
,matched
,name
等路由信息参数。
而$router
是“路由实例”对象包括了路由的跳转方法,钩子函数等
21.NextTick?
nextTick
可以让我们在下次 DOM 更新循环结束之后执行延迟回调,基于更新后的 DOM进行操作。
22.路由之间跳转?
声明式(标签跳转)
编程式( js跳转)
23.Vuex 有哪几种属性?
有 5 种,分别是 state、getter、mutation、action、module
24.Vuex 的 Store特性是什么?
vuex 就是一个仓库,仓库里放了很多对象。其中 state 就是数据源存放地,相当于 vue 里面的 data,state 里面存放的数据是响应式的,vue 组件从 store 读取数据,若是 store 中的数据发生改变,依赖这些数据的组件也会发生更新
25.Vuex 的 Getter 特性是什么?
getter 可以对 state 进行计算操作,它就是 store 的计算属性
虽然在组件内也可以做计算属性,但是 getters 可以在多给件之间复用
如果一个状态只在一个组件内使用,是可以不用 getters
26.Vuex 的 Mutation Action 特性是什么?
action 类似于 muation, 不同在于:action 提交的是 mutation,而不是直接变更状态
action 可以包含任意异步操作
27.不用 Vuex 会带来什么问题?
可维护性会下降,你要修改数据,你得维护 3 个地方
可读性下降,因为一个组件里的数据,你根本就看不出来是从哪里来的
增加耦合,大量的上传派发,会让耦合性大大的增加,本来 Vue 用 Component 就是为了减少耦合,现在这么用,和组件化的初衷相背
28.Store 是如何实现注入Vue?
Vue.use(Vuex) 方法执行的是 install 方法,它实现了 Vue 实例对象的 init 方法封装和注入,使传入的 store 对象被设置到 Vue 上下文环境的$store 中。因此在 Vue Component 任意地方都能够通过 this.$store 访问到该 store。
29.Vuex实现原理?
Vuex初始化时会为每一个vue实例添加Vuex.Store实例,Vue.Store实例中存储了state、action、getter、mutation相关数据,通过调用commit、dispatch修改state中的值,同时绑定数据,实现对数据的监听。
30.你都做过哪些Vue的性能优化?
编码阶段:
长列表动态加载
SPA 页面采用keep-alive缓存组件
key不使用数组下标,保证唯一
v-if和v-for不能连用
防抖、节流
图片、路由懒加载
尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
打包优化:
代码压缩
图片压缩
Tree Shaking(树摇)
使用cdn加载第三方模块,减少打包后的体积(打包时,把vue、vuex、vue-router、axios等,换用国内的bootcdn 直接引入到根目录的index.html中)
第三方模块按需加载
其他:
服务端开启gzip压缩
31.vue路由钩子函数?
路由钩子函数有三种:
1:全局钩子函数( beforeEach、 afterEach),无论访问哪一个路径,都会触发全局的钩子函数,位置是调用router的方法(router.beforeEach() 进入之前,router.afterEach() 进入之后触发)。
2:单个路由里面的钩子函数(beforeEnter、 beforeLeave),写在路由配置中,只有访问到这个路径,才能触发钩子函数。
3:组件路由(beforeRouteEnter、 beforeRouteUpdate、 beforeRouteLeave),写在组件中,访问路径,即将渲染组件的时候触发的。
32.vue内置组件有哪些?
1)component:用于动态组件
2)transition:过渡和动画,为组件的载入和切换提供动画效果
3)transition-group:作为多个元素/组件的过渡效果
4)keep-alive:包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
5)slot:用于给组件定义一个插槽,在这个插槽里传入内容
33.vue如何封装一个组件?
● 首先,使用template创建一个组件
● 然后,全局或者局部注册组件
● 接着,如果子组件需要数据,可以在props中接受定义
● 最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法
34.请求前后拦截可以做些什么?
当我们发起请求或者请求回来的时候,我们需要做一定的数据过滤或者拦截, 或者加载一个loading, 或者是针对于404、500等状态码报错, 跳转到指定的路径中。
35.vue路由传参有哪些方式?
第一种:直接调用$router.push实现携带参数的跳转,但是需要对应路由中添加/:id来对应参数。页面刷新数据不会丢失。
第二种:通过$router.push传递对象,name来确定匹配的路由,params来传递参数。在跳转组件中,通过this.$route.params.id
来获取参数。页面刷新数据会丢失。
第三种:通过$router.push传递对象,使用path来匹配路由,然后通过query来传递参数,query传递的参数会显示在url后面,通过this.$route.query.id
来获取参数。
36.vue初始化如何执行watch监听以及深度监听如何实现?
给监听对象绑定了一个handler方法,设置immediate属性为true,在初始化的时候触发watch。设置deep为true开启深度监听。
37.computed中的getter和setter?
prop
都使得其父子 prop
之间形成了一个单向下行绑定:父级 prop
的更新会向下流动到子组件中,但是反过来则不行。