如何在Vue.js中的组件之间传递数据

如何在Vue.js中的组件之间传递数据

时间:2020-7-18 作者:gykj

跨组件共享数据是VueJS的核心功能之一。它使您可以设计一个更具模块化的项目,控制数据范围,并在整个应用程序中创建自然的数据流。

除非您在一个组件中创建整个Vue应用程序(这毫无意义),否则您将遇到需要在组件之间共享数据的情况。

在本教程结束时,您将了解完成此操作的三种方法。

  • 使用道具在父母与孩子之间共享数据,
  • 发出自定义事件以将数据从子级共享给父级,
  • 使用Vuex创建应用程序级共享状态。

好的-让我们开始吧!

使用NUXT构建应用

借助Spotify,您的朋友可以查看您干扰的内容。如果Internet的其余部分也能经历您的算法节奏怎么办?了解如何编写自己的应用程序以使用Vue.js和Nuxt分享您在Spotify上正在收听的内容。阅读更多→

1.使用道具从父母到孩子共享数据

VueJS道具是在组件之间共享数据的最简单方法。道具是我们可以赋予组件的自定义属性。然后,在模板中,我们可以给这些属性值和-BAM-将数据从父级传递到子级组件!

例如,假设我们正在处理一个用户个人资料页面,并且希望让子组件接受用户名属性。我们需要两个组件。

  1. 接受道具的子组件,我们称其为AccountInfo.vue
  2. 传递道具的父组件,我们称其为ProfilePage.vue

在内部AccountInfo.vue,我们可以使用props选项声明它接受的props。因此,在组件选项中,让它看起来如下所示。

// AccountInfo.vue

<template>
 <div id='account-info'>
   {{username}}
 </div>
</template>
 
<script>
export default {
 props: ['username']
}
</script>

然后,要实际传递来自父(ProfilePage.vue)的数据,我们像自定义属性一样传递数据。

// ProfilePage.vue
 
<account-info username='matt' />

现在,如果我们加载页面,我们可以看到我们的AccountInfo组件正确呈现了其父级传递的值。

与使用其他VueJS指令时一样,我们可以使用v-bind动态传递道具。例如,假设我们要将用户名prop设置为等于变量。我们可以通过对v-bind指令使用简写(或:简称)来完成此操作。代码看起来像这样:

<template>
 <div>
   <account-info :username="user.username" />
 </div>
</template>
 
<script>
import AccountInfo from "@/components/AccountInfo.vue";
 
export default {
 components: {
   AccountInfo
 },
 data() {
   return {
     user: {
       username: 'matt'
     }
   }
 }
}
</script>

这意味着我们可以更改数据,并使用该值的所有子道具也会更新。

提示:请务必验证您的道具

如果您想编写更清晰的Vue代码,一项重要技术就是验证您的道具。简而言之,这意味着您需要指定道具的要求(即类型,格式等)。如果不满足这些要求之一(例如,如果传递了错误的道具类型),Vue将打印出警告。

假设我们希望用户名属性仅接受字符串。我们将不得不修改props对象,使其看起来像这样:

export default {
 props: {
   username: String
 }
}

在大型Vue应用程序中工作或设计插件时,验证道具至关重要。它有助于确保每个人都在同一页面上,并按预期使用道具。

对于我们可以在道具上包含的验证的完整列表,我绝对建议您查看官方文档以进行深入审查。

提示:遵循道具命名约定

根据VueJS样式指南,命名道具的最佳方法是camelCase在脚本中声明道具时使用,在模板代码中引用道具时使用kebab -case。

这背后的原因实际上很简单。在Javascript中,camelCase是标准的命名约定,而在HTML中,则是kebab-case。

因此,Vue建议我们遵循每种语言的规范。值得庆幸的是,Vue能够在两种样式之间自动转换,因此开发人员无需进行其他设置。

// GOOD
<account-info :my-username="user.username" />
props: {
   myUsername: String
}
 
// BAD
<account-info :myUsername="user.username" />
props: {
   "my-username": String
}

2.发出事件以将数据从儿童共享给父母

现在,我们已经将数据传递到层次结构中,让我们以另一种方式传递它:从子组件到父组件。我们不能使用道具,但可以使用自定义事件和侦听器。

每个Vue实例都可以调用.$emit(eventName)触发事件的方法。然后,我们可以使用v-on指令以与其他事件相同的方式监听此事件。

创建自定义事件

让我们通过添加更改用户名的按钮来构建我们的用户配置文件示例。在子组件(AccountInfo.vue)中,创建按钮。

然后,当点击此按钮时,我们将发出一个名为的事件changeUsername

<template>
 <div id='account-info'>
   <button @click='changeUsername()'>Change Username</button>
   {{username}}
 </div>
</template>
 
<script>
export default {
 props: {
   username: String
 },
 methods: {
   changeUsername() {
     this.$emit('changeUsername')
   }
 }
}
</script>

在父级内部,我们处理此事件并更改user.username变量。就像我们之前讨论的一样,我们可以使用v-on指令或简称“ @”来监听事件。

<template>
 <div>
   <account-info :username="user.username" @changeUsername="user.username = 'new name'"/>
 </div>
</template>

让我们尝试一下。您应该看到单击按钮时,用户名将更改为“新名称”。

提示:自定义事件可以接受参数

将参数传递给事件的最常见用例是,您希望子组件能够为其道具设置特定值。您永远都不想直接从组件本身编辑prop的值。

但是,幸运的是,我们可以将pass参数与自定义事件一起使用,以使父组件更改值。

假设我们要修改changeUsername事件,以便我们可以为其传递值。

$emit方法使用可选的第二个参数作为参数。因此,我们要做的就是在事件名称后添加新的用户名值。

this.$emit('changeUsername', 'mattmaribojoc')

然后,在父组件中,我们可以通过使用特殊$event变量内联访问这些值,也可以编写带有参数的处理程序方法。

<account-info :username="user.username" @changeUsername="user.username = $event"/>
 
OR 
 
<account-info :username="user.username" @changeUsername="changeUsername($event)"/>
 
export default {
...
methods: {
   changeUsername (username) {
     this.user.username = username;
   }
}
}

3.使用Vuex创建应用程序级共享状态

好的-我们知道如何在父母/孩子之间共享数据,但是其他组件呢?如果要传递数据,是否必须创建一个极其复杂的层次结构系统?

幸好没有。美妙的Vuex状态管理库多年来一直在简化开发人员的生活。简而言之,它创建了一个可由所有组件访问的集中式数据存储。

在我们先前使用的方法(属性/发射事件)中,每个组件都有自己的数据状态,然后我们在组件之间共享。但是,Vuex允许我们将所有共享数据提取到单个状态,每个组件都可以轻松访问。此共享状态称为存储。

让我们尝试一下。

由于Vuex与Vue的核心代码是分开的,因此我们首先必须将其安装并导入到我们的项目中。首先,我们必须npm install vuex --save在项目CLI中运行。

然后,使用包含以下代码的index.js文件创建一个src / store文件夹。

// store/index.js
 
import Vue from "vue";
import Vuex from "vuex";
 
Vue.use(Vuex);
 
export default new Vuex.Store({
 state: {},
 getters: {},
 mutations: {},
 actions: {}
});

要将其包含在根Vue实例中,我们必须导入store / index.js文件并将其传递到Vue构造函数中。

// main.js
 
import store from "./store";
 
new Vue({
  store,
  ...

访问组件内部的VUE商店

自从我们将Vuex存储添加到根Vue实例以来,它被注入到根的所有子级中。如果要从组件访问商店,可以通过this.$store

现在,让我们深入了解Vuec商店四个部分的每个细节。

1.状态

Vuex状态是一个包含应用程序级数据的对象。所有Vue实例都将能够访问此数据。

对于我们的商店,让我们创建一个存储更多用户配置文件数据的用户对象。

export default new Vuex.Store({
 state: {
   user: {
     username: 'matt',
     fullName: 'Matt Maribojoc'
   }
 },
 getters: {},
 mutations: {},
 actions: {}
});

我们可以在任何这样的实例组件内部访问此数据。

mounted () {
   console.log(this.$store.state.user.username);
},

2.吸气剂

我们使用Vuex吸气剂返回状态数据的修改值。考虑吸气剂的一种好方法是将它们视为计算属性。例如,像计算属性一样,getter会缓存其结果,并且仅在修改依赖项时才重新评估。

假设我们建立在较早的商店的基础上,我们想创建一个基于全名属性返回用户名字的方法。

getters: {
   firstName: state => {
     return state.user.fullName.split(' ')[0]
   }
 }

Vuex吸气剂属性可用于store.getters对象上的组件。

mounted () {
   console.log(this.$store.getters.firstName);
}
提示:了解默认的Getter参数

默认情况下,Vuex获取器接受两个参数。

  1. state —应用程序的状态对象;
  2. getters — store.getters对象,这意味着我们可以在商店中调用其他getter。

您声明的每个获取方法都将需要第一个状态参数。根据您设计代码的方式,getter可以使用第二个“ getters”参数相互引用。

让我们做一个姓氏获取器,从我们的全名状态属性中删除我们的名字值。此示例将同时需要state和getter对象。

lastName (state, getters) {
     return state.user.fullName.replace(getters.firstName, '');
}
提示:将自定义参数传递给Vuex Getter

getter的另一个很酷的功能是,我们可以通过使getter返回一个方法来传递自定义参数。

prefixedName: (state, getters) => (prefix) => {
     return prefix + getters.lastName;
}
 
// in our component
console.log(this.$store.getters.prefixedName("Mr."));

3.变异

突变是正确更改状态对象的值的唯一方法。需要注意的重要细节是,突变必须是同步的

像吸气剂一样,变异始终将Vuex状态属性作为其第一个参数。他们还接受一个自定义参数(称为有效负载)作为第二个参数。

例如,让我们进行更改以将用户名更改为特定值。

mutations: {
   changeName (state, payload) {
     state.user.fullName = payload
   }
},

然后,我们可以使用方法从组件中调用此方法store.commit,并将有效负载作为第二个参数。

this.$store.commit("changeName", "New Name");

通常,您会希望有效负载成为一个对象。这不仅意味着您可以将多个参数传递给一个突变,而且由于对象中的属性名称,它使您的代码更具可读性。

changeName (state, payload) {
     state.user.fullName = payload.newName
}

有两种使用有效载荷调用变异的方法。

  1. 您可以将变异类型作为第一个参数,将有效载荷作为第二个参数。
  2. 您可以声明传递一个对象,其中一个属性用于类型,另一个属性用于有效负载。
this.$store.commit("changeName", {
       newName: "New Name 1",
});
 
     // or
 
 this.$store.commit({
       type: "changeName",
       newName: "New Name 2"
});

两者的工作方式之间并没有真正的区别,因此完全取决于个人喜好。请记住,在整个项目中始终保持一致是最好的,因此无论您选择哪个,都坚持下去!

4.行动

在Vuex中,动作与变异非常相似,因为我们使用它们来改变状态。但是,动作本身不会更改值。相反,动作会导致突变。

同样,虽然Vuex突变必须是同步的,但动作不是同步的。例如,使用动作,我们可以在API调用之后调用变异。

尽管我们已经看到大多数Vuex处理程序都接受状态作为其主要参数,但动作接受上下文对象。这个上下文对象使我们可以访问Vuex存储中的属性(例如状态,提交,获取器)。

这是一个Vuex操作的示例,该操作等待两秒钟然后提交changeName突变。

actions: {
   changeName (context, payload) {
     setTimeout(() => {
       context.commit("changeName", payload);
     }, 2000);
   }
}

在组件内部,我们使用store.dispatch方法来运行我们的功能。我们传递参数就像处理变异一样。我们声明类型,并在第二个参数中传递任何自定义参数。

this.$store.dispatch("changeName", {
      newName: "New Name from Action"
});

包起来

现在,您应该知道在VueJS中跨组件共享数据的三种不同方式:道具,自定义事件和Vuex存储。

我希望本教程有助于您对某些不同的Vue方法和最佳实践有更多的了解。让我知道您如何将它们实现到您的项目中!

版权所有:https://www.eraycloud.com 转载请注明出处