写给自己的面试题-Vue篇

5 阅读3分钟

为什么data是一个函数而且返回一个对象

因为一个组件可能多个地方调用 每执行一次就生成全新的对象 可以避免数据污染

vue修饰符

.lazy .trim .number .stop .self .once .navtive

vue修饰符

v-text v-html v-show v-if v-else v-else-if v-for v-on v-bind v-model v-slot v-once v-pre v-cloak

组件传值

父传子 props 子传父 $emit

//	父组件
<hello-world msg="hello world!" @confirm="handleConfirm"><hello-world>
//	子组件
 props: {
    msg: {
      type: String,
      default: ''
    }
  },
  methods:{
  	handleEmitParent(){
  		this.$emit('confirm', list)
  	}
  }

parentparent和children 也可以获取到父子组件的实例

// 获取第一个子组件的数据
console.log(this.$children[0].msg)

// 调用根组件的方法
this.$root.handleRoot()

$ref 多用于父组件调用子组件的事件

// ...
<hello-world ref="hello"></hello-world>
// ...
export default {
  mounted(){
    // 调用引用的子组件的方法
    this.$refs.hello.handleRef()
  }
}

attrsattrs和listeners attrs可以获取父组件传进来但没有通过props接收的属性attrs 可以获取父组件传进来但没有通过props接收的属性 listeners 会展开父组件所有的监听事件

<Child :title="title" :desc="desc" >/>

//  子组件内
<template>
<div>
  <h2>{{title}}</h2>
  <p>{{$attrs.desc}}</p>
</div>
</template>	
<script>
export default {
  props: ['title']
  // ...
}
<script>

//  父组件
<div>
  <child-first @click="handleClick"></child-first>
  <child-second @click="handleClick"></child-second>
</div>
export default {
  methods: {
    handleClick: (){
      alert('hello')
    }
  }
}

// child-first
<div v-on="$listeners"></div>

// child-second
<div v-on="$listeners"></div>

provide/inject 常用一些多个组件嵌套封装,一个顶层组件内部的后代组件需要用到顶层组件的数据就使用这种方式

export default {
  provide(){
    return {
      msg: 'hello world!'
    }
  }
}

//  后代组件
export default {
  inject: ['msg']
}

Vuex

state 放数据的地方 getter可以对要输出的值做一些更改
mutation 里面可以放更改数据的方法

this.$store.commit('setNumberIsWhat', val);
VUEX
mutations: {
setNumberIsWhat(state, number)  // 增加一个带参数的mutations方法 state.number = number;
},

actions 这里可以放异步的方法 通常我们建议在这里调用mutations的方法 异步的修改值

this.$store.dispatch('setNum')
VUEX
actions:{
setNum(state){
state.commit(setNumberIsWhat,val)
  }
}

module 如果数据太多 需要划分 可以使用module对数据进行区分

store.state.moduleA-->就可以调用A区的
store.state.moduleB-->就可以调用B区的

vue通过4步完成双向绑定

  1. 实现一个监听器observer:遍历改数据对象,包括子属性的对象 对每个值都进行Object.defineproperty()加上getter和setter,如果给对象赋值,那就会触发setter
  2. 实现一个解析器compile:解析Vue模版指令,将模版中的变量都替换成数据,渲染页面,对每个指令绑定的节点都绑定更新函数,添加监听数据的订阅者,一旦数据变动,调用新函数数据更新
  3. 实现一个watcher:watcher是oberver和compile的通信桥梁,订阅observe中属性的变化,当属性变化的时候触发compile的更新
  4. 实现一个订阅器Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者watcher 对监听器observer和订阅者watcher统一管理 大佬解析 juejin.cn/post/684490…

vue是怎么监听对象和数组的

如果是对象和数组 会采用递归的形式 把item一层一层的加到observer方法里

set是怎么样解决对象新增属性不响应的问题

set的原理是判断目标是不是数组 是的话调用splice 触发响应式
是对象的话判断属性是否可读 是的话调用defineReative方法来激活响应式

Keepalive

Keepalive是Vue的一个内置组件,将不活动的组件实例保存在内存中,并不销毁他。
include:名字匹配的组件会给缓存
exclude 匹配的不缓存
max:缓存的上限
activated:激活的时候的生命周期,可以在这个钩子函数中进行一些状态保存,数据更新的操作
deativated:停用的时候的生命周期,可以做一些状态保存,数据清理的操作

nexttick的原理及作用

本质是对EventLoop的应用,把里面的回调函数放到一个异步队列,保证在更新DOM后的Watcher后面,从而获取到更新后的DOM

Vue模板编译的原理

主要过程有这三个template-->ast-->render 通过Parse函数解析template转化成ast树 通过children字段层层嵌套
通过optimize方法对AST树进行标记 那些是静态节点 哪些是双向绑定的 后期渲染直接跳过静态节点
通过generate函数把AST树编译成render字符串 通过new function(render)生成为render函数执行

路由守卫

全局前置钩子:beforeEach,beforeResolve,afterEach
路由独享守卫:beforeEnter
组件内钩子:beforeRouterEnter beforeRouterUpdate beforeRouterLeave