面试题之vue面试笔记

211 阅读3分钟

1.生命周期:

 主要分为8个生命周期:
 beforeCreate,created,beforeMounted,mounted,beforeUpdate,updated,beforeDestreoy,destoryed
 beforeCreate:执行Vue(),调用initLifecycle(),初始化一些vm的基本属性,比如$parent,$child等
             调用initEvents(),初始化一些关于事件的属性,比如_event。
             调用initRender(),初始一些渲染函数。以及一些浅属性的响应。比如($attrs,$listener)
 created:当回调beforeCreate以后继续初始化data,methods等属性,并进行watch等监听.这个时候就可以访问data,方法等属性了。
 beforeMount:当vm.$option.el有值以后就开始挂载,render方法已经被首次调用,相关data已经转化为Html函数.此时还不能获取DOM元素,详细可以使用document.getElementById尝试
 mounted:挂载完成创建$el和双向绑定,完成DOM和渲染
 beforeDestoryed:销毁前,实例依旧可用
 destroyed:在实例销毁后调用,
 父子组件的生命周期的执行顺序:父beforeCreate,父Created,父beforeMount,子beforeCreate,子created,子beforeMount,子mounted,父组件Mounted.父组件beforeDestroy-子组件beforeDestroy-子组件destoryed-父组件destroyed。

image.png

2.为什么组件内的data是函数?

首先因为组件是复用的,所以必须有自己的作用域,而且js只有全局作用域和函数作用域,没有对象作用域的说法。

3.Vue的双向绑定原理

vue采用的数据劫持结合发布者-订阅模式,通过Object.defineProperty()来劫持各个属性的setter,getter等,在数据变动时发布消息给订阅者,触发响应的回调。主要步骤有:
1.Object.defineProperty来劫持各个数据的gettersetter,当给这个数据赋值时,就会触发setter,就会触发watcher的监听(dep.notify())
2.compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
3.watcher是Combile和Observe中间的桥梁,主要做的事情有:1.在自身实例化时往属性里面添加自己.2.自身有个update方法。3.待属性变动时,通过dep.notice调动自己的Update方法,并触发combile的回调
https://juejin.cn/post/6906396798282104840<br/>
https://juejin.cn/post/6908959621466030094<br/>

4.assets和static的区别

assets中的文件在运行打包命令时会进行体积压缩,打包之后也会放到static中,而static中的文件不会被打包

5.v-clock指令解决页面闪屏问题

当网络延迟或者加载缓慢时,很容易出现未编译的源代码显示。使用V-Clock指令可以使编译后v-clock的样式从Html上移除.
eg:<div v-clock><br/>
    <a>{{text}}</a><br/>
    </div>
 [v-clock]{display:none}

6.HOOK Event是什么?一般应用在什么场景?实现原理是什么?

1.Hook Event 是 Vue 的自定义事件结合生命周期钩子实现的一种从组件外部为组件注入额外生命周期方法的功能。
2.一般实现场景为外部组件需要监听子组件的生命周期函数调用后执行某些策略
3.初始化eventsMixin($on)事件时,如果发现组件有hook:xx等事件时,会将_hasHookEvent 置为true,表示该组件有 Hook Event,执行钩子函数如果_hasHookEvent为true,会向外部弹射一个vm.$emit('hook:' + hook)事件。
源码如下:
初始化时
export function eventsMixin (Vue: Class<Component>) {
  const hookRE = /^hook:/
  Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
    const vm: Component = this
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        vm.$on(event[i], fn)
      }
    } else {
      (vm._events[event] || (vm._events[event] = [])).push(fn)
      // optimize hook:event cost by using a boolean flag marked at registration
      // instead of a hash lookup
      if (hookRE.test(event)) {
        vm._hasHookEvent = true
      }
    }
    return vm
  }
 执行生命周期钩子时
export function callHook (vm: Component, hook: string) {
  // #7573 disable dep collection when invoking lifecycle hooks
  pushTarget()
  const handlers = vm.$options[hook]
  const info = `${hook} hook`
  //执行生命周期
  if (handlers) {
    for (let i = 0, j = handlers.length; i < j; i++) {
      invokeWithErrorHandling(handlers[i], vm, null, vm, info)
    }
  }
  //如果有hook钩子函数
  if (vm._hasHookEvent) {
    vm.$emit('hook:' + hook)
  }
  popTarget()
}

7.vue通信方式

1.props / $emit 适用 父子组件通信
2.$refs,$parent$children
3.eventBus总线通信,适合兄弟等
4.provide,inject隔代通信
5.$attrs/$listeners,$attrs包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定,包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器
6.vuex通信

8.用过mixin吗?能简单说说它的原理吗?

用过,mixin一般用于一些可以复用的业务场景。目前我的项目关于表格的分页等方法以及属性都是由mixin实现的。
权重:组件选项(A)>组件mixin(B)>mixin的子mixin(C)>全局选项(D)
关于data属性:A>B>C>D
关于生命周期函数执行顺序:D<C<B<A
关于filters等:权重小于的会放到权重大的原型链上。
关于watch,computed,props,methods等:会直接使用权重大的覆盖权重小的。

9.为什么不能使用index作为key?

因为vue使用的是虚拟DOM比较,而在比较中有一个比较致命的方法。
function sameVnode (a, b) {
  return (
    a.key === b.key && (
      (
        a.tag === b.tag &&
        a.isComment === b.isComment &&
        isDef(a.data) === isDef(b.data) &&
        sameInputType(a, b)
      ) || (
        isTrue(a.isAsyncPlaceholder) &&
        a.asyncFactory === b.asyncFactory &&
        isUndef(b.asyncFactory.error)
      )
    )
  )
}
即只要两个vnode的key相同,在简单的v-for循环中,两个节点就会判定为一致。即就地复用。导致数据展示错误.