一文搞懂 Vue 模板语法:插值、指令与过滤器的正确用法

我们都知道 Vue 的模板语法是连接数据与视图的核心桥梁,在 HTML 基础上扩展了一套声明式语法,能够以直观的方式将数据渲染到页面,并实现交互逻辑。本文将解析 Vue 模板语法中的插值、指令和过滤器的用法、技巧与避坑点,来掌握 Vue 模板的编写逻辑。有需要的朋友可以来看看呦!

一、插值语法:数据渲染的基础方式

插值是模板中最常用的语法,用于将组件中的响应式数据动态插入到 HTML 中。Vue 提供了多种插值形式,适用于不同的渲染场景。

1. 文本插值({{ }} 双大括号)

基础用法

最常见的插值形式,用于渲染纯文本内容。双大括号内可以直接使用响应式数据、执行简单表达式,但不能编写复杂语句(如 iffor 循环)。

vue 复制代码
<template>
  <!-- 1. 直接渲染响应式数据 -->
  <div>用户名:{{ username }}</div>
  
  <!-- 2. 支持简单表达式(算术运算、三元判断、字符串拼接) -->
  <div>年龄:{{ age + 1 }}</div>
  <div>是否成年:{{ age >= 18 ? '是' : '否' }}</div>
  <div>欢迎语:{{ 'Hello, ' + username + '!' }}</div>
  
  <!-- 3. 调用组件内方法(注意性能问题) -->
  <div>注册时间:{{ formatTime(registerTime) }}</div>
</template>

<script setup>
import { ref } from 'vue';
const username = ref('张三');
const age = ref(20);
const registerTime = ref(1690000000000);

// 时间格式化方法
const formatTime = (timestamp) => {
  return new Date(timestamp).toLocaleString();
};
</script>

避坑指南

  • ❌ 不要在插值中编写复杂逻辑(如多步计算、数据过滤),会导致模板臃肿且影响性能(组件重渲染时会重复执行)。

    正确做法:用 computed 处理复杂逻辑,再在模板中引用计算属性。

  • ❌ 不要忽略空值处理:当数据可能为 undefinednull 时,直接渲染会显示 undefinednull 文本。

    正确做法:用 || 或三元表达式设置默认值:

    vue 复制代码
    <div>地址:{{ user.address || '未填写' }}</div>
  • ❌ 不要在插值中使用语句:模板表达式只能是 "有返回值的表达式",不能写 iffor 等语句。

2. HTML 插值(v-html 指令)

基础用法

当需要渲染包含 HTML 标签的字符串(如后端返回的富文本)时,{{ }} 会将 HTML 转义为纯文本,此时需用 v-html 指令渲染原始 HTML。

vue 复制代码
<template>
  <!-- 错误:双大括号会转义 HTML,显示 "<p>这是富文本</p>" -->
  <div>{{ richText }}</div>
  
  <!-- 正确:v-html 渲染原始 HTML -->
  <div v-html="richText"></div>
</template>

<script setup>
import { ref } from 'vue';
// 后端返回的富文本内容
const richText = ref('<p style="color: red; font-size: 16px;">这是带样式的文本</p>');
</script>

安全警告
v-html 存在严重的 XSS 攻击风险!如果渲染的内容来自用户输入或不可信来源(如恶意用户注入 <script>alert('攻击')</script>),会导致跨站脚本攻击。

✅ 安全原则:

  • 仅对可信内容 使用 v-html

  • 禁止在用户可编辑的内容(如评论、私信)中使用 v-html

其他注意事项

  • v-html 渲染的 HTML 不会被 Vue 编译,内部的 Vue 指令(如 v-if@click)无法生效;
  • 样式隔离:v-html 内容的样式会受全局 CSS 影响,若需隔离,可使用 scoped 样式 + ::v-deep 穿透。

3. 属性插值(v-bind 指令,简写 :

基础用法

双大括号不能用于 HTML 属性赋值,需用 v-bind 指令(简写 :)将响应式数据绑定到属性上(如 srcclassdisabled 等)。

vue 复制代码
    <template>
      <!-- 1. 绑定普通属性 -->
      <img :src="avatarUrl" :alt="username + '的头像'">
      <div :id="'user-' + userId" :data-role="userRole"></div>
      
      <!-- 2. 绑定布尔属性(值为 true 时添加属性,false 时移除) -->
      <button :disabled="isDisabled">提交</button>
      <input type="checkbox" :checked="isAgreed">
    </template>

    <script setup>
    import { ref } from 'vue';
    const avatarUrl = ref('https://example.com/avatar.png');
    const username = ref('张三');
    const userId = ref(123);
    const userRole = ref('admin');
    const isDisabled = ref(true); // 按钮禁用
    const isAgreed = ref(false); // 复选框未选中
    </script>

进阶:动态绑定 classstyle
classstyle 是属性绑定的高频场景,Vue 支持对象和数组两种语法,满足动态样式需求。

(1)动态绑定 class

  • 对象语法 :适合 "控制单个 / 多个类名是否添加",键为类名,值为布尔值(true 添加,false 移除)。

  • 数组语法:适合 "从多个类名中选择",数组元素为类名字符串或响应式变量。

vue 复制代码
    <template>
      <!-- 对象语法:active 类是否添加取决于 isActive,disabled 同理 -->
      <div class="base" :class="{ active: isActive, disabled: isDisabled }">
        动态类名
      </div>
      
      <!-- 数组语法:从多个类中选择一个(根据 isLarge 切换) -->
      <div :class="[ baseClass, isLarge ? 'large' : 'small' ]">
        数组语法类名
      </div>
    </template>

    <style>
    .base { padding: 10px; }
    .active { color: red; }
    .disabled { background: #eee; }
    .large { font-size: 20px; }
    .small { font-size: 14px; }
    </style>

    <script setup>
    import { ref } from 'vue';
    const isActive = ref(true);
    const isDisabled = ref(false);
    const baseClass = ref('container');
    const isLarge = ref(true);
    </script>

(2)动态绑定 style

  • 对象语法 :键为 CSS 属性(支持驼峰式 fontSize 或短横线式 font-size),值为样式值。

  • 数组语法:用于合并多个样式对象。

vue 复制代码
    <template>
      <!-- 对象语法:动态设置字体大小、颜色 -->
      <div :style="{ fontSize: size + 'px', color: textColor }">
        动态样式
      </div>
      
      <!-- 数组语法:合并基础样式与主题样式 -->
      <div :style="[ baseStyle, themeStyle ]">
        合并样式
      </div>
    </template>

    <script setup>
    import { ref } from 'vue';
    const size = ref(16);
    const textColor = ref('#333');
    const baseStyle = ref({ padding: '10px', margin: '5px' });
    const themeStyle = ref({ border: '1px solid #ccc', borderRadius: '4px' });
    </script>

二、指令语法:控制视图逻辑的核心工具

Vue 指令是带有 v- 前缀的特殊属性,用于在模板中实现条件渲染、循环、事件绑定等逻辑。指令的核心作用是 "将数据逻辑映射到视图行为"。

1. 条件渲染:v-if/v-else-if/v-else

基础用法

根据表达式的布尔值决定元素是否 "存在于 DOM 中"(不是隐藏,而是挂载或销毁),支持多条件判断。

vue 复制代码
    <template>
      <div v-if="role === 'admin'">
        管理员视图:<button>删除数据</button>
      </div>
      <div v-else-if="role === 'editor'">
        编辑者视图:<button>修改内容</button>
      </div>
      <div v-else>
        普通用户视图:仅查看
      </div>
    </template>

    <script setup>
    import { ref } from 'vue';
    const role = ref('editor'); // 渲染编辑者视图
    </script>

进阶:用 <template> 批量控制元素

若需条件渲染多个元素且不想添加额外父容器,可将 v-if 放在 <template> 标签上(<template> 是虚拟容器,不会渲染到 DOM)。

vue 复制代码
    <template>
      <template v-if="showContent">
        <h3>文章标题</h3>
        <p>文章内容...</p>
        <div>作者信息</div>
      </template>
      <div v-else>内容已隐藏</div>
    </template>

    <script setup>
    import { ref } from 'vue';
    const showContent = ref(true);
    </script>

v-if vs v-show:核心区别

特性 v-if v-show
DOM 存在性 false 时元素销毁 始终存在,通过 display: none 隐藏
切换成本 高(挂载 / 销毁,触发生命周期) 低(仅修改 CSS)
初始渲染成本 false 时无成本 无论条件如何,均需渲染
适用场景 低频切换(如权限控制、弹窗) 高频切换(如标签页、折叠面板)

避坑点

  • ❌ 不要在同一元素上同时使用 v-ifv-for(Vue 3 会报警告)。v-for 优先级高于 v-if,会导致先循环所有元素再过滤,浪费性能。
    正确做法:用 <template> 包裹 v-for,或先通过 computed 过滤数据。

2. 循环渲染:v-for

基础用法

根据数组或对象生成重复元素,语法:

  • 遍历数组:v-for="(item, index) in array"item 为元素,index 为索引)

  • 遍历对象:v-for="(value, key, index) in object"value 为值,key 为键)

  • 遍历整数:v-for="num in 5"(生成 5 个元素)

必须配合 key 属性使用key 用于帮助 Vue 识别元素唯一性,优化渲染性能。

vue 复制代码
    <template>
      <!-- 1. 遍历数组(推荐用 item.id 作为 key) -->
      <ul>
        <li v-for="(item, index) in goodsList" :key="item.id">
          {{ index + 1 }}. {{ item.name }} - {{ item.price }}元
        </li>
      </ul>
      
      <!-- 2. 遍历对象 -->
      <div v-for="(value, key) in userInfo" :key="key">
        {{ key }}: {{ value }}
      </div>
    </template>

    <script setup>
    import { ref } from 'vue';
    const goodsList = ref([
      { id: 1, name: '手机', price: 3999 },
      { id: 2, name: '电脑', price: 5999 }
    ]);
    const userInfo = ref({ name: '张三', age: 20, gender: '男' });
    </script>

key 属性的正确用法

  • key 必须唯一:使用后端返回的 id 等唯一标识,避免重复。

  • key 必须稳定:不要用 index 作为 key(列表增删时 index 会变化,导致元素频繁销毁 / 创建)。

vue 复制代码
    <!-- 错误:用 index 作为 key -->
    <li v-for="(item, index) in list" :key="index">...</li>

    <!-- 正确:用唯一 id 作为 key -->
    <li v-for="item in list" :key="item.id">...</li>

3. 事件绑定:v-on(简写 @

基础用法

用于给元素绑定事件(如 clickinput),语法:v-on:事件名="处理函数" 或简写 @事件名="处理函数"。支持传递参数和获取原生事件对象。

vue 复制代码
    <template>
      <!-- 1. 无参数:自动接收事件对象 $event -->
      <button @click="handleClick">点击我</button>
      
      <!-- 2. 带参数:手动传递 $event 获取事件对象 -->
      <div @click="handleItemClick(item.id, $event)">
        {{ item.name }}
      </div>
    </template>

    <script setup>
    import { ref } from 'vue';
    const item = ref({ id: 1, name: '商品A' });

    // 无参数处理函数
    const handleClick = (e) => {
      console.log('点击事件对象:', e.target);
    };

    // 带参数处理函数
    const handleItemClick = (id, e) => {
      console.log('商品ID:', id);
      e.stopPropagation(); // 阻止事件冒泡
    };
    </script>

事件修饰符:简化事件处理

Vue 提供了常用事件修饰符,避免在函数中编写原生代码(如 e.stopPropagation()):

修饰符 作用 示例
.stop 阻止事件冒泡 @click.stop="handleClick"
.prevent 阻止默认行为(如表单提交) @submit.prevent="handleSubmit"
.self 仅元素自身触发时执行 @click.self="handleClick"
.once 事件仅触发一次 @click.once="handleClick"

示例

vue 复制代码
    <!-- 阻止表单默认提交(不刷新页面) -->
    <form @submit.prevent="handleSubmit">
      <button type="submit">提交</button>
    </form>

    <!-- 点击一次后失效 -->
    <button @click.once="handleClickOnce">仅点击一次</button>

4. 双向绑定:v-model

基础用法
v-model 是语法糖,结合 v-bind(绑定值)和 v-on(监听输入),实现 "数据↔视图" 双向同步,常用于表单元素。

vue 复制代码
    <template>
      <!-- 文本输入框 -->
      <input type="text" v-model="username">
      <p>你输入的是:{{ username }}</p>
      
      <!-- 复选框(单个绑定布尔值,多个绑定数组) -->
      <input type="checkbox" v-model="isAgreed"> 同意协议
      <div>
        <input type="checkbox" value="apple" v-model="fruits"> 苹果
        <input type="checkbox" value="banana" v-model="fruits"> 香蕉
      </div>
      
      <!-- 单选框 -->
      <div>
        <input type="radio" value="male" v-model="gender"> 男
        <input type="radio" value="female" v-model="gender"> 女
      </div>
    </template>

    <script setup>
    import { ref } from 'vue';
    const username = ref('');
    const isAgreed = ref(false);
    const fruits = ref([]); // 多个复选框绑定数组
    const gender = ref('male');
    </script>

v-model 修饰符

  • .lazy:失去焦点或按回车时同步数据(默认实时同步)。

  • .number:自动将输入值转为数字类型。

  • .trim:自动去除首尾空格。

vue 复制代码
    <input v-model.lazy="username"> <!-- 失去焦点同步 -->
    <input v-model.number="age"> <!-- 转为数字 -->
    <input v-model.trim="phone"> <!-- 去除空格 -->

5. 其他常用指令

指令 作用 示例
v-pre 跳过编译,显示原始内容(如 {{ }} <div v-pre>{{ 不解析 }}</div>
v-cloak 隐藏未编译的插值(解决闪烁问题) <div v-cloak>{{ message }}</div>
v-once 仅渲染一次,后续数据变化不更新 <div v-once>{{ title }}</div>

三、过滤器(Vue 2 特性,Vue 3 已移除)

过滤器用于在模板中格式化数据(如时间、金额),Vue 2 支持全局和局部过滤器,但 Vue 3 已移除该功能(推荐用 computed 或方法替代)。

Vue 2 过滤器用法

1. 局部过滤器(组件内生效)

在组件的 filters 选项中定义,仅在当前组件使用。

vue 复制代码
    <template>
      <div>时间:{{ createTime | formatTime }}</div>
      <div>金额:{{ price | formatMoney(2) }}</div>
    </template>

    <script>
    export default {
      data() {
        return { createTime: 1690000000000, price: 99.5 };
      },
      filters: {
        // 时间格式化
        formatTime(timestamp) {
          return new Date(timestamp).toLocaleDateString();
        },
        // 金额格式化(保留 n 位小数)
        formatMoney(amount, n = 2) {
          return amount.toFixed(n);
        }
      }
    };
    </script>

2. 全局过滤器(全项目生效)

main.js 中通过 Vue.filter() 定义,所有组件可使用。

vue 复制代码
    // main.js(Vue 2)
    import Vue from 'vue';
    Vue.filter('formatTime', (timestamp) => {
      return new Date(timestamp).toLocaleString();
    });

Vue 3 替代方案

Vue 3 推荐用计算属性工具方法替代过滤器,更灵活且性能更好:

vue 复制代码
    <template>
      <!-- 用计算属性格式化 -->
      <div>时间:{{ formattedTime }}</div>
      <!-- 用工具方法格式化 -->
      <div>金额:{{ formatMoney(price, 2) }}</div>
    </template>

    <script setup>
    import { ref, computed } from 'vue';
    import { formatMoney } from '@/utils/format'; // 导入工具方法

    const createTime = ref(1690000000000);
    const price = ref(99.5);

    // 计算属性(适合依赖响应式数据的格式化)
    const formattedTime = computed(() => {
      return new Date(createTime.value).toLocaleString();
    });
    </script>

四、总结

Vue 模板语法是数据驱动视图的核心,掌握以下要点将大幅提升开发效率:

  1. 插值 :用 {{ }} 渲染文本,v-html 渲染 HTML,v-bind 绑定属性;
  2. 指令v-if/v-for 控制渲染,v-on 绑定事件,v-model 双向绑定;
  3. 过滤器 :Vue 2 可用,Vue 3 推荐用 computed 或工具方法替代;
  4. 性能与安全 :避免复杂表达式,谨慎使用 v-html,正确设置 v-forkey

好了,本次分享的Vue 模板语法到此结束!

相关推荐
wearegogog1237 小时前
基于 MATLAB 的卡尔曼滤波器实现,用于消除噪声并估算信号
前端·算法·matlab
Drawing stars7 小时前
JAVA后端 前端 大模型应用 学习路线
java·前端·学习
品克缤7 小时前
Element UI MessageBox 增加第三个按钮(DOM Hack 方案)
前端·javascript·vue.js
小二·8 小时前
Python Web 开发进阶实战:性能压测与调优 —— Locust + Prometheus + Grafana 构建高并发可观测系统
前端·python·prometheus
小沐°8 小时前
vue-设置不同环境的打包和运行
前端·javascript·vue.js
Irene19918 小时前
Vue3 <Suspense> 使用指南与注意事项
vue.js·suspense
qq_419854058 小时前
CSS动效
前端·javascript·css
烛阴8 小时前
3D字体TextGeometry
前端·webgl·three.js
桜吹雪9 小时前
markstream-vue实战踩坑笔记
前端
C_心欲无痕9 小时前
nginx - 实现域名跳转的几种方式
运维·前端·nginx