Vue框架之模板语法全面解析

Vue框架之模板语法全面解析

    • 一、模板语法的核心思想
    • 二、插值表达式:数据渲染的基础
      • 2.1 基本用法:渲染文本
      • 2.2 纯HTML渲染:`v-html`指令
      • 2.3 一次性插值:`v-once`指令
    • 三、指令系统:控制DOM的行为
      • 3.1 条件渲染:`v-if`与`v-show`
        • 3.1.1 `v-if`:动态创建/销毁元素
        • 3.1.2 `v-else`与`v-else-if`:条件分支
        • 3.1.3 `v-show`:动态显示/隐藏元素
        • 3.1.4 `v-if`与`v-show`的区别
      • 3.2 列表渲染:`v-for`
        • 3.2.1 遍历数组
        • 3.2.2 遍历对象
        • 3.2.3 `key`属性的重要性
      • 3.3 属性绑定:`v-bind`
        • 3.3.1 基础用法
        • 3.3.2 绑定class的特殊用法
        • 3.3.3 绑定style的特殊用法
      • 3.4 事件绑定:`v-on`
        • 3.4.1 基础用法
        • 3.4.2 传递事件参数
        • 3.4.3 事件修饰符
      • 3.5 表单绑定:`v-model`
        • 3.5.1 文本框与文本域
        • 3.5.2 复选框与单选框
        • 3.5.3 下拉框
        • 3.5.4 修饰符
    • 四、模板语法的进阶技巧
      • 4.1 计算属性:`computed`
      • 4.2 侦听器:`watch`
      • 4.3 模板中的注释
    • 五、常见问题与避坑指南
      • 5.1 插值表达式不能使用语句
      • 5.2 `v-for`与`v-if`同时使用的陷阱
      • 5.3 响应式数据更新不触发视图

Vue的模板语法是连接数据与视图的桥梁,它允许我们开发者以声明式的方式将数据渲染到DOM中,同时支持丰富的指令和表达式,掌握模板语法是使用Vue开发页面的基础,本文我将从插值表达式、指令系统、事件处理到表单绑定,系统解析Vue模板语法的核心知识点,并结合实例演示其用法。

一、模板语法的核心思想

Vue的模板语法基于HTML扩展,核心思想是声明式渲染:开发者只需关注“数据应该如何展示”,而无需手动操作DOM。模板中的特殊语法会被Vue编译器处理,最终转换为渲染函数,生成对应的DOM节点。


<div id="app">
  <h1>{{ message }}h1>
div>

<script>
const app = new Vue({
  el: '#app',
  data() {
    return {
      message: 'Hello Vue Template!'
    }
  }
});
script>

上述代码中,{{ message }}是模板语法的核心——插值表达式,它会将Vue实例中的message数据实时渲染到页面中。当message的值变化时,页面会自动更新,这就是Vue的响应式渲染特性。

二、插值表达式:数据渲染的基础

插值表达式是模板中最基础的语法,用于将数据插入到DOM中,语法为{{ 表达式 }}

2.1 基本用法:渲染文本

<div id="app">
  
  <p>姓名:{{ name }}p>
  
  
  <p>年龄+1:{{ age + 1 }}p>
  
  
  <p>大写姓名:{{ name.toUpperCase() }}p>
  
  
  <p>是否成年:{{ age >= 18 ? '是' : '否' }}p>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      name: 'zhangsan',
      age: 20
    }
  }
});
script>

特性

  • 支持JavaScript表达式(如+toUpperCase()、三元运算),但不能写语句(如iffor);
  • 数据变化时自动更新(响应式);
  • 会自动转义HTML(防止XSS攻击),例如{{ '

    标题

    ' }}
    会渲染为纯文本,而非HTML标签。

2.2 纯HTML渲染:v-html指令

如果需要渲染包含HTML标签的字符串,需使用v-html指令(注意XSS风险):

<div id="app">
  
  <p>{{ rawHtml }}p> 
  
  
  <p v-html="rawHtml">p> 
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      rawHtml: '红色文本'
    }
  }
});
script>

注意

  • v-html会覆盖元素的子节点;
  • 动态渲染HTML存在XSS风险,仅在内容完全可信时使用;
  • 不能用于单文件组件(SFC)的模板根节点。

2.3 一次性插值:v-once指令

如果数据只需渲染一次,后续变化不再更新,可使用v-once

<div id="app">
  <p v-once>初始值:{{ message }}p>
  <p>实时值:{{ message }}p>
  <button @click="message = '新值'">修改值button>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      message: '初始值'
    }
  }
});
script>

点击按钮后,v-once所在的段落仍显示“初始值”,而另一段落会更新为“新值”。

三、指令系统:控制DOM的行为

Vue提供了一系列内置指令(以v-为前缀),用于控制DOM的行为,如条件渲染、列表渲染、事件绑定等。

3.1 条件渲染:v-ifv-show

3.1.1 v-if:动态创建/销毁元素

v-if根据表达式的真假,动态创建或销毁元素(完全从DOM中移除):

<div id="app">
  <p v-if="isShow">这是v-if控制的内容p>
  <button @click="isShow = !isShow">切换显示button>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      isShow: true
    }
  }
});
script>
3.1.2 v-elsev-else-if:条件分支
<div id="app">
  <p v-if="score >= 90">优秀p>
  <p v-else-if="score >= 60">及格p>
  <p v-else>不及格p>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      score: 85
    }
  }
});
script>
3.1.3 v-show:动态显示/隐藏元素

v-show通过CSS的display属性控制元素显示(display: none),元素始终存在于DOM中:

<div id="app">
  <p v-show="isShow">这是v-show控制的内容p>
  <button @click="isShow = !isShow">切换显示button>
div>
3.1.4 v-ifv-show的区别
特性 v-if v-show
原理 动态创建/销毁DOM元素 通过display: none控制显示
初始渲染成本 条件为假时,无渲染成本 无论条件真假,都有初始渲染成本
切换成本 较高(涉及DOM操作) 较低(仅修改CSS)
适用场景 条件很少切换(如权限控制) 条件频繁切换(如标签页切换)

3.2 列表渲染:v-for

v-for用于循环渲染列表数据,支持数组、对象、字符串和数字,语法为v-for="(item, index) in items"

3.2.1 遍历数组
<div id="app">
  <ul>
    
    <li v-for="(item, index) in fruits" :key="item.id">
      {{ index + 1 }}. {{ item.name }} - 价格:{{ item.price }}元
    li>
  ul>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      fruits: [
        { id: 1, name: '苹果', price: 5 },
        { id: 2, name: '香蕉', price: 3 },
        { id: 3, name: '橙子', price: 4 }
      ]
    }
  }
});
script>
3.2.2 遍历对象
<div id="app">
  <ul>
    
    <li v-for="(value, key, index) in user" :key="key">
      {{ index + 1 }}. {{ key }}: {{ value }}
    li>
  ul>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      user: {
        name: '张三',
        age: 25,
        gender: '男'
      }
    }
  }
});
script>
3.2.3 key属性的重要性

v-for渲染列表时,必须添加key属性(唯一标识),Vue通过key识别元素的身份,优化DOM更新性能:


<li v-for="item in list">{{ item }}li>


<li v-for="item in list" :key="item.id">{{ item.name }}li>

注意

  • key的值必须唯一,不能重复;
  • 不要用index作为key(数组排序、删除元素时会导致身份错乱);
  • 推荐使用数据的唯一ID作为key(如后端返回的id)。

3.3 属性绑定:v-bind

v-bind用于动态绑定HTML属性,语法为v-bind:属性名="表达式",可简写为:属性名

3.3.1 基础用法
<div id="app">
  
  <img :src="imgUrl" alt="图片">
  
  
  <div :class="boxClass">这是一个divdiv>
  
  
  <p :style="textStyle">这是带样式的文本p>
  
  
  <div :data-id="itemId">div>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      imgUrl: 'https://picsum.photos/200',
      boxClass: 'container active',
      textStyle: {
        color: 'red',
        fontSize: '16px'
      },
      itemId: 123
    }
  }
});
script>
3.3.2 绑定class的特殊用法

class属性支持对象和数组语法,动态控制类名:

<div id="app">
  
  <div :class="{ active: isActive, 'text-danger': hasError }">div>
  
  
  <div :class="[baseClass, isActive ? 'active' : '']">div>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      isActive: true,
      hasError: false,
      baseClass: 'container'
    }
  }
});
script>
3.3.3 绑定style的特殊用法

style属性支持对象和数组语法,动态控制样式:

<div id="app">
  
  <div :style="{ color: textColor, fontSize: fontSize + 'px' }">div>
  
  
  <div :style="[baseStyle, highlightStyle]">div>
script>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      textColor: 'blue',
      fontSize: 16,
      baseStyle: { padding: '10px' },
      highlightStyle: { backgroundColor: 'yellow' }
    }
  }
});
script>

3.4 事件绑定:v-on

v-on用于绑定事件监听器,语法为v-on:事件名="处理函数",可简写为@事件名

3.4.1 基础用法
<div id="app">
  
  <button @click="handleClick">点击我button>
  
  
  <input @input="handleInput" placeholder="输入内容">
  
  
  <button @click="count++">计数器:{{ count }}button>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleClick() {
      alert('按钮被点击了');
    },
    handleInput(e) {
      console.log('输入内容:', e.target.value); // e是原生事件对象
    }
  }
});
script>
3.4.2 传递事件参数
<div id="app">
  
  <button @click="handleClick">无参数button>
  
  
  <button @click="handleClickWithParams('参数1', $event)">带参数button>
div>

<script>
new Vue({
  el: '#app',
  methods: {
    handleClick(e) {
      console.log('事件对象:', e);
    },
    handleClickWithParams(param, e) {
      console.log('参数:', param);
      console.log('事件对象:', e);
    }
  }
});
script>
3.4.3 事件修饰符

Vue提供了事件修饰符,简化事件处理(如阻止默认行为、阻止冒泡):

<div id="app">
  
  <form @submit.prevent="handleSubmit">
    <button type="submit">提交button>
  form>
  
  
  <div @click="parentClick">
    <button @click.stop="childClick">点击button>
  div>
  
  
  <button @click.once="handleOnce">只触发一次button>
div>

<script>
new Vue({
  el: '#app',
  methods: {
    handleSubmit() {
      console.log('表单提交');
    },
    parentClick() {
      console.log('父元素事件');
    },
    childClick() {
      console.log('子元素事件');
    },
    handleOnce() {
      console.log('只触发一次');
    }
  }
});
script>

常用事件修饰符:

  • .prevent:阻止默认行为(如e.preventDefault());
  • .stop:阻止事件冒泡(如e.stopPropagation());
  • .once:事件只触发一次;
  • .self:仅当事件目标是元素自身时触发;
  • .enter:仅在按键为Enter时触发(键盘事件专用)。

3.5 表单绑定:v-model

v-model用于在表单元素(输入框、复选框等)与数据之间创建双向绑定,本质是v-bind绑定valuev-on监听input事件的语法糖。

3.5.1 文本框与文本域
<div id="app">
  
  <input v-model="username" placeholder="用户名">
  <p>用户名:{{ username }}p>
  
  
  <textarea v-model="message" rows="3" placeholder="留言">textarea>
  <p>留言:{{ message }}p>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      username: '',
      message: ''
    }
  }
});
script>
3.5.2 复选框与单选框
<div id="app">
  
  <div>
    <label>
      <input type="radio" v-model="gender" value="male">label>
    <label>
      <input type="radio" v-model="gender" value="female">label>
    <p>性别:{{ gender }}p>
  div>
  
  
  <div>
    <label>
      <input type="checkbox" v-model="isAgree"> 同意协议
    label>
    <p>是否同意:{{ isAgree }}p>
  div>
  
  
  <div>
    <label>
      <input type="checkbox" v-model="hobbies" value="reading"> 阅读
    label>
    <label>
      <input type="checkbox" v-model="hobbies" value="sports"> 运动
    label>
    <p>爱好:{{ hobbies }}p>
  div>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      gender: 'male',
      isAgree: false,
      hobbies: []
    }
  }
});
script>
3.5.3 下拉框
<div id="app">
  
  <select v-model="selectedCity">
    <option value="">请选择城市option>
    <option value="beijing">北京option>
    <option value="shanghai">上海option>
  select>
  <p>选中城市:{{ selectedCity }}p>
  
  
  <select v-model="selectedCities" multiple>
    <option value="beijing">北京option>
    <option value="shanghai">上海option>
    <option value="guangzhou">广州option>
  select>
  <p>选中城市:{{ selectedCities }}p>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      selectedCity: '',
      selectedCities: []
    }
  }
});
script>
3.5.4 修饰符

v-model提供了修饰符,处理表单数据:

  • .trim:自动去除首尾空格;
  • .number:将输入值转为数字(无法转换时保留字符串);
  • .lazy:在change事件(而非input)时更新数据(适合输入完成后验证)。
<div id="app">
  <input v-model.trim="username" placeholder="自动去空格">
  <input v-model.number="age" placeholder="仅数字">
  <input v-model.lazy="search" placeholder="失去焦点后更新">
div>

四、模板语法的进阶技巧

4.1 计算属性:computed

当模板中的表达式逻辑复杂时,推荐使用计算属性(computed),它具有缓存特性,依赖数据不变时不会重新计算。

<div id="app">
  <p>原始价格:{{ price }}p>
  <p>折扣价(9折):{{ discountedPrice }}p>
  <p>折扣价(8折):{{ getDiscountedPrice(0.8) }}p>
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      price: 100
    }
  },
  computed: {
    // 计算属性(缓存)
    discountedPrice() {
      console.log('计算属性执行');
      return this.price * 0.9;
    }
  },
  methods: {
    // 方法(无缓存,每次调用都执行)
    getDiscountedPrice(discount) {
      console.log('方法执行');
      return this.price * discount;
    }
  }
});
script>

计算属性 vs 方法

  • 计算属性:依赖数据变化时才重新计算,适合频繁访问且逻辑复杂的场景;
  • 方法:每次调用都执行,适合需要动态参数的场景。

4.2 侦听器:watch

watch用于监听数据变化,执行异步或复杂逻辑(如数据变化后发送请求)。

<div id="app">
  <input v-model="username" placeholder="输入用户名">
div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      username: ''
    }
  },
  watch: {
    // 监听username变化
    username(newVal, oldVal) {
      console.log(`用户名从${oldVal}变为${newVal}`);
      // 模拟异步请求(如验证用户名是否已存在)
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        console.log(`验证用户名:${newVal}`);
      }, 500);
    }
  }
});
script>

4.3 模板中的注释

Vue模板支持HTML注释和Vue特有的注释(不会被渲染到DOM中):

<div id="app">
  
  {{ /* 这是Vue注释,不会被渲染 */ }}
div>

五、常见问题与避坑指南

5.1 插值表达式不能使用语句


<p>{{ if (isShow) { return '显示' } else { return '隐藏' } }}p>


<p>{{ isShow ? '显示' : '隐藏' }}p>

5.2 v-forv-if同时使用的陷阱

不建议在同一元素上同时使用v-forv-if,因为v-for的优先级高于v-if,会导致每次循环都执行条件判断,影响性能。

错误示例


<li v-for="item in list" v-if="item.isActive" :key="item.id">
  {{ item.name }}
li>

正确示例:先过滤数据,再循环


<li v-for="item in activeItems" :key="item.id">
  {{ item.name }}
li>

<script>
new Vue({
  computed: {
    activeItems() {
      return this.list.filter(item => item.isActive);
    }
  }
});
script>

5.3 响应式数据更新不触发视图

Vue的响应式系统依赖Object.defineProperty(Vue 2),直接修改数组索引或对象属性可能不会触发视图更新:

// 错误:直接修改数组索引
this.list[0] = '新值'; // 视图不更新

// 正确:使用Vue提供的方法或重新赋值
this.list.splice(0, 1, '新值'); // 或 this.list = [...this.list, 新值]

// 错误:直接添加对象属性
this.user.age = 25; // 视图不更新

// 正确:使用Vue.set或重新赋值
this.$set(this.user, 'age', 25); // 或 this.user = { ...this.user, age: 25 }

总结:Vue的模板语法是其声明式编程模型的核心,通过简洁的语法将数据与视图关联

  • 简化DOM操作:无需手动操作DOM,专注数据逻辑;
  • 响应式更新:数据变化自动同步到视图;
  • 丰富的指令v-ifv-forv-model等指令覆盖常见场景;
  • 灵活的扩展:计算属性、侦听器处理复杂逻辑。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

你可能感兴趣的:(Vue,vue.js)