VUE3常见面试题

Pinia如何重置数据

Pinia是一个Vue状态管理库,如果您想重置它的数据,可以尝试以下方法:

        1.使用Pinia的 reset 方法

在你的store中,调用 reset 方法可以将store中的所有状态重置为它们的默认值,例如:

import { defineStore } from 'pinia'

export const useMyStore = defineStore('myStore', {
  state: () => ({
    counter: 0,
    isAuthenticated: false,
  }),
  actions: {
    resetAll() {
      this.$reset()
    },
  },
})

在上面的例子中,调用 resetAll 方法可以将 counterisAuthenticated 两个状态都重置为它们的默认值。

        2.手动重置状态

在某些情况下,您可能需要手动重置store中的数据。您可以遍历store中的状态,并将它们设为它们的默认值,例如:

import { defineStore } from 'pinia'

export const useMyStore = defineStore('myStore', {
  state: () => ({
    counter: 0,
    isAuthenticated: false,
  }),
  actions: {
    resetAll() {
      Object.assign(this.$state, this.$options.state())
    },
  },
})

在上面的例子中,resetAll 方法遍历store的状态,将每个状态设为它们的默认值。这将导致 counterisAuthenticated 两个状态都重置为它们的默认值。

无论您使用哪种方法,都应该重置store的所有状态以确保它们在下一次使用时处于正确的初始状态。  

Pinia如何修改数据

Pinia 是一个状态管理库,可以用来管理 Vue 应用中的数据状态。要修改 Pinia 中的数据,您需要使用 Pinia 中提供的 actions 方法,它类似于 Vuex 中的 mutations 方法。

这里是一个简单的示例,展示如何在 Pinia 中修改数据:

import { defineStore } from 'pinia'

// 创建一个 Pinia Store
const store = defineStore('example', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    }
  }
})

// 在组件中使用
import { useStore } from 'pinia'

export default {
  setup() {
    const store = useStore('example')

    function handleClick() {
      store.increment()
    }

    return {
      handleClick
    }
  }
}

在上面的代码中,我们定义了一个名为 example 的 Pinia Store,它包含一个名为 count 的状态。我们在 actions 中定义了一个名为 increment 的方法,它可以通过 this.count++count 的值加 1。

在组件中,我们可以使用 useStore 方法获取 example Store 的实例,并调用 increment 方法来修改 count 的值。

当您在组件中使用 store.count 时,它将自动响应到视图中,因为 Pinia 的状态是可响应的。

Pinia如何进行异步操纵

Pinia使用 Vue 3 的 Composition API,支持异步操纵数据。以下是异步操纵数据的示例:

import { defineStore } from 'pinia'

export const useStore = defineStore({
  id: 'example',
  state: () => ({
    data: null,
    loading: false,
    error: null,
  }),
  actions: {
    async fetchData() {
      try {
        this.loading = true
        const response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
        const data = await response.json()
        this.data = data
        this.error = null
      } catch (error) {
        this.error = error.message
      } finally {
        this.loading = false
      }
    },
  },
})

在上面的示例中,fetchData 方法使用 async/await 异步获取数据。在开始获取数据时,将 loading 状态设置为 true,以便能够在界面上显示加载状态。如果出现任何错误,将 error 状态设置为错误消息。不管结果如何,最后都将 loading 状态设置为 false

在组件中使用该 store:




在上面的示例中,我们从 store 中导入 fetchDatadataloadingerror,并将它们添加到组件的 setup 函数中。在模板中,我们使用 v-if 属性根据状态来显示相应的内容,并使用 @click 属性调用 fetchData 方法来获取数据。

pinia和vuex的区别

 Pinia和Vuex都是在Vue.js应用中用于管理应用状态的库,但是它们有以下区别:

  1. API风格:Pinia采用基于函数API的风格,Vuex采用基于对象API的风格。

  2. TypeScript支持:Pinia天生支持TypeScript,而Vuex需要额外安装TypeScript支持。

  3. 性能:Pinia通过利用Vue 3中的新特性来提高性能,比如使用reactive来管理状态,让你能够避免使用Vue 2中的Dep对象。相比之下,Vuex使用了更复杂的数据结构,并使用了Vue 2中的Dep对象,因此相对来说性能相对较低。

  4. 动态加载:Pinia支持动态加载模块,而Vuex需要在应用启动时加载所有模块。

  5. 模块初始化:在Vuex中,模块需要在应用启动时初始化,而在Pinia中,模块是在需要时动态创建的。

总的来说,Pinia更加轻量化,可以提供更好的性能,而Vuex则提供了更多的开箱即用的功能和更广泛的社区支持。选择哪一个取决于您的具体需求。

Vue2.0 和 Vue3.0 有什么区别?

 Vue2.0和Vue3.0是Vue.js的两个主要版本,它们有以下区别:

  1. 性能提升:Vue3.0通过使用Proxy代替Object.defineProperty来实现响应式数据绑定,提高了性能。

  2. 更好的类型推断:Vue3.0使用TypeScript重写了代码,提供了更好的类型推断和类型约束。

  3. 更小的包体积:Vue3.0通过删除不必要的代码和更好的树摇动优化,实现了更小的包体积。

  4. 模板编译器升级:Vue3.0的模板编译器使用了全新的编译器框架,提高了编译性能和编译错误的反馈。

  5. 更好的可组合性:Vue3.0引入了Composition API,提供了更好的可组合性和复用性。

  6. 更好的开发体验:Vue3.0提供了更好的开发工具和开发体验,如更好的错误处理和更好的调试工具等等。

总的来说,Vue3.0相比于Vue2.0具有更高的性能,更好的可组合性,更好的开发体验和更小的包体积等优势。但是,由于Vue3.0引入了一些新的特性和修改了一些原有的API,因此与Vue2.0在语法和使用方面存在一些差异,需要开发者进行适当的学习和转换。

简述下setup 参数

 Vue 3 的 setup 参数是用于 Composition API 的一种特殊函数,它可以用于在组件内部定义可复用的逻辑代码。这些逻辑代码可以使用 refreactivecomputed 等响应式 API 来定义数据,并且可以使用 watchonMounted 等生命周期函数来处理副作用。

下面是一些常用的 setup 参数:

  1. props:定义从父组件中接收的属性;
  2. context:组件上下文对象,包含父组件、子组件等信息;
  3. setup:定义组件逻辑的函数;
  4. data:定义组件内部数据的函数;
  5. computed:定义计算属性的函数;
  6. methods:定义组件方法的对象;
  7. watch:定义响应式数据的监听器。

在 Vue 3 中,setup 函数是必须的,且在创建组件实例之前先执行一次。setup 函数可以接收两个参数:propscontext。其中,props 是一个响应式对象,用于接收来自父组件的属性,并且可以使用 refreactive 包装其中的属性;context 是一个常规 JavaScript 对象,包含一些常用的组件上下文信息。

一个简单的使用 setup 函数的 Vue 3 组件示例:




在上面的示例中,我们使用 ref 定义了一个名为 message 的响应式数据,并将其初始化为 'Hello World'。然后,我们在 increment 函数中通过修改 message.value 来改变 message 的值。最后,我们通过 return 语句将 messageincrement 导出,以便在模板中使用。

简述setup返回值

 在 Vue 3 中,setup 函数是必须的,它用于组合式 API。setup 函数必须返回一个对象或者 null,这个对象会成为组件实例的 setupState 属性。

setup 函数返回的对象可以包含多个属性,每个属性都可以是一个普通值、响应式对象、计算属性、方法等。这些属性可以在组件的模板中使用,也可以在组件的方法中使用。

下面是一个简单的 setup 函数的示例:

import { reactive } from 'vue'

export default {
  name: 'MyComponent',
  setup() {
    const state = reactive({
      count: 0,
      increment() {
        state.count++
      }
    })

    return { state }
  }
}

在上面的示例中,setup 函数返回了一个包含 state 属性的对象,这个属性的值是一个响应式对象。在这个响应式对象中,我们定义了一个名为 count 的属性,它的初始值为 0,以及一个名为 increment 的方法,用于增加 count 的值。最后,我们将 state 导出,以便在组件的模板和方法中使用。

需要注意的是,如果 setup 函数返回的对象中包含了与组件选项中相同名称的属性,那么这个属性将会覆盖掉组件选项中的属性。例如,如果 setup 函数和组件选项中都定义了 created 方法,那么 setup 函数中的方法将会覆盖掉组件选项中的方法。

shallowReactive是什么

shallowReactive是Vue 3中的一个API,它是reactive API的一种变体,用于创建一个仅响应对象顶层属性的响应式对象。与reactive不同的是,shallowReactive不会递归地将对象的所有属性转换为响应式对象,只会将顶层属性转换为响应式对象。因此,当顶层属性改变时,shallowReactive会触发更新,但当嵌套属性改变时,不会触发更新。

shallowRef是什么

 shallowRef是Vue.js 3中的一个响应式数据类型,它类似于ref,但只对基本类型(如字符串、数字、布尔值)进行浅层响应式处理(即只处理数据本身,不处理嵌套的属性)。当shallowRef包装一个对象时,虽然对象内部的属性不会被响应式处理,但是对象本身会被响应式处理。与ref一样,shallowRef也提供value属性来读取和更新包装的值。

readonly与shallowReadonly分别是什么

 readonlyshallowReadonly 都是 Vue3 的工具函数,用于创建只读(不可修改)的响应式对象。

  • readonly 会递归将对象的所有属性都转换成只读的响应式属性,即使对象内部还包含其他对象或数组;
  • shallowReadonly 只会将对象自身的属性转换成只读的响应式属性,而不会递归转换对象内部的属性。

举个例子:

import { readonly, shallowReadonly } from 'vue';

const obj = {
  a: 1,
  b: {
    c: 2
  },
  arr: [3, 4, 5]
};

const ro = readonly(obj);
const sro = shallowReadonly(obj);

// 下面两行代码都会报错
ro.a = 2;
sro.a = 2;

// 下面两行代码只有第一行会报错
ro.b.c = 3;
sro.b.c = 3;

// 下面两行代码都会报错
ro.arr[0] = 6;
sro.arr[0] = 6;

toRef与toRefs分别什么

 toRef 和 toRefs 都是 Vue3 的响应式 API。它们用于将非响应式对象转换成响应式对象。

toRef 的作用是将一个普通的对象属性转换成一个响应式对象属性,返回一个 ref 对象,使得可以在模板中使用这个 ref 对象来渲染和响应式更新。

toRefs 的作用是将一个普通的对象转换成多个 ref 对象,每个 ref 对象对应原对象的一个属性,使得可以在模板中使用这些 ref 对象来渲染和响应式更新。toRefs 函数返回的是一个包含多个 ref 对象的响应式对象。

toRef 和 toRefs 的区别在于:

  • toRef 只能将一个普通的对象属性转换成 ref 对象,而 toRefs 可以将整个对象转换成多个 ref 对象。
  • toRef 返回的是一个 ref 对象,而 toRefs 返回的是一个包含多个 ref 对象的响应式对象。

组合式apiref是什么

 在组合式API中,ref是引用一个组件或元素实例的属性。它允许您在使用组合式API时直接操作DOM元素或组件实例。ref可以是一个回调函数,也可以是一个创建ref的函数,具体取决于使用的API。通过ref,您可以直接操作组件上的方法和属性,例如触发事件、获取属性值或强制重新渲染等。

组合式api的ref与reactive区别

 组合式API是Vue 3中的新API,可以用于组合多个可重用的逻辑函数,而不是使用传统的选项API编写Vue组件。组合式API中的ref和reactive都用于管理响应式数据。

ref将一个普通的JavaScript数据转换为响应式数据,并返回一个包含该数据的引用对象。可以通过.value属性访问该数据,或使用ref内置的一些方法对数据进行操作。

reactive将一个普通的JavaScript对象转换为响应式对象,并返回该响应式对象。可以通过访问该响应式对象的属性,以及响应式对象内置的一些方法进行数据操作。

ref和reactive之间的区别在于:

  • ref只能用于管理单个值的响应式数据,而reactive可以对整个对象进行响应式管理。
  • ref中的.value属性是直接访问数据的方式,而reactive中的数据需要通过访问对象属性进行访问。
  • 在组件中使用ref时,可以通过传递ref对象给子组件来实现值的传递;而在使用reactive时,需要通过将整个对象传递给子组件来实现值的传递。

总之,ref和reactive都是用于管理响应式数据的API,但是它们的应用场景略有不同,需要根据具体情况来选择使用哪一个。

Object.defineProperty与Proxy有什么区别

 Object.defineProperty与Proxy都可以用来拦截JavaScript对象的操作,但是二者还是有一些区别的。

  1. 功能不同:Object.defineProperty主要用于拦截单个属性的读取、写入和删除操作,而Proxy可以拦截所有对象操作,包括属性访问、赋值、函数调用等等。

  2. 操作方式不同:Object.defineProperty需要对每个属性进行设置,而Proxy可以对整个对象进行拦截,拦截器只需要实现对应的操作即可。

  3. 兼容性不同:Object.defineProperty从ES5开始支持,而Proxy从ES6开始支持。早期的浏览器可能不支持Proxy。

  4. 使用场景不同:Object.defineProperty一般用于对已有对象进行改造,而Proxy则更适合在对象创建时就进行拦截,或者对已有的复杂对象进行拦截。

总体来说,Object.defineProperty更加简单易用,而Proxy功能更加强大,但使用也更加复杂。根据具体需求,可以选择使用对应的方法。

组合式api的计算属性

 组合式 API 允许我们使用计算属性,用于在组合式函数中计算和存储数据,从而提高代码的重用性和可读性。

例如,在一个组合式函数中,我们可以创建一个计算属性来计算总价格:

import { computed } from 'vue';
import { useStore } from './store';

export default {
  setup() {
    const store = useStore();

    const totalPrice = computed(() => {
      return store.state.cart.reduce((total, product) => total + product.price, 0);
    });

    return { totalPrice };
  }
}

在上面的示例中,我们使用 computed 函数创建了一个名为 totalPrice 的计算属性,它计算了购物车中所有商品的总价格,并返回它。我们将计算属性作为组合式函数的返回值,以便在模板中使用它。

在模板中,我们可以像这样使用计算属性:


这样,当购物车中的商品数量或价格发生变化时,totalPrice 计算属性将自动更新,从而保持总价格的准确性。

组合式api过滤器

 在Vue 3中,过滤器已经被废弃,因此推荐使用计算属性或方法来执行相同的功能。

计算属性:




在上面的代码中,我们使用一个计算属性filteredMessage来过滤message中包含特定单词的部分。

方法:




在上面的代码中,我们使用一个方法filteredMessage来执行相同的过滤功能。

总之,Vue 3已经废弃了过滤器,建议使用计算属性或方法来进行相同的操作。

组合式api有哪些

 Vue 3引入了全新的基于函数的组合式API。以下列出了一些Vue 3组合式API:

  1. setup():组件选项之一,在组件实例化之前执行,用来进行组件的初始化。可以在这里定义响应式的数据、计算属性、方法、生命周期钩子等。

  2. reactive():接受一个对象作为参数,返回一个响应式的数据对象。

  3. ref():接受一个初始值作为参数,返回一个包装对象,可以通过.value属性访问和更改这个值。

  4. watchEffect():接受一个响应式数据或计算属性作为参数,当这个数据改变时会自动执行回调函数。

  5. computed():接受一个函数作为参数,返回一个计算属性。当计算属性依赖的响应式数据改变时会重新计算该属性的值。

  6. watch():接受一个响应式数据或计算属性作为参数,当这个数据改变时会执行回调函数。

  7. toRefs():将一个响应式数据对象转换为一个由响应式数据组成的对象。

  8. onMounted():在组件挂载后执行的生命周期钩子。

  9. onUpdated():在组件更新后执行的生命周期钩子。

  10. onUnmounted():在组件卸载前执行的生命周期钩子。

总之,Vue 3中的组合式API更加灵活和直观,可以更好地进行组件的封装和复用。

组合式api-watch请简述

Vue3组合式API的watch函数,用于监听响应式数据的变化并执行相应的操作。watch函数接收两个参数:要监听的数据和回调函数。当监听的数据发生变化时,回调函数会被触发执行相应的操作。

watch函数有三种使用方式:

  1. 监听单个数据源:
import { watch } from 'vue'

const count = ref(0)

watch(count, (newVal, oldVal) => {
  console.log(`count的值发生变化,新值为${newVal},旧值为${oldVal}`)
})

        1.监听多个数据源:

import { watch } from 'vue'

const count1 = ref(0)
const count2 = ref(0)

watch([count1, count2], ([newVal1, newVal2], [oldVal1, oldVal2]) => {
  console.log(`count1的值发生变化,新值为${newVal1},旧值为${oldVal1}`)
  console.log(`count2的值发生变化,新值为${newVal2},旧值为${oldVal2}`)
})

        3.对象形式监听多个数据源:

import { watch } from 'vue'

const data = reactive({
  count1: 0,
  count2: 0
})

watch(data, ({ count1, count2 }, { count1: oldCount1, count2: oldCount2 }) => {
  console.log(`count1的值发生变化,新值为${count1},旧值为${oldCount1}`)
  console.log(`count2的值发生变化,新值为${count2},旧值为${oldCount2}`)
})

什么是自定义hook

 Vue3的自定义hook是基于Vue3的组合式API而实现的。通过自定义hook,我们可以将一些常用的逻辑(如数据获取、状态管理等)封装成一个函数,以便在不同组件中复用,避免重复的代码和逻辑。

自定义hook的实现方式非常简单,只需要定义一个函数并在函数内部使用Vue3的组合式API来实现逻辑封装即可。例如,下面是一个简单的使用自定义hook的例子:

import { ref, onMounted } from 'vue'

function useCountdown(seconds) {
  const count = ref(seconds)

  const timer = setInterval(() => {
    count.value--
  }, 1000)

  onMounted(() => {
    if (count.value <= 0) {
      clearInterval(timer)
    }
  })

  return { count }
}

export default {
  setup() {
    const { count } = useCountdown(10)

    return { count }
  }
}

在上面的例子中,我们定义了一个名为useCountdown的自定义hook函数,该函数接收一个表示倒计时的秒数,通过ref函数创建了一个名为count的响应式数据,并在函数内部使用了Vue3的组合式API onMounted和setInterval来实现倒计时的逻辑封装。最后我们将自定义hook作为一个函数导出,并在组件内使用该函数之后返回的count数据。

Vue选项式api 组合式api 正向传值分别是什么

  • 选项式 API: 正向传值是通过组件的 props 进行传递的。
  • 组合式 API: 正向传值是通过组合式 API 的参数进行传递的。例如,使用 setup 函数中的参数来接收父组件传递的props,或者使用 provide/inject API 在父子组件之间共享状态。
  • 正向传值:是指从父组件向子组件传递数据,通常通过 props 属性进行传递。例如,在父组件中使用 的方式将属性值传递给子组件。

Vue选项式api 组合式api  逆向传值分别是什么

 Vue的选项式API中,从父组件向子组件传递值是通过props进行的。而从子组件向父组件传递值则是通过$emit触发事件来实现的。

Vue的组合式API中,从父组件向子组件传递值是通过setup函数中返回的对象进行的。而从子组件向父组件传递值则是通过在子组件中定义一个函数,然后在父组件中使用v-on指令绑定该函数来实现的。也可以通过context属性来访问祖先组件的属性和方法来进行传递值。

Vue2与vue3双向数据绑定原理不同

Vue2和Vue3的双向数据绑定原理不同。

在Vue2中,双向数据绑定是通过使用数据劫持来实现的。数据劫持是指通过Object.defineProperty()方法对对象的属性进行劫持,从而实现对该属性的监听和响应。在Vue2中,当数据发生变化时,系统会自动触发setter函数,并通知相关的组件进行更新。

在Vue3中,双向数据绑定是通过使用Proxy代理来实现的。Proxy代理是ES6的新特性,可以代理一个对象并跟踪该对象的变化。在Vue3中,当数据发生变化时,系统会通过Proxy代理来捕获新的值,从而触发相关的组件进行更新。

总的来说,Vue2和Vue3的双向数据绑定实现原理不同,但都能实现数据和视图的自动更新。Vue3中使用Proxy代理的方式比Vue2的数据劫持更加灵活和高效,但需要考虑浏览器兼容性。  

v-if与v-for优先级

 在 Vue 2 中,v-for 的优先级高于 v-if。这意味着当一个元素同时具有 v-if 和 v-for 指令时,v-for 将首先运行,然后再运行 v-if。

例如:

  {{ item.name }}

在上面的示例中,如果没有 isActive 属性或值为 false,则渲染的 div 元素将不会被显示,但是 v-for 指令仍然会运行.

在Vue 3中,v-if 和 v-for 的顺序被改变了。如果一个元素拥有 v-if 和 v-for 指令,那么 v-if 将会首先被解析和执行,而 v-for 则会在 v-if 的条件为 true 的情况下才会被执行循环渲染。

例如:

  {{ item }}

在 Vue 3 中,只有在 isShow 为 true 的情况下,数组 items 中的元素才会以列表形式渲染出来。

总结一下,在 Vue 2 中 v-for 的优先级高于 v-if;在 Vue 3 中,v-if 的优先级更高。因此,应该注意选择合适的指令顺序以确保您的模板能够按照预期工作。

最后需要注意的是,在使用 v-if 和 v-for 的时候需要小心使用,以免造成渲染性能问题。避免同时在同一个节点上使用 v-if 和 v-for 指令,并且不要对大型数据集进行 v-if 操作。

vue-router4和vue-router3有什么区别

Vue Router 4 和 Vue Router 3 之间的区别包括以下几点:

  1. 动态路由的写法不同。在 Vue Router 4 中,动态路由需要使用 :param 来表示,而在 Vue Router 3 中需要使用 $route.params.param

  2. Vue Router 4 可以让你使用可选的参数,这个功能在 Vue Router 3 中是不支持的。

  3. 在 Vue Router 4 中,你可以使用 createRouter() 方法来创建一个新的路由实例,而在 Vue Router 3 中,你需要使用 new VueRouter() 方法。

  4. Vue Router 4 中增加了一些新的生命周期钩子函数,例如 beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave,这些生命周期在 Vue Router 3 中是不存在的。

  5. 在 Vue Router 4 中,你可以使用 useRoute() 来获取当前路由对象,而在 Vue Router 3 中,你需要使用 $route 来获取。

  6. Vue Router 4 中的 history 模式下,路由的 base 配置使用的是相对路径,而在 Vue Router 3 中,使用的是绝对路径。

总体来说,Vue Router 4 在功能和语法上都比 Vue Router 3 更加强大和易用。如果你正在使用 Vue 2.x,建议升级到 Vue Router 4 进行开发。

vue-router4如何设置路由模式

在Vue Router 4中,您可以使用createRouter函数来创建一个路由实例并设置路由模式。路由模式有两种:hash模式和history模式。

        1.Hash模式

在hash模式下,URL中的路径会以 # 开头,路由器会监听 URL 中 hash 值的变化,并自动将当前 URL 的 hash 值作为路由的参数,然后渲染匹配的组件。

您可以通过在createRouter函数中设置history属性为createWebHashHistory()来启用hash模式,如下所示:

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    // routes配置
  ]
})

        2.History模式

在history模式下,URL中的路径不会以 # 开头,路由器会监听浏览器的历史记录变化,并自动将当前 URL 的路径作为路由的参数,然后渲染匹配的组件。

您可以通过在createRouter函数中设置history属性为createWebHistory()来启用history模式,如下所示:

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    // routes配置
  ]
})

注意:在使用history模式时,您需要确保服务器正确地配置了基础 URL,以支持在浏览器中刷新页面时正确地获取应用程序的正确状态。如果服务器未正确配置基础 URL,则在刷新页面时可能会出现404错误。

简述下插槽, 普通插槽、具名插槽和作用域插槽

 插槽是一种可以在组件中填充内容的占位符,可以让父组件向子组件传递内容。

普通插槽是组件中最简单的一种插槽,也叫默认插槽。当父组件没有向子组件传入具体内容时,插槽中的默认内容就会被渲染出来。

具名插槽可以有不同的名称,使得父组件可以向子组件传入多个不同的内容。在子组件中,使用<slot>标签的name属性指定具名插槽的名称,在父组件中使用