Vue中级面试题汇总

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

参考答案 在created中,页面视图未出现,若是请求信息过多,页面会长时间处于白屏状态,DOM节点没出来,没法操做DOM节点。在mounted不会这样,比较好。

v-model的原理是什么?

参考答案
<template>
    <div>
        <my-component v-model="value"></my-component>
        <!-- 等同 -->
        <my-component :value="value" @input="value=$event"></my-component>
        <button @click="value=true">显示</button>
    </div>
</template>
<script>
    export default{
        data(){
            return{
                value:false,
            }
        },
        components:{
            myComponent:resolve =>require(['./my_component'],resolve),
        }
    }
</script>
复制代码
<template>
    <div v-show="value">
        <span>个人组件</span>
        <button @click="$emit('input',false)">隐藏</button>
    </div>
</template>
<script>
    export default{
        props:{
            value:{
                type:Boolean,
                default:false,
            }
        },
        data(){
            return{}
        },
    }
</script>
复制代码

说说你对keep-alive的理解

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

其有三个参数css

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

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

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

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

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

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

在v-for中使用key,会提高性能吗,为何?

参考答案

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

  • 若是渲染是一个简单的列表,如不依赖子组件状态或临时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,请用字符串或数值类型的值;npm

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

    例:在渲染[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('updata:show',data)来改变父组件中show的值。
  • 经过v-model

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

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

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

参考答案

递归引用能够理解为组件调用自身,在开发多级菜单组件时就会用到,调用前要先设置组件的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>
复制代码

说说你对slot的理解?slot使用场景有哪些?

参考答案

组件的插槽功能

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

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

说说你对provide和inject的理解

参考答案

组件的依赖注入

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

参考答案

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

Vue组件里写的原生addEventListeners监听事件,要手动去销毁吗?为何?

参考答案

要,否则会形成屡次绑定和内存泄露。关于移除事件监听的坑

Vue组件里的定时器要怎么销毁?

参考答案
  • 若是页面上有不少定时器,能够在data选项中建立一个对象timer,给每一个定时器取个名字一一映射在对象timer中, 在beforeDestroy构造函数中for(let k in this.timer){clearInterval(k)}
  • 若是页面只有单个定时器,能够这么作。
    const timer = setInterval(() =>{}, 500);
    this.$once('hook:beforeDestroy', () => {
       clearInterval(timer);
    })
    复制代码

Vue中能监听到数组变化的方法有哪些?为何这些方法能监听到呢?

参考答案
  • push()pop()shift()unshift()splice()sort()reverse(),这些方法在Vue中被从新定义了,故能够监听到数组变化;
  • filter()concat()slice(),这些方法会返回一个新数组,也能够监听到数组的变化。

在Vue中那些数组变化没法监听,为何,怎么解决?

参考答案
  • 利用索引直接设置一个数组项时;

  • 修改数组的长度时。

    • 第一个状况,利用已有索引直接设置一个数组项时Object.defineProperty()能够监听到,利用不存在的索引直接设置一个数组项时Object.defineProperty()不能够监听到,可是官方给出的解释是因为JavaScript的限制,Vue不能检测以上数组的变更,其实根本缘由是性能问题,性能代价和得到的用户体验收益不成正比。
    • 第二个状况,缘由是Object.defineProperty()不能监听到数组的length属性。
  • this.$set(this.items, indexOfItem, newValue)this.items.splice(indexOfItem, 1, newValue)来解决第一种状况;

  • this.items.splice(newLength)来解决第二种状况。

在Vue中那些对象变化没法监听,为何,怎么解决?

参考答案
  • 对象属性的添加
  • 对象属性的删除

由于Vue是经过Object.defineProperty来将对象的key转成getter/setter的形式来追踪变化,但getter/setter只能追踪一个数据是否被修改,没法追踪新增属性和删除属性,因此才会致使上面对象变化没法监听。

  • this.$set(this.obj,"key","newValue")来解决第一种状况;
  • Object.assign来解决第二种状况。

删除对象用delete和Vue.delete有什么区别?

参考答案
  • delete:只是被删除对象成员变为' 'undefined,其余元素键值不变;
  • Vue.delete:直接删了对象成员,若是对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开 Vue 不能检测到属性被删除的限制。

watch和计算属性有什么区别?

参考答案
  • watch:一个数据影响多个数据,当须要在数据变化时执行异步或开销较大的操做时;
  • 计算属性:一个数据受多个数据影响。

计算属性和方法有什么区别?

参考答案
  • 计算属性:是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会从新求值。
  • 方法:每当触发从新渲染时,调用方法将总会再次执行函数。当咱们不但愿有缓存,可使用方法,可是若是求值开销大时建议用计算属性。

过渡动画实现的方式有哪些?

参考答案

你有写过自定义指令吗?自定义指令的生命周期(钩子函数)有哪些?

参考答案

自定义指令的钩子函数

手写一个自定义指令及写出如何调用

参考答案

注册一个让字体颜色闪烁的指令v-color

Vue怎么定义全局方法

参考答案

有三种

  • 挂载在Vue的prototype上

    // base.js
    const install = function (Vue, opts) {
        Vue.prototype.demo = function () {
            console.log('我已经在Vue原型链上')
        }
    }
    export default {
        install
    }
    复制代码
    //main.js
    //注册全局函数
    import base from 'service/base';
    Vue.use(base);
    复制代码
  • 利用全局混入mixin

  • this.$root.$on绑定方法,用this.$root.$off解绑方法,用this.$root.$emit全局调用。

    this.$root.$on('demo',function(){
        console.log('test');
    })
    this.$root.$emit('demo');
    this.$root.$off('demo');
    复制代码

说说你对DOM选项el、template、render的理解?

参考答案
  • el:提供一个在页面上已存在的DOM元素做为Vue实例的挂载目标。能够是CSS选择器,也能够是一个HTMLElement实例。
    • 由于全部的挂载元素会被Vue生成的DOM替换。所以不推荐挂载Vue实例到或者上。
    • 若是在const vm = new Vue({})中存在这个选项,实例将当即进入编译过程,不然,须要显式调用vm.$mount()手动开启编译。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">我是el挂载的内容:小明今年{{age}}岁了</div>
    </body>
    <script>
        const vm= new Vue({
            el:'#app',
            data:{
                age:17
            },
        }
    </script>
</html>
复制代码
<script>
    const vm= new Vue({
        data:{
            age:17
        },
    })
    vm.$mount('#app')
</script>
复制代码

  • template:一个字符串模板做为Vue实例的标识使用。若是el存在,模板将会替换挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。
    • 若是值以 # 开始,则它将被用做选择符,并使用匹配元素的 innerHTML 做为模板。
<script>
    const vm= new Vue({
        el:'#app',
        data:{
            age:17
        },
        template:'<div>我是template的内容:小明今年{{age}}岁了</div>',
    })
</script>
复制代码
<script type="x-template" id="mb">
	<div>我是template的内容:小明今年{{age}}岁了</div>
</script>
<script>
    const vm= new Vue({
        el:'#app',
        data:{
            age:17
        },
        template:'#mb',
    })
</script>
复制代码
<body>
    <div id="app">
        我是el挂载的内容:小明今年{{age}}岁了
    </div>
    <template id="mb">
        <div>我是template的内容:小明今年{{age}}岁了</div>
    </template>
</body>
<script>
    const vm= new Vue({
        el:'#app',
        data:{
            age:17
        },
        template:'#mb',
    })
</script>
复制代码

  • render :Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或经过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            我是el挂载的内容:小明今年{{age}}岁了
        </div>
    </body>
    <script>
        const vm= new Vue({
            el:'#app',
            data:{
                age:17
            },
            template:'<div>我是template的内容:小明今年{{age}}岁了</div>',
            render(h){
                return h('div',`我是render的内容:小明今年${this.age}岁了`)
            }
        })
    </script>
</html>
复制代码

<template></template>有什么用?

参考答案 当作一个不可见的包裹元素,减小没必要要的DOM元素,整个结构会更加清晰。

Vue怎么改变插入模板的分隔符?

参考答案

delimiters选项,其默认是["{{", "}}"]

// 将分隔符变成ES6模板字符串的风格
new Vue({
  delimiters: ['${', '}']
})
复制代码

Vue变量名若是以_、$开头的属性会发生什么问题?怎么访问到它们的值?

参考答案

_$ 开头的属性 不会 被 Vue 实例代理,由于它们可能和 Vue 内置的属性、API 方法冲突,你可使用例如 vm.$data._property 的方式访问这些属性。

怎么捕获Vue组件的错误信息?

参考答案
  • errorCaptured是组件内部钩子,当捕获一个来自子孙组件的错误时被调用,接收errorvminfo三个参数,return false后能够阻止错误继续向上抛出。
  • errorHandler为全局钩子,使用Vue.config.errorHandler配置,接收参数与errorCaptured一致,2.6后可捕捉v-onpromise链的错误,可用于统一错误处理与错误兜底。

Vue.observable你有了解过吗?说说看

参考答案 让一个对象可响应。能够做为最小化的跨组件状态存储器。

Vue项目中如何配置favicon?

参考答案
  • 静态配置 <link rel="icon" href="<%= BASE_URL %>favicon.ico">, 其中<%= BASE_URL %>等同vue.config.js中publicPath的配置;
  • 动态配置<link rel="icon" type="image/png" href="">
    import browserImg from 'images/kong.png';//为favicon的默认图片
    const imgurl ='后端传回来的favicon.ico的线上地址'
    let link = document.querySelector('link[type="image/png"]');
    if (imgurl) {
        link.setAttribute('href', imgurl);
    } else {
        link.setAttribute('href', browserImg);
    }
    复制代码

怎么修改Vue项目打包后生成文件路径?

参考答案
  • 在Vue CLI2中修改config/index.js文件中的build.assetsPublicPath的值;
  • 在Vue CLI3中配置publicPath的值。

怎么解决Vue项目打包后静态资源图片失效的问题?

参考答案

在项目中通常经过配置alias路径别名的方式解决,下面是Vue CLI3的配置。

configureWebpack: {
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            '@': resolve('src'),
            'assets': resolve('src/assets'),
            'css': resolve('src/assets/css'),
            'images': resolve('src/assets/images'),
        }
    },
},
复制代码

怎么解决Vue中动态设置img的src不生效的问题?

参考答案

由于动态添加src被当作静态资源处理了,没有进行编译,因此要加上require。

<template>
    <img class="logo" :src="logo" alt="公司logo">
</template>
<script>
export default {
    data() {
        return {
            logo:require("assets/images/logo.png"),
        };
    }
};
</script>
复制代码

在Vue项目中如何引入第三方库(好比jQuery)?有哪些方法能够作到?

参考答案
相关文章
相关标签/搜索