深入理解Vue模板语法:数据绑定与HTML交互

一、前言

Vue 采用了基于 HTML 的模板语法,使得数据与 DOM 元素的绑定变得简单和直观。本文将深入剖析 Vue 的模板语法,揭示其背后的工作原理,以及如何充分利用这一强大工具来构建响应式的 Web 应用程序。


二、内容

"所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。"

"在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。"

文本插值

文本插值是最基本的数据绑定形式,它使用双大括号 {{ }} 包裹表达式("Mustache"语法),将数据呈现在页面上。

比如:

html 复制代码
<template>
<span>Message: {{ msg }}</span>
</template>

<script>
export default {
  data() {
    return {
      msg: 'Hello Vue!'
    }
  },
}
</script>

效果:

可以看到,页面上显示了一个文本,内容为相应组件实例中 msg 属性的值。注意,当 msg 的值发生变化时,页面会自动更新。

原始 HTML

注意,双大括号 {{ }} 会将数据解释为纯文本。如果我们需要插入 HTML,可以使用 v-html 指令。

比如:

html 复制代码
<template>
  <p>Using text interpolation: {{ rawHtml }}</p>
  <p>Using v-html directive: <span v-html="rawHtml"></span></p>
</template>

<script>
export default {
  data() {
    return {
      rawHtml: '<span style="color: red">This should be red.</span>'
    }
  },
}
</script>

效果为:

在这里,v-html 指令将 rawHtml 属性的值解释为 HTML,从而在页面上呈现为富文本内容。

值得注意的是,使用 v-html 需要谨慎,因为动态渲染任意HTML存在安全风险,容易造成 XSS 漏洞(一种安全漏洞攻击)。

在 Vue 中,指令是以 v- 前缀的特殊属性,用于在 DOM 元素上添加响应式行为。Vue 提供了许多内置指令,允许您将数据绑定到元素的属性、控制元素的可见性、循环渲染元素、监听事件等。

属性绑定

要在 HTML 属性中绑定数据,可以使用 v-bind 指令。

v-bind 是 Vue 中的一个指令,用于动态绑定 HTML 元素的属性或组件的 prop 。它的主要作用是将数据绑定到 HTML 元素的属性上,以实现响应式的界面更新和数据传递。

比如:

html 复制代码
<a v-bind:href="url">Visit our website</a>
<img v-bind:src="imageUrl" alt="Image">
<div v-bind:class="{'active': isActive, 'error': hasError}">Dynamic classes</div>

上述示例中,v-bind 指令用于绑定hrefsrcclass属性到Vue实例中的数据。注意,如果某些属性值是 nullundefined,则该属性将从元素上移除。

需要注意的是,为了简化属性绑定,Vue 提供了特定的简写语法,将属性名称直接作为指令的参数,而不需要显式写出v-bind

比如:

html 复制代码
<div :id="dynamicId"></div>

可以看到,以冒号 : 开头的属性名是合法的,也不会出现在最终渲染的DOM中,这种简写语法在实际开发中更为常见。

布尔型属性

在 Vue 中,可以使用布尔表达式来决定是否在HTML元素上设置布尔型属性,例如 disabled。Vue 会根据表达式的真假来动态添加或移除该属性。

比如:

html 复制代码
<button :disabled="isButtonDisabled">Click me</button>

在上述代码中,:disabled v-bind 的缩写,用于绑定 disabled 属性。isButtonDisabled 是一个在 Vue 实例中定义的布尔数据,它的值将决定按钮是否被禁用。

其中:

  • isButtonDisabledtrue 时,disabled属性将被添加到按钮上,使按钮禁用;
  • isButtonDisabledfalse 时,disabled属性将被移除,使按钮可用。

可以看到,这种特性使得我们可以根据应用的状态和数据来控制元素的属性,从而实现动态的用户界面。

动态绑定多个值

在 Vue 中,我们可以将多个属性包装在一个JavaScript对象中,并使用不带参数的v-bind指令将整个对象绑定到元素上,以一次性绑定多个属性。

比如,现在有一个 div 元素如下:

html 复制代码
<div v-bind="objectOfAttrs"></div>

那么,我们可以这样写 objectOfAttrs 对象:

js 复制代码
data() {
  return {
    objectOfAttrs: {
      id: 'my-element',
      class: 'active',
      style: 'color: red;',
      disabled: true,
    }
  };
}

这会将 objectOfAttrs 对象中的所有属性和对应的值应用到上述那个 <div> 元素上。

html 复制代码
<div id="my-element" class="active" style="color: red;" disabled="disabled"></div>

使用JavaScript表达式

我们可以使用JavaScript表达式来处理和展示数据。

html 复制代码
{{ ok ? 'YES' : 'NO' }} <!-- 条件控制表达式 -->

Vue 支持在模板中使用 JavaScript 表达式的方式,这些表达式会被作为 JavaScript 代码在当前组件实例的作用域内解析和执行。我们可以在模板中执行各种操作和计算,以生成动态的内容。

比如在文本插值中,我们使用双大括号{{ }}来包含 JavaScript 表达式,表达式的结果将被显示在页面上。

html 复制代码
{{ message + ' is awesome' }} <!-- 合法的表达式 -->
{{ message.split('').reverse().join('') }} <!-- 反转字符串并显示 -->

除了文本插值,我们可以在Vue指令中的属性值中使用JavaScript表达式。例如,使用:class指令动态设置元素的CSS类:

html 复制代码
<div :class="{ 'active': isActive, 'error': hasError }"></div>

这里,JavaScript表达式{ 'active': isActive, 'error': hasError }会根据isActivehasError的值来动态计算元素的类。

另外,我们可以在属性绑定中使用 JavaScript 表达式。例如,使用 :id 绑定元素的 id 属性:

html 复制代码
<div :id="`list-${id}`"></div>

在这个示例中,list-${id}这部分被反引号包围的内容是一个模板字符串。模板字符串允许您在字符串中插入变量值。${id}是一个占位符,表示要插入的变量值是id。Vue会将模板字符串中的${id}替换为实际的id值。

需要注意的是,每个绑定只能包含一个单一的 JavaScript 表达式。这个表达式应该是能够立即求值的,而不是包含语句或条件控制。因此,模板中不支持包含语句,比如变量声明、赋值语句等,不支持使用 if 条件控制语句,而应该使用三元表达式来实现。

以下示例是无效的:

html 复制代码
{{ var a = 1 }} <!-- 无效,包含变量声明 -->
{{ if (ok) { return message } }}  <!-- 不支持if条件控制 -->

使用函数

在表达式中,还可以调用组件暴露的方法。也就是说,在Vue组件中可以封装逻辑和数据,然后在模板中根据需要调用函数。

我们举个例子:

vue 复制代码
<template>
<div>
  <!-- 调用函数并显示结果 -->
  {{ greet('John') }}
</div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello',
    }
  },
  methods: {
    greet(name) {
      return this.message + ', ' + name + '!';
    },
  }
}
</script>

效果如下:

在这个组件中,我们定义了一个greet方法,然后在模板中调用了这个方法,传递了 'John' 作为参数。greet方法会返回一个拼接了消息的字符串,最终会显示在模板中。

注意,绑定在表达式中的方法在每次组件更新时都会被重新调用

有限的全局对象

在模板中的表达式只能访问有限的全局对象,例如MathDate等。查看源码后内容如下:

typescript 复制代码
import { makeMap } from './makeMap'

const GLOBALS_ALLOWED =
  'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +
  'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +
  'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console'

export const isGloballyAllowed = /*#__PURE__*/ makeMap(GLOBALS_ALLOWED)

/** @deprecated use `isGloballyAllowed` instead */
export const isGloballyWhitelisted = isGloballyAllowed

可以看到,上述代码用于限制在 Vue 模板语法中可以访问的全局对象。

我们知道,Vue 的模板语法允许开发者在模板中使用表达式,这些表达式通常用于在模板中渲染数据或执行一些计算。但为了安全性和可控性的考虑,Vue会对这些表达式进行沙盒化,限制其访问全局作用域的对象,只允许访问白名单中列出的一些常用全局对象,以减少潜在的安全风险和不必要的副作用。

这有助于确保Vue应用的稳定性和可维护性。如果开发者需要在模板中使用其他全局对象,可以通过在 app.config.globalProperties 上添加这些对象,使它们在整个应用程序中可用。

类型如下:

typescript 复制代码
interface AppConfig {
  // 一个用于注册能够被应用内所有组件实例访问到的全局属性的对象
  globalProperties: Record<string, any>
}

用法也很简单,比如定义全局属性:

js 复制代码
app.config.globalProperties.myGlobalProperty = 'Hello, Global!'

那么在 Vue 组件的模板中像访问本地属性一样访问全局属性。这个全局属性在模板中是可见的。

html 复制代码
<template>
  <div>
    <p>{{ myGlobalProperty }}</p>
  </div>
</template>

当然,不仅可以在模板中使用全局属性,还可以在组件实例的方法、生命周期钩子等地方通过this访问全局属性。这使得全局属性在组件的逻辑处理中非常有用。

js 复制代码
export default {
  mounted() {
    console.log(this.myGlobalProperty) // 输出:'Hello, Global!'
  }
}

注意事项:

  • 如果一个全局属性与组件自身的属性发生冲突,组件自己的属性将具有更高的优先级。
  • 全局属性应该谨慎使用,只在真正需要在整个应用中共享的数据或函数时使用。滥用全局属性可能会导致代码难以维护和调试。

参数

在 Vue 中,一些指令需要附带参数,这些参数通常指定了指令的具体行为或应用。这些参数在指令名称后面用冒号隔开。

比如,v-bind 指令用于绑定HTML属性的值,你可以使用参数来指定要绑定的属性名称。

vue 复制代码
<template>
  <a v-bind:href="url">Link</a>
</template>

<script>
export default {
  data() {
    return {
      url: 'https://example.com'
    };
  }
}
</script>

在这里,:hrefv-bind 的参数,它指定了要绑定的属性是 href。这将把 url 的值绑定到<a>元素的 href 属性上。

再举一个例子,v-on 指令用于监听DOM事件,你可以使用参数来指定要监听的事件名称。

vue 复制代码
<template>
  <button v-on:click="doSomething">Click me</button>
</template>

<script>
export default {
  methods: {
    doSomething() {
      // 处理点击事件的逻辑
    }
  }
}
</script>

在这里,:clickv-on 的参数,它指定了要监听的事件是 click 事件。当用户点击按钮时,doSomething 方法将被调用。

另外,Vue还提供了简写方式,可以用 @ 符号来代替 v-on

vue 复制代码
<template>
  <button @click="doSomething">Click me</button>
</template>

这个简写方式更加简洁,但具有相同的功能。参数的使用让你可以灵活地控制指令的行为,使代码更加清晰和易于理解。

动态参数

在 Vue 中,我们可以使用动态参数来动态地设置设置指令的参数值。

动态参数是指将参数表达式包含在一对方括号 [] 内,允许你使用JavaScript表达式来计算参数的值。这在需要根据组件的状态或数据来动态设置指令参数时非常有用。

举个例子,比如

vue 复制代码
<template>
  <a :[attributeName]="url">Link</a>
</template>

<script>
export default {
  data() {
    return {
      attributeName: 'href',
      url: 'https://example.com'
    };
  }
}
</script>

在这里,: [attributeName] 是动态参数,它的值由 attributeName 的数据属性决定。如果 attributeName 的值是 "href",那么这个绑定就等价于 v-bind:href,将url的值绑定到<a>元素的href属性上。

再举一个例子,我们可以在 v-on 指令中使用动态参数来监听不同的事件:

vue 复制代码
<template>
  <button @[eventName]="doSomething">Click me</button>
</template>

<script>
export default {
  methods: {
    doSomething() {
      // 处理事件的逻辑
    },
    created() {
      this.eventName = 'click';
    }
  }
}
</script>

在上面的例子中,@[eventName] 是动态参数,eventName 的值决定了要监听的事件名称。在组件创建时,eventName 被设置为 "click",所以它等效于 v-on:click,当用户点击按钮时,doSomething 方法将被调用。

注意事项:

  • 动态参数的表达式值应该是一个字符串或null,其他非字符串值会触发警告。null 的特殊含义是显式移除该绑定。

  • 动态参数表达式有一些语法限制,例如不能包含空格和引号等特殊字符。如果你需要传递复杂的动态参数,建议使用计算属性来代替复杂的表达式。

  • 此外,当你在 DOM 内嵌模板中使用动态参数时,需要注意浏览器会将属性名转换为小写,所以尽量避免使用大写字母。在单文件组件内的模板不受此限制。

修饰符

修饰符是以点号 . 开头的特殊后缀,用于改变指令的默认行为或添加额外的功能。

比如,.prevent 修饰符用于阻止元素的默认行为,通常在处理表单提交时会用到,以避免页面刷新。

vue 复制代码
<form @submit.prevent="onSubmit">...</form>

.stop 修饰符可以阻止事件继续传播,即停止事件在 DOM 树上传播。

vue 复制代码
<div @click.stop="handleClick">...</div>

.once 修饰符可以让事件处理函数只执行一次。

vue 复制代码
<button @click.once="handleClick">...</button>

修饰符可以组合使用,比如 .stop.prevent 会同时阻止事件冒泡和默认行为。我们会在后面继续记录修饰符的用法。

小结

三、总结

综上所述,Vue的模板语法提供了多种方式来实现数据绑定、HTML插入、属性绑定等功能。通过了解这些核心概念,我们可以更好地理解Vue的工作原理,并能够更高效地构建出功能丰富的Vue应用程序。同时,本文还介绍了动态参数和修饰符等高级用法,可以更好地掌握Vue的强大功能。

相关推荐
Jiaberrr2 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
LvManBa3 小时前
Vue学习记录之六(组件实战及BEM框架了解)
vue.js·学习·rust
200不是二百3 小时前
Vuex详解
前端·javascript·vue.js
LvManBa3 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
深情废杨杨4 小时前
前端vue-父传子
前端·javascript·vue.js
工业互联网专业4 小时前
毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计
J不A秃V头A5 小时前
Vue3:编写一个插件(进阶)
前端·vue.js
司篂篂5 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客5 小时前
pinia在vue3中的使用
前端·javascript·vue.js
天下无贼!7 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue