第一部分:Vue 3 基础入门

第7集:模板语法基础:插值与指令

Vue 3的模板语法是连接数据和视图的桥梁,它允许我们在HTML中嵌入动态内容和逻辑。在本集中,我们将学习Vue 3模板语法的基础,包括插值、指令、表达式等内容。

7.1 插值语法

插值是Vue模板中最基本的动态内容渲染方式,使用双大括号{{ }}包裹表达式。

7.1.1 文本插值

作用:将数据渲染为文本内容。

示例

<template>
  <div>
    <h1>{{ message }}</h1>
    <p>{{ count }}</p>
    <p>{{ isActive ? '激活' : '未激活' }}</p>
    <p>{{ user.name }} - {{ user.age }}</p>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const message = ref('Hello Vue 3!')
const count = ref(0)
const isActive = ref(true)
const user = reactive({
  name: '张三',
  age: 25
})
</script>

特点

  • 会自动转义HTML标签,防止XSS攻击
  • 支持JavaScript表达式
  • 会响应数据变化,自动更新视图

7.1.2 原始HTML插值

作用:渲染原始HTML内容。

语法:使用v-html指令。

示例

<template>
  <div>
    <p v-html="rawHtml"></p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const rawHtml = ref('<strong>这是粗体文本</strong>')
</script>

注意事项

  • 谨慎使用,可能导致XSS攻击
  • 只对可信内容使用,不要对用户输入使用

7.1.3 属性插值

作用:动态绑定HTML属性。

语法:使用v-bind指令或简写:

示例

<template>
  <div>
    <img v-bind:src="imageUrl" alt="图片">
    <img :src="imageUrl" :alt="imageAlt">
    <div :class="className"></div>
    <button :disabled="isDisabled">禁用按钮</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const imageUrl = ref('https://example.com/image.jpg')
const imageAlt = ref('示例图片')
const className = ref('box')
const isDisabled = ref(true)
</script>

特点

  • 可以绑定任何HTML属性
  • 支持动态属性名(Vue 3.2+)
  • 支持布尔属性

7.2 指令系统

指令是Vue模板中的特殊属性,以v-前缀开头,用于在DOM上应用特殊的响应式行为。

7.2.1 指令的基本语法

<element v-directive:argument.modifier="value"></element>
  • v-directive:指令名称
  • argument:指令参数
  • modifier:指令修饰符
  • value:指令值

7.2.2 常用指令

1. v-bind

作用:动态绑定属性。

示例

<!-- 完整语法 -->
<a v-bind:href="url">链接</a>

<!-- 简写 -->
<a :href="url">链接</a>

<!-- 动态属性名 -->
<a :[attributeName]="url">链接</a>

<!-- 绑定对象 -->
<div v-bind="objectOfAttrs"></div>
2. v-on

作用:绑定事件监听器。

示例

<!-- 完整语法 -->
<button v-on:click="handleClick">点击</button>

<!-- 简写 -->
<button @click="handleClick">点击</button>

<!-- 带参数 -->
<button @click="handleClick('hello')">点击</button>

<!-- 访问事件对象 -->
<button @click="handleClickWithEvent($event)">点击</button>

<!-- 事件修饰符 -->
<button @click.stop="handleClick">阻止冒泡</button>
<button @click.prevent="handleSubmit">阻止默认行为</button>
<button @click.stop.prevent="handleClick">链式修饰符</button>
<button @click.once="handleClick">只触发一次</button>

<!-- 按键修饰符 -->
<input @keyup.enter="handleEnter">
<input @keyup.esc="handleEsc">
<input @keyup.tab="handleTab">

<!-- 系统修饰符 -->
<button @click.ctrl="handleCtrlClick">Ctrl+点击</button>
<button @click.alt="handleAltClick">Alt+点击</button>
<button @click.shift="handleShiftClick">Shift+点击</button>
<button @click.meta="handleMetaClick">Meta+点击</button>
3. v-model

作用:实现表单元素和数据的双向绑定。

示例

<!-- 文本输入 -->
<input v-model="message" type="text">
<p>{{ message }}</p>

<!-- 多行文本 -->
<textarea v-model="textarea"></textarea>

<!-- 复选框 -->
<input v-model="isChecked" type="checkbox">
<label>{{ isChecked ? '已选中' : '未选中' }}</label>

<!-- 多个复选框 -->
<input v-model="checkedFruits" type="checkbox" value="apple">苹果
<input v-model="checkedFruits" type="checkbox" value="banana">香蕉
<input v-model="checkedFruits" type="checkbox" value="orange">橙子
<p>选中的水果: {{ checkedFruits }}</p>

<!-- 单选按钮 -->
<input v-model="selectedFruit" type="radio" value="apple">苹果
<input v-model="selectedFruit" type="radio" value="banana">香蕉
<input v-model="selectedFruit" type="radio" value="orange">橙子
<p>选中的水果: {{ selectedFruit }}</p>

<!-- 下拉选择 -->
<select v-model="selectedOption">
  <option value="">请选择</option>
  <option value="option1">选项1</option>
  <option value="option2">选项2</option>
  <option value="option3">选项3</option>
</select>
<p>选中的选项: {{ selectedOption }}</p>

<!-- 修饰符 -->
<input v-model.lazy="message" type="text"> <!-- 失去焦点时更新 -->
<input v-model.number="age" type="number"> <!-- 转换为数字 -->
<input v-model.trim="username" type="text"> <!-- 去除首尾空格 -->
4. v-if / v-else-if / v-else

作用:条件渲染。

示例

<template>
  <div>
    <p v-if="score >= 90">优秀</p>
    <p v-else-if="score >= 80">良好</p>
    <p v-else-if="score >= 60">及格</p>
    <p v-else>不及格</p>
    
    <div v-if="isLoggedIn">
      <p>欢迎,{{ username }}!</p>
      <button @click="logout">退出登录</button>
    </div>
    <div v-else>
      <button @click="login">登录</button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const score = ref(85)
const isLoggedIn = ref(false)
const username = ref('张三')

function login() {
  isLoggedIn.value = true
}

function logout() {
  isLoggedIn.value = false
}
</script>

特点

  • 条件为真时才会渲染元素
  • 会销毁和重建元素,触发完整的生命周期
  • v-else必须紧跟在v-ifv-else-if后面
5. v-show

作用:条件显示元素。

示例

<template>
  <div>
    <p v-show="isVisible">这是显示的文本</p>
    <button @click="toggleVisible">切换显示</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const isVisible = ref(true)

function toggleVisible() {
  isVisible.value = !isVisible.value
}
</script>

v-if vs v-show

特性 v-if v-show
渲染方式 条件为真时渲染,为假时销毁 始终渲染,通过CSS display控制显示/隐藏
性能开销 切换时开销大 初始渲染开销大
适用场景 条件不频繁切换 条件频繁切换
支持template
支持v-else
6. v-for

作用:列表渲染。

示例

<template>
  <div>
    <!-- 遍历数组 -->
    <h3>水果列表</h3>
    <ul>
      <li v-for="(fruit, index) in fruits" :key="fruit.id">
        {{ index + 1 }}. {{ fruit.name }} - {{ fruit.price }}元
      </li>
    </ul>
    
    <!-- 遍历对象 -->
    <h3>用户信息</h3>
    <ul>
      <li v-for="(value, key, index) in user" :key="key">
        {{ index + 1 }}. {{ key }}: {{ value }}
      </li>
    </ul>
    
    <!-- 遍历数字 -->
    <h3>数字列表</h3>
    <ul>
      <li v-for="n in 5" :key="n">
        {{ n }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const fruits = ref([
  { id: 1, name: '苹果', price: 5.5 },
  { id: 2, name: '香蕉', price: 3.0 },
  { id: 3, name: '橙子', price: 4.0 }
])

const user = reactive({
  name: '张三',
  age: 25,
  email: 'zhangsan@example.com'
})
</script>

注意事项

  • 必须使用key属性,并且值要唯一
  • key值不能是索引(除非列表不涉及排序、过滤等操作)
  • 不建议在同一元素上使用v-ifv-for(Vue 3会报警告)

7.3 表达式支持

Vue模板支持JavaScript表达式,但有一些限制:

支持的表达式

  • 算术表达式:{{ 1 + 1 }}{{ count * 2 }}
  • 比较表达式:{{ count &gt; 0 }}{{ count === 10 }}
  • 逻辑表达式:{{ isActive &amp;&amp; isVisible }}{{ isActive || isVisible }}
  • 三元表达式:{{ isActive ? &#39;激活&#39; : &#39;未激活&#39; }}
  • 对象和数组:{{ { name: &#39;张三&#39; } }}{{ [1, 2, 3] }}
  • 方法调用:{{ message.toUpperCase() }}{{ formatDate(date) }}
  • 模板字符串:{{ ${user.name} - ${user.age} }}

不支持的表达式

  • 语句:{{ if (isActive) { return &#39;激活&#39; } }}(使用三元表达式替代)
  • 声明:{{ const a = 1 }}{{ let b = 2 }}{{ var c = 3 }}
  • 赋值:{{ count = 1 }}
  • 副作用的表达式:{{ console.log(&#39;hello&#39;) }}{{ count++ }}

7.4 模板语法最佳实践

  1. 保持模板简洁

    • 模板中只放简单的表达式
    • 复杂逻辑放在计算属性或方法中
    • 避免在模板中写过多的JavaScript代码
  2. 合理使用指令

    • 根据场景选择合适的指令
    • 优先使用简写语法(:@
    • 合理使用修饰符
  3. 性能优化

    • 使用v-memo优化频繁渲染的列表
    • 使用v-once优化静态内容
    • 合理使用v-ifv-show
    • v-for提供唯一的key
  4. 代码可读性

    • 指令按逻辑顺序排列
    • 复杂的v-bindv-on可以拆分成多行
    • 使用有意义的变量名和属性名
  5. 安全性

    • 避免使用v-html渲染不可信内容
    • 对用户输入进行验证和过滤
    • 使用计算属性处理敏感数据

本集小结

在本集中,我们学习了Vue 3模板语法的基础:

  • 插值语法:文本插值、原始HTML插值、属性插值
  • 指令系统
    • v-bind:动态绑定属性
    • v-on:绑定事件监听器
    • v-model:双向数据绑定
    • v-if/v-else-if/v-else:条件渲染
    • v-show:条件显示
    • v-for:列表渲染
  • 表达式支持:支持的表达式类型和限制
  • 最佳实践:保持模板简洁、合理使用指令、性能优化等

模板语法是Vue开发的基础,掌握好模板语法可以让我们更高效地开发Vue应用。在下一集中,我们将学习Vue 3的响应式数据,深入了解Vue的响应式系统。

« 上一篇 单文件组件(SFC)揭秘 下一篇 » 响应式数据初体验