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循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用。 

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

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

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

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

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

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

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

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

<template>
    <div>
        <span v-for="item in lists">{{item}}</span>
    </div>
</template>
<script>
export default {
    data() {
        return {
            lists: [1, 2, 3, 4, 5]
        }
    },
}
</script>

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

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

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

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

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

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

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

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

 创建map函数

function createKeyToOldIdx(children, beginIdx, endIdx) {
    let i, key
    const map = {}
    for (i = beginIdx; i <= endIdx; ++i) {
        key = children[i].key
        if (isDef(key)) map[key] = i
    }
    return map
}

 遍历寻找函数

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

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

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

  • 完整地触发组件的生命周期钩子
  • 触发过渡
<transition>
  <span :key="text">{{ text }}</span>
</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导航菜单组件开发多级菜单为例: 

<template>
    <el-submenu :index="menu.id" popper-class="layout-sider-submenu" :key="menu.id">
        <template slot="title">
            <Icon :type="menu.icon" v-if="menu.icon"/>
            <span>{{menu.title}}</span>
        </template>
        <template v-for="(child,i) in menu.menus">
            <side-menu-item v-if="Array.isArray(child.menus) && child.menus.length" :menu="child"></side-menu-item>
            <el-menu-item :index="child.id" :key="child.id" v-else>
                <Icon :type="child.icon" v-if="child.icon"/>
                <span>{{child.title}}</span>
            </el-menu-item>
        </template>
    </el-submenu>
</template>
<script>
    export default{
        name: 'sideMenuItem',
        props: {
            menu: {
                type: Object,
                default(){
                    return {};
                }
            }
        }
    }
</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销毁。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值