当前位置:   article > 正文

深入理解vue_vue深入理解

vue深入理解

谈一下你对MVVM原理的理解

  • 传统的mvc指的是用户操作会请求服务器路由,也就是后端路由,然后路由调用对应的控制器来获取数据,再将结果返回前端进行渲染。
  • mvvm模式则不需要用户去操作dom元素,而是通过viewmodel将数据进行渲染到页面上。同样,当数据发生改变时,viewmodel也会收到通知,从而将视图层的更改同步到数据中。

响应式数据的原理

理解:

  • 核心点:Object.defineProperty

  • 默认vue在初始化数据时,利用es5的 Object.defineProperty重新定义vue实例中的所有属性,当页面取到对应属性时,会进行依赖收集(收集当前组件的watcher)如果属性发生变化会通知相应的依赖更新操作。

vue检测数组的变化

首先明确数组并没有使用Object.defineProperty去重新定义数组的每一项,它是使用函数劫持的方式,重写了数组的方法。vue将data中的数组进行原型链的重写,指向了自己定义的数组原型方法,这样当调用数组返回api时,可以通知依赖更新,如果数组中包含着引用类型,会对数组中的引用类型再次进行监控。

Computed和watch的差异

  • computed 是计算一个新的属性,并将该属性挂载到 Vue 实例上,而 watch 是监听已经存在且已挂载到 Vue 实例上的数据,所以用 watch 同样可以监听 computed 计算属性的变化。
  • computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值。而 watch 则是当数据发生变化便会调用执行函数。
  • 从使用场景上说,computed 适用一个数据被多个数据影响,而 watch 适用一个数据影响多个数据。

Vue的生命周期

Vue 的生命周期指的是组件从创建到销毁的一系列的过程,被称为 Vue 的生命周期。通过提供的 Vue 在生命周期各个阶段的钩子函数,我们可以很好的在 Vue 的各个生命阶段实现一些操作。

  1. beforeCreate ,在实例初始化之后,在数据监听和事件配置之前触发。因此在这个事件中我们是获取不到 data 数据的。
  2. created ,在实例创建完成后触发,此时可以访问 data、methods 等属性。但这个时候组件还没有被挂载到页面中去,所以这个时候访问不到 $el 属性。一般我们可以在这个函数中进行一些页面初始化的工作,比如通过 ajax 请求数据来对页面进行初始化。
  3. beforeMount ,在组件被挂载到页面之前触发。相关的render函数首次被调用。
  4. mounted ,在组件挂载到页面之后触发。此时可以通过 DOM API 获取到页面中的 DOM 元素。
  5. beforeUpdate ,在响应式数据更新时触发,发生在虚拟 DOM 重新渲染和打补丁之前,这个时候我们可以对可能会被移除的元素做一些操作,比如移除事件监听器。
  6. updated ,虚拟 DOM 重新渲染和打补丁之后调用该钩子。
  7. beforeDestroy ,在实例销毁之前调用。一般在这一步我们可以销毁定时器、解绑全局事件等。
  8. destroyed,在实例销毁之后调用,调用后,Vue 实例中的所有东西都会解除绑定,所有的事件监听器会被移除,所有的子实例也会被销毁,并且该钩子函数在服务器渲染器件不被调用。

当我们使用 keep-alive 的时候,还有两个钩子函数,分别是 activated 和 deactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 actived 钩子函数。

ajax请求放在哪个生命周期中

在created的时候,视图的dom并没有渲染出来,所以此时如果直接去操作dom节点,并没有办法找到。
在mounted中,由于此时dom已经渲染出来了,所以可以直接操作dom,一般情况下都放在mounted中,保证逻辑的统一性,因为生命周期是同步执行的,而ajax是异步执行的。但是由于服务端渲染不支持mounted方法,因此在服务端渲染的情况下统一放到created中。

Vue 组件间的参数传递方式

  1. 父子组件间通信

    第一种方法是子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。
    
    第二种是通过 ref 属性给子组件设置一个名字。父组件通过 $refs 组件名来获得子组件,子组件通过 $parent 获得父组件,这样也可以实现通信。
    
    • 1
    • 2
    • 3
  2. 兄弟组件间通信

    第一种是使用 eventBus 的方法,它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。
    
    第二种是通过 $parent.$refs 来获取到兄弟组件,也可以进行通信。
    
    • 1
    • 2
    • 3
  3. 任意组件之间

    使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。
    
    如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候采用上面这一些方法可能不利于项目的维护。这个时候可以使用 vuex ,vuex 的思想就是将这一些公共的数据抽离出来,将它作为一个全局的变量来管理,然后其他组件就可以对这个
    公共数据进行读写操作,这样达到了解耦的目的。
    
    • 1
    • 2
    • 3
    • 4

v–if和v-show

  • v-if如果条件不成立不会渲染当前指令所在的节点的dom元素。
  • v-show只是切换当前dom的显示或者隐藏。

v-if每次切换都会重新渲染dom节点,也就是往dom树增添或者删除节点,具有较高的切换性能消耗。而v-if实际上只是改变dom节点的样式的display,具有较高的初次渲染性能消耗。

什么是 Virtual DOM以及为什么Virtual DOM 比原生 DOM 快

  • 虚拟dom首先对我们将要插入到文档中的 DOM 树结构进行分析,使用 js 对象将其表示出来,比如一个元素对象,包含 TagName、props 和 Children 这些属性。然后我们将这个 js 对象树给保存下来,最后再将 DOM 片段插入到文档中。

  • 当页面的状态发生改变,我们需要对页面的 DOM 的结构进行调整的时候,我们首先根据变更的状态,重新构建起一棵对象树,然后将这棵新的对象树和旧的对象树进行比较,记录下两棵树的的差异。

  • 最后将记录的有差异的地方应用到真正的 DOM 树中去,这样视图就更新了。

比较两个 DOM 树的差异的方法

  • 两个树的完全 diff 算法的时间复杂度为 O(n^3) ,但是在前端中,我们很少会跨层级的移动元素,所以我们只需要比较同一层级的元素进行比较,这样就可以将算法的时间复杂度降低为 O(n)。

  • 算法首先会对新旧两棵树进行一个深度优先的遍历,这样每个节点都会有一个序号。在深度遍历的时候,每遍历到一个节点,我们就将这个节点和新的树中的节点进行比较,如果有差异,则将这个差异记录到一个对象中。

  • 在对列表元素进行对比的时候,由于 TagName 是重复的,所以我们不能使用这个来对比。我们需要给每一个子节点加上一个 key,列表对比的时候使用 key 来进行比较,这样我们才能够复用老的 DOM 树上的节点。

v-for中为什么要用key

  • vue中的diff算法主要是同级比较,他会比较当前标签上的key还有标签名,如果key和标签名都一样则认为节点是一样的。所以当标签有key时,就可以提高diff算法的比较,当数据内容发生变化时,更新的是节点的位置,而节点中的内容则不发生改变。当发生数据的增添的时候,则是插入新的节点。
  • 当列表渲染没有key属性时,dom节点实际上是就地复用的,可以理解为,当内容发生变化时,是更新dom节点里面的内容,而不是更新dom节点的位置。

引用链接:
《做面试的不倒翁:浅谈 Vue 中 computed 实现原理》 https://juejin.im/post/5b98c4da6fb9a05d353c5fd7
《Virtual DOM》https://juejin.im/book/5bdc715fe51d454e755f75ef/section/5bdc72e6e51d45054f664dbf
《vue 生命周期深入》 https://juejin.im/entry/5aee8fbb518825671952308c

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/114717
推荐阅读
相关标签
  

闽ICP备14008679号