<返回目录     Powered by claud/xia兄

第2课: 模板语法与数据绑定

深入理解Vue3模板语法原理,掌握各种数据绑定方式

📚 学习目标

🎯 模板语法基础

Vue3的模板语法基于HTML,通过特殊的语法将数据绑定到DOM。模板会被Vue的编译器编译成渲染函数,最终生成虚拟DOM。

🔬 模板编译原理

编译过程:HTML模板 → 抽象语法树(AST) → 渲染函数 → 虚拟DOM → 真实DOM

编译时优化特性

📝 文本插值(Mustache语法)

使用双大括号{{ }}进行文本插值,这是Vue最基本的数据绑定方式。

基础用法

<template>
  <div>
    <!-- 简单文本插值 -->
    <p>{{ message }}</p>
    
    <!-- JavaScript表达式 -->
    <p>{{ firstName + ' ' + lastName }}</p>
    <p>{{ count * 2 }}</p>
    <p>{{ isActive ? '激活' : '未激活' }}</p>
    
    <!-- 方法调用 -->
    <p>{{ getFullName() }}</p>
    
    <!-- 计算属性 -->
    <p>{{ reversedMessage }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue3',
      firstName: '张',
      lastName: '三',
      count: 10,
      isActive: true
    }
  },
  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('')
    }
  },
  methods: {
    getFullName() {
      return this.firstName + this.lastName
    }
  }
}
</script>
原理说明:文本插值中的表达式会在所属组件实例的数据作用域下作为JavaScript被解析。每个绑定只能包含单个表达式,不能包含语句或流程控制。

🔤 原始HTML渲染(v-html指令)

使用v-html指令可以渲染原始HTML内容,而不是将其作为纯文本显示。

基本用法

<template>
  <div>
    <!-- 文本插值:显示原始HTML代码 -->
    <p>普通文本: {{ rawHtml }}</p>
    
    <!-- v-html指令:渲染HTML内容 -->
    <p>HTML内容: <span v-html="rawHtml"></span></p>
    
    <!-- 动态HTML内容 -->
    <div v-html="dynamicContent"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      rawHtml: '<strong style="color: red;">加粗的红色文本</strong>',
      dynamicContent: '<div class="alert alert-success">操作成功!</div>'
    }
  }
}
</script>

⚠️ 安全警告与最佳实践

XSS攻击风险:v-html会直接插入HTML到DOM中,可能导致跨站脚本攻击。

安全使用原则

安全示例

<template>
  <div>
    <!-- 不安全:用户输入 -->
    <div v-html="userInput"></div>
    
    <!-- 安全:可信内容 -->
    <div v-html="trustedContent"></div>
    
    <!-- 更安全:使用组件 -->
    <RichTextRenderer :content="sanitizedContent" />
  </div>
</template>

<script>
import DOMPurify from 'dompurify'

export default {
  data() {
    return {
      userInput: '', // 危险!不要直接渲染
      trustedContent: '<p>来自可信来源的内容</p>'
    }
  },
  computed: {
    sanitizedContent() {
      return DOMPurify.sanitize(this.userInput)
    }
  }
}
</script>

🔗 属性绑定(v-bind指令)

v-bind指令用于动态绑定HTML属性,将属性值与Vue实例的数据关联起来。

🔬 v-bind工作原理

响应式绑定机制:当绑定的数据发生变化时,Vue会自动更新对应的DOM属性。

编译过程

// 模板中的v-bind
<img :src="imageUrl" :alt="imageAlt">

// 编译后的渲染函数
h('img', {
  src: _ctx.imageUrl,
  alt: _ctx.imageAlt
})
原理说明:v-bind指令在编译阶段被转换为渲染函数的属性对象,Vue的响应式系统会跟踪这些属性的依赖关系。

语法详解

<template>
  <div>
    <!-- 1. 完整语法 -->
    <img v-bind:src="imageUrl" v-bind:alt="imageAlt">

    <!-- 2. 简写语法(推荐) -->
    <img :src="imageUrl" :alt="imageAlt">

    <!-- 3. 动态属性名 -->
    <button :[attributeName]="value">按钮</button>

    <!-- 4. 布尔属性 -->
    <button :disabled="isDisabled">提交</button>

    <!-- 5. 绑定对象 -->
    <div v-bind="objectOfAttrs">绑定多个属性</div>

    <!-- 6. 表达式绑定 -->
    <a :href="'/user/' + userId">用户详情</a>

    <!-- 7. 方法返回值绑定 -->
    <input :value="getInputValue()">
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: 'https://vuejs.org/logo.svg',
      imageAlt: 'Vue Logo',
      attributeName: 'id',
      value: 'dynamic-id',
      isDisabled: true,
      userId: 123,
      objectOfAttrs: {
        id: 'container',
        class: 'wrapper',
        'data-test': 'test-value'
      }
    }
  },
  methods: {
    getInputValue() {
      return this.userId.toString()
    }
  }
}
</script>

Class绑定

<template>
  <div>
    <!-- 对象语法 -->
    <div :class="{ active: isActive, 'text-danger': hasError }">
      对象语法
    </div>

    <!-- 数组语法 -->
    <div :class="[activeClass, errorClass]">
      数组语法
    </div>

    <!-- 数组与对象混合 -->
    <div :class="[{ active: isActive }, errorClass]">
      混合语法
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isActive: true,
      hasError: false,
      activeClass: 'active',
      errorClass: 'text-danger'
    }
  }
}
</script>

Style绑定

<template>
  <div>
    <!-- 对象语法 -->
    <div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
      对象语法
    </div>

    <!-- 绑定样式对象 -->
    <div :style="styleObject">
      样式对象
    </div>

    <!-- 数组语法 -->
    <div :style="[baseStyles, overridingStyles]">
      数组语法
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      activeColor: 'red',
      fontSize: 30,
      styleObject: {
        color: 'blue',
        fontSize: '20px'
      },
      baseStyles: { color: 'green' },
      overridingStyles: { fontSize: '25px' }
    }
  }
}
</script>

双向绑定(v-model)

<template>
  <div>
    <!-- 文本输入 -->
    <input v-model="message" placeholder="输入文本">
    <p>输入的内容: {{ message }}</p>

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

    <!-- 复选框 -->
    <input type="checkbox" v-model="checked">
    <p>选中状态: {{ checked }}</p>

    <!-- 单选按钮 -->
    <input type="radio" value="男" v-model="gender"> 男
    <input type="radio" value="女" v-model="gender"> 女
    <p>选择: {{ gender }}</p>

    <!-- 下拉选择 -->
    <select v-model="selected">
      <option disabled value="">请选择</option>
      <option>A</option>
      <option>B</option>
      <option>C</option>
    </select>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: '',
      description: '',
      checked: false,
      gender: '',
      selected: ''
    }
  }
}
</script>

v-model修饰符

<template>
  <div>
    <!-- .lazy: 在change事件后同步 -->
    <input v-model.lazy="msg">

    <!-- .number: 自动转换为数字 -->
    <input v-model.number="age" type="number">

    <!-- .trim: 自动过滤首尾空白字符 -->
    <input v-model.trim="username">
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: '',
      age: 0,
      username: ''
    }
  }
}
</script>

组合式API写法

<template>
  <div>
    <p>{{ message }}</p>
    <input v-model="message">
    <button :disabled="isDisabled">按钮</button>
  </div>
</template>

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

const message = ref('Hello Vue3')
const isDisabled = ref(false)
</script>

练习

  1. 创建一个表单,包含姓名、年龄、性别输入框,使用v-model实现双向绑定
  2. 实现一个动态样式切换,点击按钮改变文字颜色和大小
  3. 创建一个待办事项输入框,显示输入的内容
  4. 使用v-bind绑定图片src和alt属性