一文梳理Vue面试题

你有对 Vue 项目进行哪些优化?

(1)代码层面的优化

  • v-if 和 v-show 区分使用场景
  • computed 和 watch 区分使用场景
  • v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
  • 长列表性能优化
  • 事件的销毁
  • 图片资源懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 优化无限列表性能
  • 服务端渲染 SSR or 预渲染

(2)Webpack 层面的优化

  • Webpack 对图片进行压缩
  • 减少 ES6 转为 ES5 的冗余代码
  • 提取公共代码
  • 模板预编译
  • 提取组件的 CSS
  • 优化 SourceMap
  • 构建结果输出分析
  • Vue 项目的编译优化

(3)基础的 Web 技术的优化

  • 开启 gzip 压缩
  • 浏览器缓存
  • CDN 的使用
  • 使用 Chrome Performance 查找性能瓶颈

Vuex中action和mutation的区别

mutation中的操作是一系列的同步函数,用于修改state中的变量的的状态。当使用vuex时需要通过commit来提交需要操作的内容。mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

const store = new Vuex.Store({
   
  state: {
   
    count: 1
  },
  mutations: {
   
    increment (state) {
   
      state.count++      // 变更状态
    }
  }
})

当触发一个类型为 increment 的 mutation 时,需要调用此函数:

store.commit('increment')

而Action类似于mutation,不同点在于:

  • Action 可以包含任意异步操作。
  • Action 提交的是 mutation,而不是直接变更状态。
const store = new Vuex.Store({
   
  state: {
   
    count: 0
  },
  mutations: {
   
    increment (state) {
   
      state.count++
    }
  },
  actions: {
   
    increment (context) {
   
      context.commit('increment')
    }
  }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
所以,两者的不同点如下:

  • Mutation专注于修改State,理论上是修改State的唯一途径;Action业务代码、异步请求。
  • Mutation:必须同步执行;Action:可以异步,但不能直接操作State。
  • 在视图更新时,先触发actions,actions再触发mutation
  • mutation的参数是state,它包含store中的数据;store的参数是context,它是 state 的父级,包含 state、getters

函数式组件优势和原理

函数组件的特点

  1. 函数式组件需要在声明组件是指定 functional:true
  2. 不需要实例化,所以没有this,this通过render函数的第二个参数context来代替
  3. 没有生命周期钩子函数,不能使用计算属性,watch
  4. 不能通过$emit 对外暴露事件,调用事件只能通过context.listeners.click的方式调用外部传入的事件
  5. 因为函数式组件是没有实例化的,所以在外部通过ref去引用组件时,实际引用的是HTMLElement
  6. 函数式组件的props可以不用显示声明,所以没有在props里面声明的属性都会被自动隐式解析为prop,而普通组件所有未声明的属性都解析到$attrs里面,并自动挂载到组件根元素上面(可以通过inheritAttrs属性禁止)

优点

  1. 由于函数式组件不需要实例化,无状态,没有生命周期,所以渲染性能要好于普通组件
  2. 函数式组件结构比较简单,代码结构更清晰

使用场景:

  • 一个简单的展示组件,作为容器组件使用 比如 router-view 就是一个函数式组件
  • “高阶组件”——用于接收一个组件作为参数,返回一个被包装过的组件

例子

Vue.component('functional',{
    // 构造函数产生虚拟节点的
    functional:true, // 函数式组件 // data={attrs:{}}
    render(h){
   
        return h('div','test')
    }
})
const vm = new Vue({
   
    el: '#app'
})

源码相关

// functional component
if (isTrue(Ctor.options.functional)) {
    // 带有functional的属性的就是函数式组件
  return createFunctionalComponent(Ctor, propsData, data, context, children)
}

// extract listeners, since these needs to be treated as
// child component listeners instead of DOM listeners
const listeners = data.on // 处理事件
// replace with listeners with .native modifier
// so it gets processed during parent component patch.
data.on = data.nativeOn // 处理原生事件

// install component management hooks onto the placeholder node
installComponentHooks(data) // 安装组件相关钩子 (函数式组件没有调用此方法,从而性能高于普通组件)

v-model实现原理

我们在 vue 项目中主要使用 v-model 指令在表单 inputtextareaselect 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖(可以看成是value + input方法的语法糖),v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • texttextarea 元素使用 value 属性和 input 事件
  • checkboxradio 使用 checked 属性和 change 事件
  • select 字段将 value 作为 prop 并将 change 作为事件

所以我们可以v-model进行如下改写:

<input v-model="sth" />
<!-- 等同于 -->
<input :value="sth" @input="sth = $event.target.value" />

当在input元素中使用v-model实现双数据绑定,其实就是在输入的时候触发元素的input事件,通过这个语法糖,实现了数据的双向绑定

  • 这个语法糖必须是固定的,也就是说属性必须为value,方法名必须为:input
  • 知道了v-model的原理,我们可以在自定义组件上实现v-model
//Parent
<template>
  {
   {
   num}}
  <Child v-model="num">
</template>
export default {
   
  data(){
   
    return {
   
      num: 0
    }
  }
}

//Child
<template>
  <div @click="add">Add</div>
</template>
export default {
   
  props: ['value'], // 属性必须为value
  methods:{
   
    add(){
   
      // 方法名为input
      this.$emit('input', this.value + 1)
    }
  }
}

原理

会将组件的 v-model 默认转化成value+input

const VueTemplateCompiler = require('vue-template-compiler'); 
const ele = VueTemplateCompiler.compile('<el-checkbox v-model="check"></el- checkbox>'); 

// 观察输出的渲染函数:
// with(this) { 
//     return _c('el-checkbox', { 
//         model: { 
//             value: (check), 
//             callback: function ($$v) { check = $$v }, 
//             expression: "check" 
//         } 
//     }) 
// }
// 源码位置 core/vdom/create-component.js line:155

function transformModel (options, data: any) {
    
    const prop = (options.model && options.model.prop) || 'value' 
    const event = (options.model && options.model.event) || 'input' 
    ;(data.attrs || (data.attrs = {
   }))[prop] = data.model.value 
    const on = data.on || (data.on = {
   }) 
    const existing = on[event] 
    const callback = data.model.callback 
    if (isDef(existing)) {
    
        if (Array.isArray(existing) ? existing.indexOf(callback) === -1 : existing !== callback ) {
   
            on[event] = [callback].concat(existing) 
        } 
    } else {
    
        on[event] = callback 
    } 
}

原生的 v-model,会根据标签的不同生成不同的事件和属性

const VueTemplateCompiler = require('vue-template-compiler'); 
const ele = VueTemplateCompiler.compile('<input v-model="value"/>');

// with(this) { 
//     return _c('input', { 
//         directives: [{ name: "model", rawName: "v-model", value: (value), expression: "value" }], 
//         domProps: { "value": (value) },
//         on: {"input": function ($event) { 
//             if ($event.target.composing) return;
//             value = $event.target.value
//         }
//         }
//     })
// }

编译时:不同的标签解析出的内容不一样 platforms/web/compiler/directives/model.js

if (el.component) {
    
    genComponentModel(el, value, modifiers) // component v-model doesn't need extra runtime 
    return false 
} else if (tag === 'select') {
    
    genSelect(el, value, modifiers) 
} else if (tag === 'input' && type === 'checkbox') {
    
    genCheckboxModel(el, value, modifiers) 
} else if 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值