4、模板语法:插值表达式、v-text与v-html、v-bind绑定属性、v-on绑定事件

好,咱们继续往下走。上一章我们把 Vue 实例和模板的关系理清了,现在该动真格的了——模板语法。

说白了,模板语法就是 Vue 用来“说话”的方式。你想让页面显示什么、怎么显示、点击后干什么,都得靠这些语法告诉 Vue。我个人觉得,这部分是 Vue 最直观、最好玩的地方。你写一行代码,页面立马变样,那种即时反馈感,真的很爽。

4.1 插值表达式:最基础的“填空”

插值表达式,就是那对花括号 {{ }}。你可以在里面写变量、写表达式,Vue 会自动把结果填到 DOM 里。

<div id="app">
  <p>{{ message }}</p>
  <p>{{ 1 + 1 }}</p>
  <p>{{ isActive ? '激活' : '未激活' }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    message: '你好,Vue!',
    isActive: true
  }
})
</script>

你看,{{ message }} 直接渲染成“你好,Vue!”。{{ 1 + 1 }} 会算出 2。三元表达式也能用,Vue 会帮你算好再填进去。

小提示:插值表达式里只能写单个表达式,不能写 if 语句、for 循环这些。比如 {{ if (true) { return 'a' } }} 这样写会报错。记住,它只是个“填空”,不是“编程区”。

我在项目中遇到过有人把很长的计算逻辑塞进插值表达式里,结果模板变得又臭又长。我的建议是:复杂的逻辑放到计算属性(后面会讲)里,模板只负责展示。

4.2 v-text 与 v-html:控制内容的两种方式

插值表达式有个小问题——如果网速慢,页面刚加载时会闪现出 {{ message }} 这种原始文本,用户体验不好。这时候 v-text 就派上用场了。

<!-- 等价写法 -->
<p>{{ message }}</p>
<p v-text="message"></p>

v-text 会直接替换掉标签里的所有内容。它不会闪烁,因为 Vue 在渲染前就把内容处理好了。

v-text 有个限制——它把内容当纯文本处理。如果你要渲染 HTML 标签,比如从后端拿到的富文本内容,就得用 v-html

<div id="app">
  <p v-text="htmlContent"></p>
  <p v-html="htmlContent"></p>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    htmlContent: '<strong>加粗文字</strong>'
  }
})
</script>

结果:v-text 显示的是 <strong>加粗文字</strong> 这段字符串,而 v-html 会渲染成真正的加粗文字。

⚠️ 重要警告:千万不要用 v-html 渲染用户输入的内容!比如评论框、用户简介这些。我曾经见过一个项目,因为用了 v-html 渲染用户评论,结果被人注入了恶意脚本,整个站点的用户数据都泄露了。如果你非要渲染 HTML,一定要先做 XSS 过滤。

4.3 v-bind:动态绑定属性

插值表达式只能用在标签内容里,那标签的属性怎么办?比如你想让图片的 src 根据数据变化,或者让按钮的 disabled 状态跟着变量走。这时候就需要 v-bind

<div id="app">
  <img v-bind:src="imageUrl" alt="动态图片">
  <button v-bind:disabled="isDisabled">点击</button>
  <a v-bind:href="link">跳转</a>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    imageUrl: 'https://example.com/logo.png',
    isDisabled: true,
    link: 'https://vuejs.org'
  }
})
</script>

v-bind:src 的意思就是:把 src 属性跟 imageUrl 这个数据绑定起来。数据一变,属性值也跟着变。

嗯,这里要注意:v-bind 可以简写成冒号 :。上面的代码可以写成:

<img :src="imageUrl" alt="动态图片">
<button :disabled="isDisabled">点击</button>
<a :href="link">跳转</a>

我个人习惯用简写,代码看起来更干净。但刚开始学的时候,建议先写全称,等熟悉了再换简写。

还有一个很实用的场景——动态绑定 class。比如根据某个状态切换样式:

<div :class="{ active: isActive, 'text-danger': hasError }">
  这段文字会根据状态变化样式
</div>

isActive 为 true 时,这个 div 会加上 active 类;hasError 为 true 时,加上 text-danger 类。这种写法在写列表高亮、表单验证时特别常用。

4.4 v-on:绑定事件,让页面动起来

光有数据显示还不够,用户得能交互。点击按钮、输入文字、鼠标移动……这些都需要事件绑定。Vue 用 v-on 来处理。

<div id="app">
  <button v-on:click="handleClick">点我</button>
  <input v-on:input="handleInput">
  <p>你输入了:{{ inputValue }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    inputValue: ''
  },
  methods: {
    handleClick() {
      alert('按钮被点击了!')
    },
    handleInput(event) {
      this.inputValue = event.target.value
    }
  }
})
</script>

v-on:click 监听点击事件,v-on:input 监听输入事件。事件处理函数写在 methods 对象里,通过 this 访问 data 中的数据。

v-bind 一样,v-on 也有简写——用 @ 符号:

<button @click="handleClick">点我</button>
<input @input="handleInput">

是不是简洁多了?我平时写代码基本都用简写,除非是团队规范要求写全称。

事件绑定还能传参数:

<button @click="say('你好')">打招呼</button>
<button @click="say('再见')">告别</button>

<script>
methods: {
  say(msg) {
    alert(msg)
  }
}
</script>

有时候你既需要传参数,又需要访问原生事件对象,可以用 $event

<button @click="handleClick('参数', $event)">点我</button>
核心总结:
  • {{ }}:插值表达式,显示数据,不能用于属性
  • v-text:纯文本渲染,不会闪烁
  • v-html:渲染 HTML,小心 XSS 攻击
  • v-bind(简写 :):动态绑定属性、class、style
  • v-on(简写 @):绑定事件,处理用户交互

这四种模板语法,基本覆盖了日常开发 80% 的场景。你想想看,显示数据、控制内容、绑定属性、处理事件——一个交互页面需要的功能,这里全有了。

下一章我们会聊条件渲染和列表渲染,到时候这些语法会组合起来用,威力更大。先把这个基础打牢,后面学起来就顺了。