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打包后的文件会非常大,导致第一次进入首页时,加载时间过长,不利于用户体验。而运用懒加载可以将页面进行划分,需要的时候才加载页面,可以有效的分担首页所承受的加载压力,有效减少了加载用时。

7.自定义指令?
答:Vue自定义指令和组件一样存在着全局注册和局部注册两种方式。
全局注册
// 注册一个全局自定义指令 `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层更新数据。

 20.Route和Router的区别?

$route是“路由信息对象”,包括pathparamshashqueryfullPathmatchedname等路由信息参数。

$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?

在 Vue 中,computed 的属性可以被视为是 data 一样,可以读取和设值,因此在 computed 中可以分成 getter(读取) 和 setter(设值),一般情况下是没有 setter 的,computed 默认设置只有 getter。
38.vue的单向数据流?
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
39.v-if和v-for的优先级?
v-for比v-if优先
40.什么时候用到watch?
父组件向子组件传递data数据,如果数据在父组件中改变,就需要在子组件中手动监听这个变化,就用到了watch。
结合这个食用更佳
posted @ 2020-09-23 20:27  sykeswh  阅读(52)  评论(0编辑  收藏  举报