vue常见面试题

目录

 

v-if与v-show的区别:

对MVVM开发模式的理解:

VUE组件data为什么必须是函数

methods,computed,watch

为何要在v-for中使用key

描述Vue组件生命周期(父子组件)

vue组件如何通讯

描述组件和渲染的过程

何时要使用beforeDestory

什么是作用域插槽

Vuex中action和mutation有何区别:

vue-router常用的路由模式

如何配置vue-router异步加载

请用vnode描述一个DOM结构

监听data变化的核心的API是什么?

请描述响应式原理

简述diff算法过程

Vue为何是异步渲染,$nextTick何用

Vue常见性能优化:


v-if与v-show的区别:

  • v-showv-show通过CSS dispaly控制显示和隐藏
  • v-if组件真正的渲染和销毁,而不是显示和隐藏
  • 频繁切换状态使用v-show,否则使用v-if

对MVVM开发模式的理解:

  • Model 代表数据模型,数据和业务逻辑都在Model层中定义;
  • View 代表UI视图,负责数据的展示;
  • ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作
  •  Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步

VUE组件data为什么必须是函数

  • vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们共用一个data对象,那么状态变更将会影响所有组件实例,这是不合理的

methods,computed,watch

  • computed:可以进行缓存,只有在它的相关依赖发生改变时才会重新计算值,常适用于与一个数据受多个数据影响
  • method:只要发生重新渲染,methods调用总会执行该函数
  • watch:一般用于一个数据影响多个数据,或者在数据变化时来执行异步操作

为何要在v-for中使用key

  • 必须使用key,且不能是index和random
  • diff算法中通过tag和key来判断,是否sanmeNode
  • 减少渲染次数,提升渲染性能(如果发现是sameNode,那么会将node的位置进行移动)

描述Vue组件生命周期(父子组件)

  • beforeCreate(创建前) 在数据观测和初始化事件还未开始
  • created(创建后) 完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来
  • beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
  • mounted(载入后) 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
  • beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
  • updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
  • beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
  • destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

vue组件如何通讯

  • 父子组件传值:父组件给子组件传值,子组件通过props进行接受;子组件向父组件传值,通过$emit方法传递参数,在父组件中穿件子组件时,需要监听$emit的事件
  • 兄弟组件传值:eventBus,创建一个事件中心(是new的一个vue实例),通过event.$on和$event.$emit发布订阅的方式实现通讯,可参考(vue - 组件之间的通信
  • vuex

描述组件和渲染的过程

  • 初次渲染:
    • 解析模板为render函数(或在开发环境下已完成,vue-loader)
    • 触发响应式,监听data属性,setter和getter
    • 执行render函数,返回生成vnode,再执行patch(elem, vnode),页面渲染(在执行render函数时,就已经执行了data的getter,但不会引起视图变化的不会触发get) 
  • 更新过程
    • 修改data,触发setter(此前在getter中已被监听)
    • 重新执行render函数,生成newVnode
    • 执行patch(vnode, newVnode)
  • 流程图参考如下:

 

何时要使用beforeDestory

  • 解绑自定义事件event.$off
  • 清除定时器
  • 解绑自定义的DOM事件,如window scroll等

什么是作用域插槽

  • 作用域插槽给了子组件将数据返回组组件的能力,子组件一样可以复用,同时父组件也可以重新组织内容和样式
  • 一下是一个简单的demo:

Vuex中action和mutation有何区别:

  • action处理异步,mutation不可以
  • mutation专注于修改state,而action是提交的mutation,而不直接变更状态
  • action可以整合多个mutation

vue-router常用的路由模式

  • hash(默认):hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误
  • H5 history:且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误

如何配置vue-router异步加载

 

请用vnode描述一个DOM结构

监听data变化的核心的API是什么?

  • Object.defineProperty
  • Object.defineProperty有和缺点
    • 深度监听,需要递归到底,计算量大
    • 对删除的属性和新增的属性无法实现监听,需要使用Vue.set和Vue.delete
    • 无法监听数组,需要特殊处理
  • 实现如下:该实现通过重写数组的常用方法实现数组的监听
const data = {
    name: 'zhangsan',
    age:21,
    info: {
        address: 'BeiJing'
    },
    num: [1,2,3]
}


// 重新定义数组的原型,不建议直接重写数组的方法,否则就会污染全局的原型方法
let oldArrayProperty = Array.prototype;
var arrProto = Object.create(oldArrayProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
    arrProto[methodName] = function(){
        updateView  ();
        oldArrayProperty[methodName].call(this, ...arguments);
    }
})



function updateView(){
    console.log('update view');
}

function observer(target){
    if (typeof target !== 'object' || target === null){
        return target;
    }

    if (Array.isArray(target)){
        target.__proto__ = arrProto;
    }

    for (let key in target){
        defineReactive(target, key, target[key])
    }
}

function defineReactive(target, key, value){
    // 深度监听
    observer(value);

    Object.defineProperty(target, key, {
        get(){
            return value
        },
        set(newValue){
            // 设置的新值可能还是一个object
            observer(newValue);
            if (newValue !== value){
                value = newValue
                updateView();
            }
        }
    })
}

// 执行observer必须等数组方法重写后进行监听
observer(data);

data.name = 'lisi';
data.age = 20;
data.info.address = 'ShangHai';
data.num.push(4)

请描述响应式原理

  • 当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter,在属性被访问和修改时通知变化。
  • 每个组件实例都有相应的 watcher 程序实例,当data发生变化是,之后setter 被调用,会通知 watcher 重新计算,从而执行render函数,致使它关联的组件得以更新。
  • 可参考上面题目的流程图:“描述组件和渲染的过程”

简述diff算法过程

  • patch函数:patch(elem, vnode)   和   patch(vnode, newVnode)
    • 当第一个参数不是vnode时,创建一个空的vnode关联到dom元素上
    • 当两个vnode不一致时,创建新的vnode,将旧的vnode删除
    • 当两个vnode一致时,执行patchVnode函数
  • patchVnode函数:
    • 该函数主要用于对旧vnode和新vnode中的children进行对比,从而进行对应操作
    • 当旧vnode的children和新vnode的children同时存在,执行updateChildren
    • 当新的children有,旧的text有,那么将旧的vnode的text设置为空,添加新的children
    • 当新的children无,旧的children有,删除旧的children
    • 当新的vnode有text时,且不等于旧的vnode的text时,将旧的children移除,设置新的text
  • updateChildren
    • 该函数主要用于对children进行更新,分别从旧的children和新的children中每一项对比,如果有发现同样的vnode,那么再次执行patcVnode函数
  • sameVnode:
    • 用于判断是否是相同的vnode,通过key和sel进行比较,这也是为什么for循环中一定要有key

Vue为何是异步渲染,$nextTick何用

  • 异步渲染(以及合并data修改),以提高渲染性能,否则每次更新数据都会对当前组件进行重新渲染
  • $nextTick用于在DOM更新完之后,触发回调

keep-alive

  • keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
  • 属性:
    • include:  字符串或正则表达式,只有名称匹配的组件会被缓存
    • exclude: 字符串或正则表达式,名称匹配的组件不会被缓存》
    • max:     数字,最多可以缓存多少组件实例
  • 生命周期:
    • activated和deactivated会在keep-alive树内所有嵌套的组件中触发
        如:B页面是缓存页面
          当A页面跳到B页面时,B页面的生命周期:activated(可在此时更新数据)
          B页面跳出时,触发deactivated
          B页面自身刷新时,会触发created-mouted-activated

  •  router.meta 属性来实现

export default {
  name: 'hello',
  //keep-alive钩子函数:组件被激活时调用
  activated() {
    console.log('首页被激活');
  },
  //keep-alive钩子函数:组件消失,被缓存时调用
  deactivated() {
    console.log('首页被缓存');
  },
  beforeRouteLeave(to, from, next) {
    //设置下一个路由的meta(即首页)
    to.meta.keepAlive = true;  // 让首页缓存,即不刷新
    next();
  }
}

Vue常见性能优化:

  • 合理使用v-if和v-show
  • 合理使用computed
  • v-for加key,以及避免和v-if同时使用(v-for比v-if的优先级高,所以每次都要v-for之后再v-if,所以避免使用)
  • 自定义事件,DOM事件,定时即使销毁
  • 合理使用异步组件
  • 合理使用keep-alive(对需要进行缓存的时候keep-alive)
  • data层级不要太深
  • webpack层面的性能优化

 

 

 

 

  • 3
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值