如何在Vue.js中使用内置和自定义指令

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

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

介绍

作为一个前端框架,Vue.js 可以被认为是 ReactAngular 的混合体。 Vue 借鉴了 React prop-driven 方法,但也使用了 指令 ,这在 Angular 中很流行。 在这种情况下,指令是开发人员可以在 HTML 模板中使用的可重用代码或逻辑块。 这些可以让您以多种不同的方式操作 HTML,例如有条件地渲染元素、将事件连接到元素或创建依赖于 Vue 代码的动态属性。

在本教程中,您将尝试一些最常见的 Vue 内置指令,例如 v-ifv-showv-onv-bind、[ X136X] 和 v-html。 对于这些第一部分,本教程将引导您完成示例,您可以在 Vue Single File Component Playground 等在线 Vue 游乐场中学习这些示例。 除此之外,您将创建一个新的 Vue 项目来尝试自定义指令,您可以将这些指令添加到 HTML 元素中以获得附加功能。

先决条件

使用 v-ifv-elsev-else-if 指令

Vue.js 预先打包了许多开发人员在框架内工作时常用的指令。 提供v-ifv-showv-onv-modelv-bindv-html等指令为您开箱即用。 所有这些提供的指令都以 v- 开头。

v-ifv-elsev-else-if 指令允许您创建有条件呈现的 HTML 元素,其工作方式类似于 JavaScript 的 if、else if、else 条件 . Vue 不会像在 JavaScript 中那样返回 HTML 或代码,而是有条件地渲染该代码块。

要应用 Vue 指令,您需要将其添加到 Vue 单文件组件template 部分的 HTML 元素中。 例如,如果您想将 v-if 指令添加到段落元素,您将使用以下语法:

<p v-if="condition"></p>

在这种情况下,突出显示的 condition 是布尔表达式的占位符,用于确定是否呈现段落元素。

为了说明 v-if 指令如何在真实情况下工作,请为用户欢迎页面创建以下代码:

<template>
  <p v-if="user.firstName && user.lastName">
    Welcome, {{ user.firstName }} {{ user.lastName }}!
  </p>
  <p v-else-if="user.username">
    Welcome, {{ user.username }}!
  </p>
  <div v-else>
    <button>Login</button>
    <button>Create Account</button>
  </div>
</template>

<script setup>
    const user = {
    firstName: 'Sammy',
    lastName: 'Shark',
    username: 'sammyDO'
  }
</script>

在这段代码中,有许多 HTML 元素,包括两个 <p> 标签和一个带有两个按钮的 <div> 标签。 但是,当此代码在浏览器中运行时,这些代码块中只有一个会呈现,具体取决于评估为 true 的条件。 具有错误条件的 HTML 不会在您的 DOM(文档对象模型)中呈现。

就像现在一样,由于 firstNamelastName<script> 标记中都有值,因此表达式 user.firstName && user.lastName 将计算为 true,并且浏览器将呈现该段落。 这将在您的浏览器中如下图所示:

如果 firstNamelastName 未定义,则条件将评估为 false,并且 Vue 将移动到 v-else-if 指令。 该指令附加到 user.username 表达式,因此如果计算结果为 true 它将呈现附加的段落元素。 要尝试此操作,请删除 <script> 标签中的 firstName

...
<script setup>
    const user = {
    lastName: 'Shark',
    username: 'sammyDO'
  }
</script>

由于条件 user.firstName && user.lastName 现在计算为 falseuser.username 计算为 true,用户名将改为呈现。 如下图所示:

最后,如果所有条件的计算结果为 false,控制将传递给 v-else 指令,该指令在此处呈现两个用于登录或创建帐户的按钮。 要尝试此操作,请删除 script 元素中的 username 数据:

...
<script setup>
    const user = {
    lastName: 'Shark',
  }
</script>

现在您会发现浏览器中呈现的默认按钮:

重要的是要注意,在 v-else-ifv-else 指令之前必须有一个带有 v-if 指令的元素。 否则它将无法正常工作。

例如,以下代码片段被视为无效,您将在浏览器的控制台中收到错误消息:

<template>
  <p v-if="user.firstName && user.lastName">
    Welcome, {{ user.firstName }} {{ user.lastName }}!
  </p>
  <p v-else-if="user.username">
    Welcome, {{ user.username }}!
  </p>
  <h1>Some Title</h1>
  <div v-else>
    <button>Login</button>
    <button>Create Account</button>
  </div>
</template>

<script setup>
    const user = {
    firstName: 'Sammy',
    lastName: 'Shark',
    username: 'sammyDO'
  }
</script>

由于带有 v-else-if 指令的段落后面的 <h1> 元素没有指令,因此此代码将无法呈现并会产生以下语法错误:

OutputSyntaxError: v-else/v-else-if has no adjacent v-if.

有了这个 v-if 的摘要,您现在可以尝试另一种有条件地显示 HTML 元素的方法:v-show 指令。

使用 v-show 指令

除了与 v-if 相关的指令之外,还有另一个指令可用于根据条件显示 HTML 元素。 该指令是 v-show。 它类似于 v-if,除了没有 else-ifelse 对应物并且元素是有条件地显示而不是有条件地渲染。

看看下面的代码,它解决了与上一节类似的情况:

<template>
  <div v-show="!userIsLoggedIn">
    <button>Login</button>
    <button>Create Account</button>
  </div>
  <div v-show="userIsLoggedIn">
    <p>Welcome!</p>
  </div>
</template>

<script setup>
    const userIsLoggedIn = true
</script>

在此代码中,您已将 v-show 与条件表达式一起附加到两个 <div>。 如果满足引号中的条件,v-show 将显示附加的 HTML。 在此示例中,userIsLoggedIn 的计算结果为 true,因此浏览器将显示 <div>Welcome! 段落:

现在将 userIsLoggedIn 值更改为 false

...
<script setup>
    const userIsLoggedIn = false
</script>

您将再次找到登录按钮:

值得强调的是v-ifv-show的区别。 v-if 有条件地渲染 HTML; 如果条件表达式的计算结果为 false,则 DOM 根本不会包含它。 另一方面,v-show 将始终在 DOM 中呈现 HTML。 但是该元素不会出现在浏览器中,因为它将以 display: none CSS 样式隐藏。

在涵盖了条件 v-ifv-show 指令后,您现在可以继续使用 v-on 指令将事件与 HTML 元素联系起来。

使用 v-on 指令

v-on 指令在特定的 event 上执行函数。 这可以是自定义事件或标准 JavaScript 事件,例如 clickhovermouseenter。 使用 v-on 指令时,必须在冒号后提供事件类型 (:) 和要执行的函数。 组件的函数名称将位于引号之间。

例如,检查以下突出显示的代码:

<template>
  <button v-on:click="handleClick">Click Me</button>
</template>

<script setup>
    function handleClick() {
    alert('You clicked the button!')
  }
</script>

在这个例子中,当用户点击指令附加到的 <button> 元素时,组件函数 handleClick 将执行。 如果您运行此代码并单击按钮,您将收到一条警报,内容为 您单击了按钮!

带有 v-on 指令的事件也可以将 事件修饰符 链接到事件本身。 这些事件修饰符可以改变事件的执行方式,并且可以在编写通常需要多行 JavaScript 的功能时节省时间。 Vue 提供的一些修饰符包括:

  • once:将事件限制为仅触发一次。
  • self:仅当事件目标与包含指令的元素相同时才会触发事件。
  • prevent:阻止事件发生。
  • stop:停止传播事件。

接下来,您将运行 once 事件修饰符的示例来尝试语法。 将以下突出显示的代码添加到上一个代码段:

<template>
  <button v-on:click.once="handleClick">Click Me</button>
</template>
...

使用 .once 修饰符,函数 handleClick 只会执行一次。 尝试点击点击我按钮,会弹出提示。 清除警报,然后再次单击它。 该事件不会触发,因为它已经触发过一次。

v-on 指令也有简写语法。 要使用简写语法,请将 v-on: 替换为 @

<template>
  <button @click.once="handleClick">Click Me</button>
</template>
...

这将导致与 v-on:click.once 相同的行为。

现在已经使用 v-on 处理了事件,您可以继续使用 v-bindv-model 将数据绑定到模板元素。

使用 v-bindv-model 指令

Vue.js 是一个 Model-View-ViewModel (MVVM) 框架,这意味着单独的数据(模型)更新 HTML(视图),视图反过来更新模型。 这种分离意味着视图或浏览器中呈现的内容可以独立于数据处理进行操作。

为了制定 MVVM 方法,Vue 提供了将数据、道具和计算属性传递到 Vue 组件的方法。 这是通过 双向数据绑定 完成的,它允许视图和模型相互交互。

在以下代码中,您有一个 <p> 元素,其动态内容会根据数据值而变化:

<template>
  <p>I am from {{ city }}.</p>
</template>

<script setup>
    const city = 'Cincinnati'
</script>

在此代码段中,模板:City 是对其后 <script> 元素中的 city 常量的数据引用。 现在,模板:City 将评估为字符串 "Cincinnati",并且带有单词 I am from Cincinnati 的段落元素将在您的浏览器中呈现。 如果您要将 Cincinnati 更改为 Seattle,则模板中的 模板:City 将相应更新。

对于这个动态内容,您不需要使用指令:模板可以自动访问 city 常量。 但是,如果您想通过引用 <script> 数据使 HTML 属性动态化,则必须将数据显式绑定到 v-bind

为了说明这一点,您将 模板:City 占位符包含在链接 (<a>) 标记中,该标记将动态指向分配给 city 常数。 首先,将 模板:City 包装在 <a> 标记中,以便用户单击它并获取有关城市本身的更多信息。 之后,创建一个名为 wikipediaLink 的计算属性并让它返回适当的 URL。 添加突出显示的代码:

<template>
  <p>I am from <a href="">{{ city }}</a>.</p>
</template>

<script setup>
  import { computed } from 'vue'
  
    const city = 'Cincinnati'
  const wikipediaLink = computed(() =>`https://en.wikipedia.org/wiki/${city}`)
</script>

<script> 元素中,您从 Vue 库中导入了 computed 函数,然后使用它为 wikipediaLink 分配 URL。 URL 字符串使用 模板文字 根据 city 的值进行更改。

现在您有了 Wikipedia 链接,继续将计算的属性名称添加到您之前添加的锚标记的 href 属性中:

<template>
  <p>I am from <a href="wikipediaLink">{{ city }}</a>.</p>
</template>
...

如果此时您要在浏览器中查看此内容,您将收到控制台错误。 这是因为现在 Vue.js 认为 wikipediaLink 是一个字符串文字,它不是一个有效的 URL。

要告诉 Vue.js 使用 wikipediaLink 计算属性的返回值,您需要使用 v-bind 指令。 这会将模板中的引用绑定到计算属性,如下所示:

<template>
  <p>I am from <a v-bind:href="wikipediaLink">{{ city }}</a>.</p>
</template>
...

现在,href 值将是辛辛那提维基百科页面的 URL。 如果 city 属性更改为另一个城市,例如西雅图,此 URL 将更新。

v-on 类似,v-bind 也有一个您可以选择使用的速记。 要使用简写,请将 v-bind: 替换为 :,如下所示:

<template>
  <p>I am from <a :href="wikipediaLink">{{ city }}</a>.</p>
</template>

Vue.js 中有另一个指令用于将值绑定到 data 属性。 但是,该指令仅适用于 input 标签:

<template>
  <input v-model="city" type="text" />
</template>

<script setup>
  const city = 'Cincinnati'
</script>

使用 v-model 指令时,您将输入字段 value 属性绑定到引号中的数据属性。 对于表单 <input /> 标记,建议使用 v-model 指令而不是 v-bind

这个Vue组件会渲染一个文本输入框,默认文本为Cincinnati,如下图所示:

本节介绍了将 HTML 属性绑定到变量或计算数据的不同方法。 接下来,您将使用 v-html 指令将 HTML 注入到您的模板中。

使用 v-html 指令

本教程将介绍的最后一个预打包指令是 v-html。 该指令将字符串文字中的 HTML 转换为原始 HTML 以供浏览器读取,这将使您在创建和应用 HTML 时更加灵活。

在这个假设的组件中,您有一个 <div> ,它有一个 v-html 指令,其值为 data 属性:

<template>
  <div v-html="someHtmlCode" />
</template>

<script setup>
  const someHtmlCode = `<p>Some <span>HTML</span> in this string</p>`
</script>

v-html 指令告诉 Vue.js 将 someHtmlCode 数据引用的字符串注入到模板中的 <div /> 中。 当被 Vue 编译时,你会在你的 DOM 中找到以下内容:

<div>
  <p>Some <span>HTML</span> in this string</p>
</div>

HTML 也会在您的浏览器中呈现:

如果您需要呈现来自 REST API 服务的 HTML 或来自外部 JavaScript 文件的大型 HTML,则此指令很有用。

在本教程的这一点上,您已经试用了 Vue.js 提供给您的指令。 但是,有时您可能需要 Vue 不提供的指令。 在这些情况下,您可以创建自定义指令来处理 HTML 模板中的特定逻辑。

创建自定义指令

在 Vue.js 框架中,您可以创建自定义指令以满足项目的个性化需求。 例如,在本节中,您将创建一个 v-theme 指令,将特定样式应用于模板的元素。

到目前为止,您不必跟随独立的 Vue 项目。 但是,在本节中,您将创建一个从 Vue CLI 生成的新项目。

打开终端并使用以下命令生成一个新项目。 该项目的名称将是 custom-directive,这也是根目录的名称:

vue create custom-directive

对于本教程,为 Choose Vue Version 选择 Vue 3x。 创建应用程序后,在您选择的文本编辑器中打开生成的项目。 然后打开src目录下的main.js文件。

首先,您将设置此文件。 将 createApp(App) 存储到 const 中,以便稍后引用:

自定义指令/src/main.js

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.mount('#app')

现在有了自己的 const 中的 createApp 函数,您可以通过添加指令来扩展此应用程序:

自定义指令/src/main.js

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.directive("theme", {})

app.mount('#app')

在此代码中,您将利用 Vue 实例上的 directive() 函数。 此函数接受两个参数:指令名称(在本例中为 theme)和带有 生命周期挂钩 的对象。

您将设置此代码,使其在组件为 mounted 时执行。 这个挂载的钩子接受两个参数:el,HTML 元素,和 binding,传递给指令的值。 使用此信息,您可以构建以下内容:

自定义指令/src/main.js

const app = createApp(App)

app.directive("theme", {
  mounted(el, binding) {

  }
})

app.mount('#app')

对于这个 theme 指令,您将传入一个字符串来确定元素的样式。 该字符串将是 primarysecondarytertiary,每个都对应于假设颜色方案中的一种颜色。

现在指令代码已经到位,您可以添加逻辑。 要访问指令引号内的值,可以使用 binding.value。 要更改元素文本的颜色,您将使用 JavaScript 访问 el 属性:

自定义指令/src/main.js

const app = createApp(App)

app.directive("theme", {
  mounted(el, binding) {
    if (binding.value === 'primary') {
      el.style.color = 'red'
    } else if (binding.value === 'secondary') {
      el.style.color = 'green'
    } else if (binding.value === 'tertiary') {
      el.style.color = 'blue'
    } else {
      el.style.color = 'black'
    }
  }
})

app.mount('#app')

此片段的突出显示部分是一系列 if/else 语句。 如果传入指令的值为 primary,则文本颜色将为 redsecondary 将为 greentertiary 将为blue,并且没有值将恢复为默认的 black

关闭并保存您的 main.js 文件。

此时,您已经创建了一个可以在 Vue.js 应用程序中使用的自定义指令。 Vue 会自动在指令名称前加上 v-,因此模板可以以 v-theme 的形式访问您的指令。

在您选择的文本编辑器中打开您的 App.vue 文件。 在模板中,添加一个 <p> 标记,其中包含一些文本:

自定义指令/src/App.vue

<template>
  <p>This text will change color based on the directive value!</p>
</template>

保存此文件,然后使用 npm run serve 启动应用程序。 这将在 localhost 上的 :8080 端口上运行您的项目:

npm run serve

要查看您生成的项目,请打开您选择的浏览器并访问 URL 栏中的 localhost:8080。 你会发现你的段落元素呈现为黑色:

接下来,通过将指令添加到 HTML 来更改颜色:

自定义指令/src/App.vue

<template>
  <p v-theme="`primary`">This text will change color based on the directive value!</p>
</template>

保存此文件并在您的网络浏览器中打开它。 引号内的值是原始值并自动绑定到 Vue,因此在引号内您需要使用反引号将 primary 换行以将其转换为字符串。

保存文件,渲染站点上的文本将变为红色:

该指令读取 binding 对象中的值并相应地执行代码。 由于值为 primary,JavaScript 会将文本的颜色更改为红色。

在本节中,您创建了一个自定义指令、注册了它并执行了它的逻辑。 您还添加了新的自定义指令并将其分配给模板中的 HTML 元素。

结论

在本教程中,您通过练习来测试指令是什么以及如何使用它们。 具体来说,您使用了最常见的内置指令,包括 v-ifv-onv-showv-html。 除此之外,您还注册并创建了自己的自定义指令。 该指令 v-theme 现在可用于任何 HTML 元素以执行 JavaScript 函数。

当您浏览了许多指令时,Vue.js 为您提供了更多指令。 有关指令的更多信息,建议查看官方 Vue.js 文档。 有关 Vue 的更多教程,请查看 如何使用 Vue.js 开发网站系列页面