Skip to content

模板语法

Vue 使用一种基于 HTML 的模板语法,允许你声明式地将组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。

文本插值

数据绑定最常见的形式就是使用 "Mustache" 语法(双大括号)的文本插值:

vue
<template>
  <span>Message: {{ msg }}</span>
</template>

<script>
export default {
  data() {
    return {
      msg: 'Hello Vue!'
    }
  }
}
</script>

双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令。

一次性插值

通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新:

vue
<template>
  <span v-once>这个将不会改变: {{ msg }}</span>
</template>

原始 HTML

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:

vue
<template>
  <p>Using mustaches: {{ rawHtml }}</p>
  <p>Using v-html directive: <span v-html="rawHtml"></span></p>
</template>

<script>
export default {
  data() {
    return {
      rawHtml: '<span style="color: red">This should be red.</span>'
    }
  }
}
</script>

安全警告

在你的站点上动态渲染任意的 HTML 是非常危险的,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。

Attribute 绑定

双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令:

vue
<template>
  <div v-bind:id="dynamicId"></div>
  <!-- 简写 -->
  <div :id="dynamicId"></div>
</template>

<script>
export default {
  data() {
    return {
      dynamicId: 'my-id'
    }
  }
}
</script>

布尔型 Attribute

布尔型 attribute 依据 true / false 值来决定 attribute 是否应该存在于该元素上。

vue
<template>
  <button :disabled="isButtonDisabled">Button</button>
</template>

<script>
export default {
  data() {
    return {
      isButtonDisabled: true
    }
  }
}
</script>

动态绑定多个值

如果你有像这样的一个包含多个 attribute 的 JavaScript 对象:

javascript
data() {
  return {
    objectOfAttrs: {
      id: 'container',
      class: 'wrapper'
    }
  }
}

通过不带参数的 v-bind,你可以将它们绑定到单个元素上:

vue
<template>
  <div v-bind="objectOfAttrs"></div>
</template>

使用 JavaScript 表达式

到目前为止,在我们的模板中,我们只绑定简单的 property 键值。但实际上,对于所有的数据绑定,Vue 都提供了完全的 JavaScript 表达式支持。

vue
<template>
  <div>
    {{ number + 1 }}
    {{ ok ? 'YES' : 'NO' }}
    {{ message.split('').reverse().join('') }}
    <div :id="'list-' + id"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      number: 1,
      ok: true,
      message: 'Hello',
      id: 'main'
    }
  }
}
</script>

这些表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。

仅支持表达式

每个绑定都只能包含单个表达式,所以下面的例子都不会生效。

vue
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}

<!-- 流程控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

调用函数

可以在绑定的表达式中调用一个组件暴露的方法:

vue
<template>
  <span :title="toTitleDate(date)">
    {{ formatDate(date) }}
  </span>
</template>

<script>
export default {
  data() {
    return {
      date: new Date()
    }
  },
  methods: {
    formatDate(date) {
      return date.toLocaleDateString()
    },
    toTitleDate(date) {
      return date.toLocaleString()
    }
  }
}
</script>

指令

指令是带有 v- 前缀的特殊 attribute。Vue 提供了许多内置指令,包括上面我们所介绍的 v-bindv-html

指令 attribute 的期望值为一个 JavaScript 表达式(除了少数几个例外,即之后要讨论到的 v-forv-onv-slot)。一个指令的任务是在其表达式的值变化时响应式地更新 DOM。

vue
<template>
  <p v-if="seen">现在你看到我了</p>
</template>

<script>
export default {
  data() {
    return {
      seen: true
    }
  }
}
</script>

参数

某些指令会需要一个"参数",在指令名后通过一个冒号隔开做标识。例如,v-bind 指令被用来响应式地更新 HTML attribute:

vue
<template>
  <a v-bind:href="url">链接</a>
  <!-- 简写 -->
  <a :href="url">链接</a>
</template>

这里 href 就是一个参数,它告诉 v-bind 指令将表达式 url 的值绑定到元素的 href attribute 上。

另一个例子是 v-on 指令,它将监听 DOM 事件:

vue
<template>
  <a v-on:click="doSomething">点击我</a>
  <!-- 简写 -->
  <a @click="doSomething">点击我</a>
</template>

这里的参数是要监听的事件的名称。

动态参数

同样在指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内:

vue
<template>
  <a v-bind:[attributeName]="url">动态属性</a>
  <a v-on:[eventName]="doSomething">动态事件</a>
</template>

<script>
export default {
  data() {
    return {
      attributeName: 'href',
      eventName: 'click',
      url: 'https://vuejs.org'
    }
  },
  methods: {
    doSomething() {
      alert('Hello!')
    }
  }
}
</script>

动态参数值的限制

动态参数期望结果为一个字符串,或者是 null。特殊值 null 意为显式移除该绑定。其他非字符串的值会触发警告。

动态参数语法的限制

动态参数表达式因为某些字符的缘故有一些语法限制,比如空格和引号,在 HTML attribute 名称中都是不合法的。例如下面的示例:

vue
<!-- 这会触发一个编译警告 -->
<a v-bind:['foo' + bar]="value">...</a>

如果你需要传入一个复杂的动态参数,我们推荐使用计算属性替换复杂的表达式。

修饰符

修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。例如 .prevent 修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault()

vue
<template>
  <form @submit.prevent="onSubmit">...</form>
</template>

常用指令示例

v-if / v-else / v-else-if

条件渲染:

vue
<template>
  <div>
    <h1 v-if="awesome">Vue is awesome!</h1>
    <h1 v-else>Oh no 😢</h1>
    
    <div v-if="type === 'A'">
      A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      awesome: true,
      type: 'A'
    }
  }
}
</script>

v-show

另一个用于条件性展示元素的选项是 v-show 指令:

vue
<template>
  <h1 v-show="ok">Hello!</h1>
</template>

<script>
export default {
  data() {
    return {
      ok: true
    }
  }
}
</script>

不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。

v-for

列表渲染:

vue
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.message }}
    </li>
  </ul>
  
  <ul>
    <li v-for="(item, index) in items" :key="item.id">
      {{ index }} - {{ item.message }}
    </li>
  </ul>
  
  <ul>
    <li v-for="(value, name) in object" :key="name">
      {{ name }}: {{ value }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, message: 'Foo' },
        { id: 2, message: 'Bar' }
      ],
      object: {
        title: 'How to do lists in Vue',
        author: 'Jane Doe',
        publishedAt: '2016-04-10'
      }
    }
  }
}
</script>

v-on

事件监听:

vue
<template>
  <div>
    <button v-on:click="counter += 1">Add 1</button>
    <button @click="greet">Greet</button>
    <button @click="say('hi')">Say hi</button>
    <button @click="warn('Form cannot be submitted yet.', $event)">
      Submit
    </button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      counter: 0,
      name: 'Vue.js'
    }
  },
  methods: {
    greet(event) {
      alert('Hello ' + this.name + '!')
      if (event) {
        alert(event.target.tagName)
      }
    },
    say(message) {
      alert(message)
    },
    warn(message, event) {
      if (event) {
        event.preventDefault()
      }
      alert(message)
    }
  }
}
</script>

v-model

双向数据绑定:

vue
<template>
  <div>
    <input v-model="message" placeholder="edit me">
    <p>Message is: {{ message }}</p>
    
    <textarea v-model="message2" placeholder="add multiple lines"></textarea>
    
    <input type="checkbox" id="checkbox" v-model="checked">
    <label for="checkbox">{{ checked }}</label>
    
    <select v-model="selected">
      <option disabled value="">Please select one</option>
      <option>A</option>
      <option>B</option>
      <option>C</option>
    </select>
    <span>Selected: {{ selected }}</span>
  </div>
</template>

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

完整示例

vue
<template>
  <div class="demo">
    <h1>{{ title }}</h1>
    
    <!-- 文本插值 -->
    <p>{{ message }}</p>
    
    <!-- HTML 插值 -->
    <div v-html="htmlMessage"></div>
    
    <!-- 属性绑定 -->
    <img :src="imageSrc" :alt="imageAlt">
    
    <!-- 条件渲染 -->
    <p v-if="showMessage">这是一条消息</p>
    <button @click="toggleMessage">切换消息</button>
    
    <!-- 列表渲染 -->
    <ul>
      <li v-for="item in list" :key="item.id">
        {{ item.name }}
      </li>
    </ul>
    
    <!-- 表单绑定 -->
    <input v-model="inputValue" placeholder="输入一些文字">
    <p>你输入的是: {{ inputValue }}</p>
    
    <!-- 事件处理 -->
    <button @click="handleClick">点击我</button>
    <button @click="increment">计数: {{ count }}</button>
  </div>
</template>

<script>
export default {
  name: 'TemplateSyntaxDemo',
  data() {
    return {
      title: '模板语法演示',
      message: 'Hello Vue!',
      htmlMessage: '<strong>这是粗体文本</strong>',
      imageSrc: 'https://vuejs.org/images/logo.png',
      imageAlt: 'Vue.js Logo',
      showMessage: true,
      inputValue: '',
      count: 0,
      list: [
        { id: 1, name: '苹果' },
        { id: 2, name: '香蕉' },
        { id: 3, name: '橙子' }
      ]
    }
  },
  methods: {
    toggleMessage() {
      this.showMessage = !this.showMessage
    },
    handleClick() {
      alert('按钮被点击了!')
    },
    increment() {
      this.count++
    }
  }
}
</script>

<style scoped>
.demo {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
}

img {
  max-width: 100px;
  height: auto;
}

button {
  margin: 5px;
  padding: 8px 16px;
  cursor: pointer;
}

input {
  padding: 8px;
  margin: 5px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
</style>

下一步

现在你已经了解了 Vue 的模板语法基础,让我们继续学习:

模板语法是 Vue 的核心特性之一,掌握它将让你能够高效地构建动态的用户界面!

基于 Vue.js 官方文档构建的学习宝典