阿里前端常考vue面试题汇总

Vuex中actions和mutations有什么区别

题目分析

  • mutationsactionsvuex带来的两个独特的概念。新手程序员容易混淆,所以面试官喜欢问。
  • 我们只需记住修改状态只能是mutationsactions只能通过提交mutation修改状态即可

回答范例

  1. 更改 Vuexstore 中的状态的唯一方法是提交 mutationmutation 非常类似于事件:每个 mutation 都有一个字符串的类型 (type)和一个 回调函数 (handler) 。Action 类似于 mutation,不同在于:Action可以包含任意异步操作,但它不能修改状态, 需要提交mutation才能变更状态
  2. 开发时,包含异步操作或者复杂业务组合时使用action;需要直接修改状态则提交mutation。但由于dispatchcommit是两个API,容易引起混淆,实践中也会采用统一使用dispatch action的方式。调用dispatchcommit两个API时几乎完全一样,但是定义两者时却不甚相同,mutation的回调函数接收参数是state对象。action则是与Store实例具有相同方法和属性的上下文context对象,因此一般会解构它为{commit, dispatch, state},从而方便编码。另外dispatch会返回Promise实例便于处理内部异步结果
  3. 实现上commit(type)方法相当于调用options.mutations[type](state)dispatch(type)方法相当于调用options.actions[type](store),这样就很容易理解两者使用上的不同了

实现

我们可以像下面这样简单实现commitdispatch,从而辨别两者不同

class Store {
   
    constructor(options) {
   
        this.state = reactive(options.state)
        this.options = options
    }
    commit(type, payload) {
   
        // 传入上下文和参数1都是state对象
        this.options.mutations[type].call(this.state, this.state, payload)
    }
    dispatch(type, payload) {
   
        // 传入上下文和参数1都是store本身
        this.options.actions[type].call(this, this, payload)
    }
}

如何在组件中批量使用Vuex的getter属性

使用mapGetters辅助函数, 利用对象展开运算符将getter混入computed 对象中

import {
   mapGetters} from 'vuex'
export default{
   
    computed:{
   
        ...mapGetters(['total','discountTotal'])
    }
}

Vue组件之间通信方式有哪些

Vue 组件间通信是面试常考的知识点之一,这题有点类似于开放题,你回答出越多方法当然越加分,表明你对 Vue 掌握的越熟练。 Vue 组件间通信只要指以下 3 类通信父子组件通信隔代组件通信兄弟组件通信,下面我们分别介绍每种通信方式且会说明此种方法可适用于哪类组件间通信

组件传参的各种方式

组件通信常用方式有以下几种

  • props / $emit 适用 父子组件通信
    • 父组件向子组件传递数据是通过 prop 传递的,子组件传递数据给父组件是通过$emit 触发事件来做到的
  • ref$parent / $children(vue3废弃) 适用 父子组件通信
    • ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
    • $parent / $children:访问访问父组件的属性或方法 / 访问子组件的属性或方法
  • EventBus ($emit / $on) 适用于 父子、隔代、兄弟组件通信
    • 这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件
  • $attrs / $listeners(vue3废弃) 适用于 隔代组件通信
    • $attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( classstyle 除外 )。当一个组件没有声明任何 prop时,这里会包含所有父作用域的绑定 ( classstyle 除外 ),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用
    • $listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件
  • provide / inject 适用于 隔代组件通信
    • 祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题, 不过它的使用场景,主要是子组件获取上级组件的状态 ,跨级组件间建立了一种主动提供与依赖注入的关系
  • $root 适用于 隔代组件通信 访问根组件中的属性或方法,是根组件,不是父组件。$root只对根组件有用
  • Vuex 适用于 父子、隔代、兄弟组件通信
    • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )
    • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
    • 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

根据组件之间关系讨论组件通信最为清晰有效

  • 父子组件:props/$emit/$parent/ref
  • 兄弟组件:$parent/eventbus/vuex
  • 跨层级关系:eventbus/vuex/provide+inject/$attrs + $listeners/$root

下面演示组件之间通讯三种情况: 父传子、子传父、兄弟组件之间的通讯

1. 父子组件通信

使用props,父组件可以使用props向子组件传递数据。

父组件vue模板father.vue:

<template>
  <child :msg="message">child>
template>

<script>
import child from './child.vue';
export default {
     
  components: {
     
    child
  },
  data () {
     
    return {
     
      message: 'father message';
    }
  }
}
script>

子组件vue模板child.vue:

<template>
    <div>{
  {msg}}div>
template>

<script>
export default {
     
  props: {
     
    msg: {
     
      type: String,
      required: true
    }
  }
}
script>

回调函数(callBack)

父传子:将父组件里定义的method作为props传入子组件

// 父组件Parent.vue:
<Child :changeMsgFn="changeMessage">
methods: {
   
    changeMessage(){
   
        this.message = 'test'
    }
}
// 子组件Child.vue:
<button @click="changeMsgFn">
props:['changeMsgFn']

子组件向父组件通信

父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件

父组件vue模板father.vue:

<template>
    <child @msgFunc="func">child>
template>

<script>
import child from './child.vue';
export default {
     
    components: {
     
        child
    },
    methods: {
     
        func (msg) {
     
            console.log(msg);
        }
    }
}
script>

子组件vue模板child.vue:

<template>
    <button @click="handleClick">点我button>
template>

<script>
export default {
     
    props: {
     
        msg: {
     
            type: String,
            required: true
        }
    },
    methods () {
     
        handleClick () {
     
          //........
          this.$emit('msgFunc');
        }
    }
}
script>

2. provide / inject 跨级访问祖先组件的数据

父组件通过使用provide(){return{}}提供需要传递的数据

export default {
   
  data() {
   
    return {
   
      title: '我是父组件',
      name: 'poetry'
    }
  },
  methods: {
   
    say() {
   
      alert(1)
    }
  },
  // provide属性 能够为后面的后代组件/嵌套的组件提供所需要的变量和方法
  provide() {
   
    return {
   
      message: '我是祖先组件提供的数据',
      name: this.name, // 传递属性
      say: this.say
    }
  }
}

子组件通过使用inject:[“参数1”,”参数2”,…]接收父组件传递的参数

<template>
  <p>曾孙组件p>
  <p>{
  {message}}p>
template>
<script>
export default {
     
  // inject 注入/接收祖先组件传递的所需要的数据即可 
  //接收到的数据 变量 跟data里面的变量一样 可以直接绑定到页面 {
     {}}
  inject: [ "message","say"],
  mounted() {
     
    this.say();
  },
};
script>

3. $parent + $children 获取父组件实例和子组件实例的集合

  • this.$parent 可以直接访问该组件的父实例或组件
  • 父组件也可以通过 this.$children 访问它所有的子组件;需要注意 $children 并不保证顺序,也不是响应式的

<template>
<div>
  <child1>child1>   
  <child2>child2> 
  <button @click="clickChild">$children方式获取子组件值button>
div>
template>
<script>
import child1 from './child1'
import child2 from './child2'
export default {
     
  data(){
     
    return {
     
      total: 108
    }
  },
  components: {
     
    child1,
    child2  
  },
  methods: {
     
    funa(e){
     
      console.log("index",e)
    },
    clickChild(){
     
      console.log(this.$children[0].msg);
      console.log(this.$children[1].msg);
    }
  }
}
script>

<template>
  <div>
    <button @click="parentClick">点击访问父组件button>
  div>
template>
<script>
export default {
     
  data(){
     
    return {
     
      msg:"child1"
    }
  },
  methods: {
     
    // 访问父组件数据
    parentClick(){
     
      this.$parent.funa("xx")
      console.log(this.$parent.total);
    }
  }
}
script>

<template>
  <div>
    child2
  div>
template>
<script>
export default {
     
  data(){
     
    return {
     
     msg: 'child2'
    }
  }
}
script>

4. $attrs + $listeners多级组件通信

$attrs 包含了从父组件传过来的所有props属性

// 父组件Parent.vue:
<Child :name="name" :age="age"/>

// 子组件Child.vue:
<GrandChild v-bind="$attrs" />

// 孙子组件GrandChild
<p>姓名:{
   {
   $attrs.name}}</p>
<p>年龄:{
   {
   $attrs.age}}</p>

$listeners包含了父组件监听的所有事件

// 父组件Parent.vue:
<Child :name="name" :age="age" @changeNameFn="changeName"/>

// 子组件Child.vue:
<button @click="$listeners.changeNameFn"></button>

5. ref 父子组件通信

// 父组件Parent.vue:
<Child ref="childComp"/>
<button @click="changeName"></button>
changeName(){
   
    console.log(this.$refs.childComp.age);
    this.$refs.childComp.changeAge()
}

// 子组件Child.vue:
data(){
   
    return{
   
        age:20
    }
},
methods(){
   
    changeAge(){
   
        this.age=15
  }
}

6. 非父子, 兄弟组件之间通信

vue2中废弃了broadcast广播和分发事件的方法。父子组件中可以用props$emit()。如何实现非父子组件间的通信,可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递。Bus.js可以是这样:

// Bus.js

// 创建一个中央时间总线类  
class Bus {
     
  constructor() {
     
    this.callbacks = {
   };   // 存放事件的名字  
  }  
  $on(

你可能感兴趣的:(前端框架,vue.js)