如何在Vue中创建与事件的用户交互

来自菜鸟教程
跳转至:导航、​搜索

作者选择 Open Sourcing Mental Illness 作为 Write for DOnations 计划的一部分来接受捐赠。

介绍

Vue.js 开发中,客户端的 Web 浏览器读取 HTML 和 JavaScript 并根据开发人员为其编写的指令呈现网页。 但是网页或应用程序不仅需要处理数据; 它还需要处理用户交互。 为此,开发人员使用 JavaScript 中的 事件,当用户与 HTML 元素交互时执行代码。

事件可以捕获与用户界面按钮或物理键盘或鼠标的任何用户交互。 在 JavaScript 中,您将创建 事件侦听器 等待该事件发生,然后执行代码块。 在 Vue.js 中,您不需要监听事件; 这是使用 v-on: 指令自动完成的。

在本教程中,您将使用 Vue 中的事件来创建机场代码的应用程序。 当用户选择一个机场代码时,应用程序会将该机场添加到“收藏夹”集合中。 通过跟随这个项目,您将了解什么是事件、如何使用 Vue 的内置事件以及如何创建自己的自定义事件。

先决条件

要完成本教程,您需要:

第 1 步 — 设置项目

本教程的第一步是设置一个演示项目,其中包含一些要在视图中显示的数据。 这将包括包含机场数据的 JavaScript 对象array 和用于迭代和呈现数据的 Vue 组件

首先,使用 Vue CLI 生成一个项目:

vue create favorite-airports

这将创建一个名为 favorite-airports 的项目。 本教程将使用 Vue 3,因此在出现提示时,选择选项 Default (Vue 3) ([Vue 3] babel, eslint)

OutputVue CLI v4.5.6
? Please pick a preset:
  Default ([Vue 2] babel, eslint)
❯ Default (Vue 3) ([Vue 3] babel, eslint)
  Manually select features

创建项目后,创建一个目录来保存该项目的所有本地数据。 首先,将新项目文件夹设为您的工作目录:

cd favorite-airports

接下来,在src目录下创建一个data目录:

mkdir src/data

在您选择的文本编辑器中,打开一个名为 src/data/airports.js 的文件。 将以下数据添加到文件中:

最喜欢的机场/src/data/airports.js

export default [
  {
    name: 'Cincinnati/Northern Kentucky International Airport',
    abbreviation: 'CVG',
    city: 'Hebron',
    state: 'KY',
  },
  {
    name: 'Seattle-Tacoma International Airport',
    abbreviation: 'SEA',
    city: 'Seattle',
    state: 'WA',
  },
  {
    name: 'Minneapolis-Saint Paul International Airport',
    abbreviation: 'MSP',
    city: 'Bloomington',
    state: 'MN',
  },
  {
    name: 'Louis Armstrong New Orleans International Airport',
    abbreviation: 'MSY',
    city: 'New Orleans',
    state: 'LA',
  },
  {
    name: `Chicago O'hare International Airport`,
    abbreviation: 'ORD',
    city: 'Chicago',
    state: 'IL',
  },
  {
    name: `Miami International Airport`,
    abbreviation: 'MIA',
    city: 'Miami',
    state: 'FL',
  }
]

该数据是由美国几个机场组成的对象数组。 接下来,您将遍历此数据以生成包含 name abbreviationcitystate 属性的卡片。 当用户点击一张卡片时,应用程序将向父级发送一个事件,父级会将该机场添加到代表您最喜欢的机场的数据集合中。

保存并关闭 airport.js 文件。

要呈现数据,请创建一个名为 src/components/AirportCard.vue 的单文件组件 (SFC),然后在文本编辑器中打开它。 该组件将包含机场卡的所有样式和逻辑。

将以下内容添加到文件中:

最喜欢的机场/src/components/AirportCard.vue

<template>
  <div class="airport">
    <p>{{ airport.abbreviation }}</p>
    <p>{{ airport.name }}</p>
    <p>{{ airport.city }}, {{ airport.state }}</p>
  </div>
</template>

<script>
export default {
  props: {
    airport: {
      type: Object,
      required: true
    }
  }
}
</script>

<style scoped>
.airport {
  border: 3px solid;
  border-radius: .5rem;
  padding: 1rem;
}

.airport p:first-child {
  font-weight: bold;
  font-size: 2.5rem;
  margin: 1rem 0;
}

.airport p:last-child {
  font-style: italic;
  font-size: .8rem;
}
</style>

该组件包含一个 prop,它在 Vue.js 中是一种将数据从父组件向下传递到子组件的方法。 template 部分然后呈现此数据。 有关单文件组件的更多信息,请查看 如何使用 Vue 单文件组件创建可重用代码块教程

您可能会注意到代码片段中包含一些 CSS。 在 AirportCard.vue 组件中,包装器 <div> 包含 airport 类。 此 CSS 通过添加边框为生成的 HTML 添加一些样式,使每个机场看起来像一张卡片。 :first-child:last-child伪选择器 ,它们对 [X150X 内部 HTML 中的第一个和最后一个 p 标记应用不同的样式] 的类为 airport

保存文件并退出文本编辑器。

接下来,修改现有的App.vue组件,遍历airports.js数据,渲染一系列AirportCards.vue组件。 在文本编辑器中打开 src/App.vue 并将内容替换为以下突出显示的代码:

最喜欢的机场/src/App.vue

<template>
  <div class="wrapper">
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" />
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'
import allAirports from '@/data/airports.js'
import AirportCard from '@/components/AirportCard.vue'

export default {
  components: {
    AirportCard
  },
  setup() {
    const airports = ref(allAirports)
    return { airports }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-column-gap: 1rem;
  max-width: 960px;
  margin: 0 auto;
}
</style>

这会导入数据和 SFC,然后使用 v-for 指令迭代数据,为 airport.js 数组中的每个对象创建一个机场卡。 它还添加了针对 wrapper 类的额外 CSS,该类使用 CSS 网格 来管理卡片的布局。

保存并退出文件。 现在设置项目后,使用以下命令运行本地开发服务器:

npm run serve

这将在您的 localhost 上启动服务器,通常在端口 :8080 上。 打开您选择的网络浏览器并访问 localhost:8080 以找到以下内容:

现在您已经设置了示例项目,接下来您将使用 v-on 指令探索内置事件。 触发此事件时,将出现一个警报弹出框,其中包含与该事件关联的机场代码。

第 2 步 — 使用 v-on 指令监听事件

如前所述,事件是用户与 DOM(文档对象模型) 中的 HTML 元素交互时执行功能的一种方式。 在编写 vanilla JavaScript 时,要对事件执行函数,您可以编写称为 事件侦听器 的东西。 事件监听器是一个等待交互发生然后执行一些代码的函数。 但是,使用 Vue,您可以为此目的使用 v-on 指令。 指令是一段可重用的代码,开发人员可以使用它来操作 DOM。 v-on 指令由 Vue.js 开箱即用地提供。

在此步骤中,您将在应用程序中创建一个函数,该函数在用户单击卡片时运行。 在您选择的文本编辑器中打开 src/components/AirportCard.vue 组件。

创建一个函数,通过添加以下突出显示的代码来提醒用户他们点击的机场:

最喜欢的机场/src/components/AirportCard.vue

...
<script>
export default {
  props: {
    airport: {
      type: Object,
      required: true
    }
  },
  setup() {
    function selectAirport(airport) {
      alert(`You clicked on ${airport.abbreviation}. It's located in ${airport.city}, ${airport.state}.`)
    }

    return { selectAirport }
  }
}
</script>
...

在 Vue.js 3 中,需要在 setup 组件方法中定义和导出反应函数。 这告诉 Vue 可以执行 <template> 中的 selectAirport 函数。

定义函数后,您现在将其附加到 HTML 元素上的事件。 如前所述,您可以使用 v-on 指令并附加一个名为 click 的事件; 这是 Vue.js 提供的事件。 在 AirportCard.vue 组件中,将 v-on 指令添加到包装器 <div> 中:

最喜欢的机场/src/components/AirportCard.vue

<template>
  <div class="airport" v-on:click="selectAirport(airport)">
    <p>{{ airport.abbreviation }}</p>
    <p>{{ airport.name }}</p>
    <p>{{ airport.city }}, {{ airport.state }}</p>
  </div>
</template>
...

添加此代码后,保存并退出文件。

现在,当您单击卡片时,将弹出一条带有所提供消息的警报。 例如,如果您单击 CVG,您会发现以下内容:

click 事件并不是 Vue.js 开箱即用地提供给您的唯一事件。 实际上,您可以使用 v-on 任何原生 JavaScript 事件,例如:

  • keyup
  • mouseover
  • focus
  • mouseenter
  • change

接下来,您将把这个 v-on:click 监听器更改为 mouseover 以说明 Vue.js 如何监听事件。 mouseover 是一个在鼠标光标移到 HTML 元素上时触发的事件。

再次打开 src/components/AirportCard.vue 并使用以下突出显示的代码更新您的文件:

最喜欢的机场/src/components/AirportCard.vue

<template>
  <div class="airport" @mouseover="selectAirport(airport)">
    <p>{{ airport.abbreviation }}</p>
    <p>{{ airport.name }}</p>
    <p>{{ airport.city }}, {{ airport.state }}</p>
  </div>
</template>

如此处所示,Vue 还具有 v-on: 事件的简写语法。 要使用简写语法,您将 v-on 替换为 @。 保存并退出文件。

现在,当您访问 localhost:8080 并将鼠标悬停在卡片上时,该功能将执行并显示本机警报。

此功能适用于测试目的,但可能不受欢迎,因为每次用户将鼠标悬停在它上面时它都会显示警报。 更好的体验可能是仅在用户第一次将鼠标悬停在该卡片上时才显示它。 在 vanilla JavaScript 中,您可以跟踪用户将鼠标悬停在卡片上的次数,然后阻止进一步执行。 Vue.js 有 事件修饰符,你可以利用它用更少的代码完成同样的事情。

在下一节中,您将探索事件修饰符并使用它们来获得更好的用户体验。

第 3 步 - 使用事件和键修饰符

在上一节中,您对 clickmouseover 事件执行了一个函数。 您还了解了 v-on 事件的 Vue.js 简写。 现在您将通过将修饰符附加到此 mouseover 事件来进一步扩展此功能,以便您的函数只执行一次。

Vue.js 为您提供了许多事件修饰符。 其中一些包括:

  • .stop:停止事件传播
  • .prevent:阻止 HTML 元素的默认行为
  • .capture:处理针对选定元素之前的内部元素的事件
  • .self:仅当 event.target 是元素本身时才触发处理程序
  • .once:只执行一次函数
  • .passive:使元素的默认行为立即发生而不是等待事件,可用于优化移动设备上的滚动性能

在这种情况下,您将使用 .once 修饰符。 在您的文本编辑器中,打开 AirportCard.vue 组件并将修饰符添加到现有的 mouseover 事件中:

最喜欢的机场/src/components/AirportCard.vue

<template>
  <div class="airport" @mouseover.once="selectAirport(airport)">
    <p>{{ airport.abbreviation }}</p>
    <p>{{ airport.name }}</p>
    <p>{{ airport.city }}, {{ airport.state }}</p>
  </div>
</template>

保存文件。 在浏览器中访问您的应用程序,您会发现该事件仅在第一个 mouseover 事件上触发一次。

接下来,您将继续使用 键修饰符 探索修饰符。 这些键修饰符与击键事件相关联,例如 keyup。 对于下一部分,假设您想让这个点击动作更明确一点。 一种方法是在模板中的 .airport <div> 上的 @click 事件中添加一个键修饰符。

为此,将 @mouseover 更改为 @click 并添加 .shift 修饰符:

最喜欢的机场/src/components/AirportCard.vue

<template>
  <div class="airport" @click.shift="selectAirport(airport)">
    <p>{{ airport.abbreviation }}</p>
    <p>{{ airport.name }}</p>
    <p>{{ airport.city }}, {{ airport.state }}</p>
  </div>
</template>

保存更改并在浏览器中打开应用程序。 如果您在没有按住 SHIFT 键的情况下单击卡片,则警报不会执行任何操作。 现在,尝试在单击卡片时按住 SHIFT 键。 您的函数现在将执行,您将收到警报。

在本节中,您了解了 Vue 的内置事件以及与这些事件关联的修饰符。 您可以使用这些内置事件完成很多工作,但有时您需要自定义事件。 在下一节中,您将使用自定义事件向父级发出一个操作,以便它执行一个函数。

第 4 步 - 创建自定义事件

在 Vue.js 中开发应用程序时,有时您需要通过自定义事件将数据传递给父组件。 props 是从父级传递给子级的只读数据,但通过 $emit 的自定义操作与此相反。 要创建最可重用的组件,最好将它们视为函数。 您通过道具(参数)向下传递数据,并将值发送回父级(return 值)。

要从子组件向父组件发出事件,请使用 $emit 函数。 在实现这个之前,本教程将引导您通过一个示例来演示它是如何工作的。

$emit 函数接受两个参数:动作名称(字符串)和传递给父级的值。 在以下示例中,当用户单击按钮时,您将值 CVG 发送到动作 favoriteAirport 下的父组件:

子组件.vue

<template>
  <button @click="$emit('favoriteAirport', 'CVG')">A button</button>
</template>

在父组件中,您将使用 v-on 指令并监听 favoriteAirport 事件。 当这个自定义事件被触发时,代码将对这个值做一些事情:

父组件.vue

<template>
  <child-component @favoriteAirport="favoriteAirport = $event" />
</template>

<script>
import { ref } from 'vue'
export default {
  setup() {
    const favoriteAirport = ref('')

    return { favoriteAirport }
  }
}
</script>

事件的值将是 $event。 在这种情况下,$event 实际上是 CVG,然后您将其存储在名为 favoriteAirport 的响应式数据属性中。

现在您知道自定义事件是什么样子的,您将通过在您的应用程序中实现这个自定义事件来将其付诸实践。

在文本编辑器中打开 AirportCards.vue 组件。 在 @click 事件中,移除对函数的引用,并将其替换为 $emit("favoriteAirport", airport)。 请记住,第一个参数是事件的名称,第二个是您发出的值:

最喜欢的机场/src/components/AirportCard.vue

<template>
  <div class="airport" @click="$emit('favoriteAirport', airport)">
    <p>{{ airport.abbreviation }}</p>
    <p>{{ airport.name }}</p>
    <p>{{ airport.city }}, {{ airport.state }}</p>
  </div>
</template>
...

保存文件。 现在,当用户单击机场卡时,将触发一个自定义事件并传递该 airport 对象。

接下来,打开 src/App.vue 为模板添加一些 HTML。 您将在已经存在的六张卡片之后显示最喜欢的机场列表:

最喜欢的机场/src/App.vue

<template>
  <div class="wrapper">
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" />
    </div>
    <h1 v-if="favoriteAirports.length">Favorite Airports</h1>
    <div v-for="airport in favoriteAirports" :key="airport.abbreviation">
      <airport-card :airport="airport" />
   </div>
  </div>
</template>

<script>
import { ref } from 'vue'
import allAirports from '@/data/airports.js'
import AirportCard from '@/components/AirportCard.vue'

export default {
  components: {
    AirportCard
  },
  setup() {
    const airports = ref(allAirports)
    const favoriteAirports = ref([])

    return { airports, favoriteAirports }
  }
}
</script>
...

在此代码片段中,您将创建一个名为 favoriteAirports 的响应式数据属性,它是一个空数组。 在 <template> 中,您遍历空数组以呈现 <airport-card /> 组件,就像您在前面的步骤中所做的一样。

现在您需要为您的自定义事件添加 v-on 事件:

最喜欢的机场/src/App.vue

<template>
  <div class="wrapper">
    <div v-for="airport in airports" :key="airport.abbreviation">
      <airport-card :airport="airport" @favoriteAirport="favoriteAirports.push($event)" />
    </div>
    <h1 v-if="favoriteAirports.length">Favorite Airports</h1>
    <div v-for="airport in favoriteAirports" :key="airport.abbreviation">
      <airport-card :airport="airport" />
   </div>
  </div>
</template>
...

@favoriteAiport 自定义事件中,您使用 JavaScript push() 方法 将机场从子 ($event) 添加到 favoriteAirports 反应数据财产。

打开浏览器并在 localhost:8080 导航到您的项目。 当您单击其中一张机场卡片时,该卡片将出现在 Favorite Airports 下。

在本节中,您了解了自定义事件、它们是什么以及如何使用它们。 自定义事件是一种通过 Vue 提供的 $emit 函数将数据向上传递给父组件的方式。 发出该数据后,您可以在父组件中进一步操作它,例如将其添加到数组中。

结论

在本教程中,您了解了 Vue.js 如何侦听许多内置事件,例如 clickmouseover。 除此之外,您还尝试了事件和键修饰符,即附加到事件以提供附加功能的小段代码。 有了这个,您将应用程序设置为使用 .once 修饰符执行一次该功能,并且仅在使用 .shift 修饰符按住 SHIFT 键时触发。

Vue 提供了一种有效的事件侦听方法,让您可以专注于操作数据而不是手动设置事件侦听器。 除此之外,Vue 允许您将组件视为函数:它们接受数据 props 并可以返回一个带有 $emit 的值。

要了解更多关于 Vue 组件的信息,建议通读 Vue 文档。 有关 Vue 的更多教程,请查看 如何使用 Vue.js 开发网站系列页面