当前位置:   article > 正文

Vue中级面试题汇总(一)_前端中级面试题 vue

前端中级面试题 vue

Vue在created和mounted这两个生命周期中请求数据有什么区别呢?

在created中,页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态,DOM节点没出来,无法操作DOM节点。在mounted不会这样,比较好。

说说你对keep-alive的理解 

keep-alive是一个抽象组件:它自身不会渲染一个DOM元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。 

其有三个参数

  • include定义缓存白名单,会缓存的组件;
  • exclude定义缓存黑名单,不会缓存的组件;
  • 以上两个参数可以是逗号分隔字符串、正则表达式或一个数组,include="a,b":include="/a|b/":include="['a', 'b']"
  • 匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配;
  • max最多可以缓存多少组件实例。一旦这个数字达到了,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉;
  • 不会在函数式组件中正常工作,因为它们没有缓存实例;
  • 当组件在内被切换,它的activated和deactivated这两个生命周期钩子函数将会被对应执行。

v-if和v-for的优先级是什么?如果这两个同时出现时,那应该怎么优化才能得到更好的性能? 

当它们处于同一节点,v-for的优先级比v-if更高,这意味着v-if将分别重复运行于每个v-for循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用。 

  1. <ul>
  2. <li v-for="item in items" v-if="item.show">{{item}}</li>
  3. </ul>

 如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template>)上。

  1. <ul v-if="items.length">
  2. <li v-for="item in items">{{item}}</li>
  3. </ul>

 使用v-for遍历对象时,是按什么顺序遍历的?如何保证顺序?

按Object.keys()的顺序的遍历,转成数组保证顺序。 

在v-for中使用key,会提升性能吗,为什么? 

主要看v-for渲染的是什么。 

如果渲染是一个简单的列表,如不依赖子组件状态或临时DOM状态(例如:表单输入值)的列表渲染输出,不用key性能会更好,因为不用key采用的是“就地更新”的策略。如果数据项的顺序被改变, Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素。

  1. <template>
  2. <div>
  3. <span v-for="item in lists">{{item}}</span>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. data() {
  9. return {
  10. lists: [1, 2, 3, 4, 5]
  11. }
  12. },
  13. }
  14. </script>

 以上的例子,v-for的内容会生成以下的DOM节点数组,我们给每一个节点标记一个身份id,以辨别节点的位置:

  1. [
  2. '<span>1</span>', // id: A
  3. '<span>2</span>', // id: B
  4. '<span>3</span>', // id: C
  5. '<span>4</span>', // id: D
  6. '<span>5</span>' // id: E
  7. ]

 将lists中的数据进行位置调换,变成[2,4,3,1,5],在没有key的情景下,节点位置不变,但是节点的内容更新了,这就是“就地更新”

  1. [
  2. '<span>2</span>', // id: A
  3. '<span>4</span>', // id: B
  4. '<span>3</span>', // id: C
  5. '<span>1</span>', // id: D
  6. '<span>5</span>' // id: E
  7. ]

 但是在有key的情景下,节点位置进行了交换,但是内容没有更新

  1. [
  2. '<span>2</span>', // id: B
  3. '<span>4</span>', // id: D
  4. '<span>3</span>', // id: C
  5. '<span>1</span>', // id: A
  6. '<span>5</span>' // id: E
  7. ]

 如果渲染不是一个简单的列表,用key性能会更好一点,因为vue是采用diff算法来对比新旧虚拟节点来更新节点,在diff算法中,当新节点跟旧节点头尾交叉对比没有结果时,先处理旧节点生成一个健为key,值为节点下标index的map映射,如果新节点有key,会通过map映射找到对应的旧节点,如果新节点没有key,会采用遍历查找的方式去找到对应的旧节点,一种一个map映射,另一种是遍历查找。相比而言。map映射的速度更快。

  1. // vue源码 src/core/vdom/patch.js 488行
  2. // 以下是为了阅读性进行格式化后的代码
  3. // oldCh 是一个旧虚拟节点数组
  4. // oldKeyToIdx map映射对象
  5. // idxInOld 对比后得到旧节点下标
  6. if (isUndef(oldKeyToIdx)) {
  7. oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
  8. }
  9. if (isDef(newStartVnode.key)) {
  10. // map 方式获取
  11. idxInOld = oldKeyToIdx[newStartVnode.key]
  12. } else {
  13. // 遍历方式获取
  14. idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
  15. }

 创建map函数

  1. function createKeyToOldIdx(children, beginIdx, endIdx) {
  2. let i, key
  3. const map = {}
  4. for (i = beginIdx; i <= endIdx; ++i) {
  5. key = children[i].key
  6. if (isDef(key)) map[key] = i
  7. }
  8. return map
  9. }

 遍历寻找函数

  1. // sameVnode 是对比新旧节点是否相同的函数
  2. function findIdxInOld(node, oldCh, start, end) {
  3. for (let i = start; i < end; i++) {
  4. const c = oldCh[i];
  5. if (isDef(c) && sameVnode(node, c)) return i
  6. }
  7. }

 key除了在v-for中使用,还有什么作用?

还可以强制替换元素/组件而不是重复使用它。在以下场景可以使用

  • 完整地触发组件的生命周期钩子
  • 触发过渡
  1. <transition>
  2. <span :key="text">{{ text }}</span>
  3. </transition>

 当 text 发生改变时,<span>会随时被更新,因此会触发过渡。

使用key要什么要注意的吗? 

  • 不要使用对象或数组之类的非基本类型值作为key,请用字符串或数值类型的值;

  • 不要使用数组的index作为key值,因为在删除数组某一项,index也会随之变化,导致key变化,渲染会出错。

    例:在渲染[a,b,c]用 index 作为 key,那么在删除第二项的时候,index 就会从 0 1 2 变成 0 1(而不是 0 2),随之第三项的key变成1了,就会误把第三项删除了。

说说组件的命名规范

组件命名有两种方式,一种是使用链式命名my-component,一种是使用大驼峰命名MyComponent,

  • 在字符串模板中<my-component></my-component><MyComponent></MyComponent>都可以使用,

  • 在非字符串模板中最好使用<MyComponent></MyComponent>,因为要遵循W3C规范中的自定义组件名

(字母全小写且必须包含一个连字符),避免和当前以及未来的 HTML 元素相冲突。

为什么组件中data必须用函数返回一个对象? 

对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。 

Vue父子组件双向绑定的方法有哪些? 

  • 通过在父组件上自定义一个监听事件<myComponent @diy="handleDiy"></myComponent>,在子组件用this.$emit('diy',data)来触发这个diy事件,其中data为子组件向父组件通信的数据,在父组件中监听diy个事件时,可以通过$event访问data这个值。
  • 通过在父组件上用修饰符.sync绑定一个数据<myComponent :show.sync="show"></myComponent>,在子组件用this.$emit('update:show',data)来改变父组件中show的值。
  • 通过v-model

 组件的name选项有什么作用?

  • 递归组件时,组件调用自身使用;
  • is特殊特性和component内置组件标签时使用;
  • keep-alive内置组件标签中include exclude属性中使用。

什么是递归组件?举个例子说明下? 

递归引用可以理解为组件调用自身,在开发多级菜单组件时就会用到,调用前要先设置组件的name选项, 注意一定要配合v-if使用,避免形成死循环,用element-vue组件库中NavMenu导航菜单组件开发多级菜单为例: 

  1. <template>
  2. <el-submenu :index="menu.id" popper-class="layout-sider-submenu" :key="menu.id">
  3. <template slot="title">
  4. <Icon :type="menu.icon" v-if="menu.icon"/>
  5. <span>{{menu.title}}</span>
  6. </template>
  7. <template v-for="(child,i) in menu.menus">
  8. <side-menu-item v-if="Array.isArray(child.menus) && child.menus.length" :menu="child"></side-menu-item>
  9. <el-menu-item :index="child.id" :key="child.id" v-else>
  10. <Icon :type="child.icon" v-if="child.icon"/>
  11. <span>{{child.title}}</span>
  12. </el-menu-item>
  13. </template>
  14. </el-submenu>
  15. </template>
  16. <script>
  17. export default{
  18. name: 'sideMenuItem',
  19. props: {
  20. menu: {
  21. type: Object,
  22. default(){
  23. return {};
  24. }
  25. }
  26. }
  27. }
  28. </script>

说下$attrs$listeners的使用场景?

  • $attrs: 包含了父作用域中(组件标签)不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。 在创建基础组件时候经常使用,可以和组件选项inheritAttrs:false和配合使用在组件内部标签上用v-bind="$attrs"将非prop特性绑定上去;
  • $listeners: 包含了父作用域中(组件标签)的 (不含.native) v-on 事件监听器。 在组件上监听一些特定的事件,比如focus事件时,如果组件的根元素不是表单元素的,则监听不到,那么可以用v-on="$listeners"绑定到表单元素标签上解决。

EventBus注册在全局上时,路由切换时会重复触发事件,如何解决呢? 

在有使用$on的组件中要在beforeDestroy钩子函数中用$off销毁。

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

闽ICP备14008679号