news 2026/5/1 15:42:24

Vue.js 模板语法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue.js 模板语法

Vue.js 模板语法学习笔记

一、插值

1. 文本插值{{ }}

最基本的数据绑定方式,使用双大括号(Mustache 语法):

<template> <p>{{ message }}</p> <p>{{ count + 1 }}</p> <p>{{ ok ? '是' : '否' }}</p> <p>{{ message.split('').reverse().join('') }}</p> </template> <script setup> import { ref } from 'vue' const message = ref('Hello Vue') const count = ref(0) const ok = ref(true) </script>

{{ }}内只能是单个表达式,不能是语句(如let a = 1)或流控制(如if ...)。

2. 原始 HTMLv-html

<template> <!-- 普通插值:转义 HTML 标签 --> <p>{{ rawHtml }}</p> <!-- 输出:<span style="color:red">红色</span> --> <!-- v-html:渲染为真实 HTML --> <p v-html="rawHtml"></p> <!-- 输出:红色(红色字体) --> </template> <script setup> import { ref } from 'vue' const rawHtml = ref('<span style="color:red">红色</span>') </script>

安全警告v-html会导致 XSS 攻击风险,绝不要用于渲染用户提交的内容。

3. 纯文本v-text

<template> <span v-text="message"></span> <!-- 等价于 --> <span>{{ message }}</span> </template>

v-text会替换元素内所有内容,不如{{ }}灵活,实际中较少使用。

4. 属性绑定v-bind

{{ }}不能用在 HTML 属性中,需使用v-bind

<template> <!-- 完整语法 --> <img v-bind:src="imageUrl" /> <!-- 缩写(推荐) --> <img :src="imageUrl" /> <a :href="link">链接</a> <button :disabled="isDisabled">提交</button> </template>

二、指令

指令总览

指令是带有v-前缀的特殊属性,当表达式的值改变时,将其产生的连带影响响应式地作用于 DOM。

指令用途缩写
v-bind动态绑定属性:attr
v-on监听事件@event
v-model双向数据绑定
v-if条件渲染(销毁/重建)
v-else-if条件分支
v-else条件否则
v-show条件显示(CSS 切换)
v-for列表渲染
v-slot插槽#name
v-html渲染原始 HTML
v-text更新文本内容
v-once只渲染一次
v-memo缓存模板
v-cloak防止闪烁

指令参数

指令名后的冒号部分为参数:

<a v-bind:href="url">链接</a> <!-- href 是参数 --> <button v-on:click="handleClick">点击</button> <!-- click 是参数 -->

动态参数

用方括号包裹 JavaScript 表达式作为动态参数:

<template> <!-- 动态属性名 --> <a :[attrName]="url">链接</a> <!-- 动态事件名 --> <button @[eventName]="handleClick">点击</button> </template> <script setup> import { ref } from 'vue' const attrName = ref('href') const eventName = ref('click') const url = ref('https://vuejs.org') </script>

动态参数的值必须是字符串,不能包含空格和引号,且应使用小写(浏览器会将属性名强制转为小写)。

修饰符

.指明的特殊后缀,表示指令需要以特殊方式绑定:

<!-- 阻止默认行为 --> <form @submit.prevent="onSubmit"> <!-- 事件只触发一次 --> <button @click.once="handleClick">只触发一次</button> <!-- 按键修饰 --> <input @keyup.enter="onEnter" /> <!-- 深度监听 --> <input v-model.lazy="msg" />

三、条件渲染

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

<template> <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>其他类型</div> </template>

<template>上使用v-if(分组渲染,不产生额外 DOM):

<template v-if="showGroup"> <h1>标题</h1> <p>段落一</p> <p>段落二</p> </template>

v-show

<template> <p v-show="isVisible">这段文字可切换显示</p> </template>

v-ifvsv-show

对比项v-ifv-show
切换方式销毁/重建 DOMdisplay: none切换
初始渲染条件为 false 时不渲染始终渲染
切换开销
初始开销
适用场景运行时条件很少改变需要频繁切换

注意v-ifv-for不要同时用在同一元素上。v-if优先级高于v-for,会导致无法访问v-for中的变量。


四、列表渲染v-for

基本用法

<template> <!-- 遍历数组 --> <ul> <li v-for="item in items" :key="item.id"> {{ item.name }} </li> </ul> <!-- 带索引 --> <ul> <li v-for="(item, index) in items" :key="item.id"> {{ index }} - {{ item.name }} </li> </ul> <!-- 遍历对象 --> <div v-for="(value, key, index) in userInfo" :key="key"> {{ index }}. {{ key }}: {{ value }} </div> <!-- 遍历数字范围 --> <span v-for="n in 10" :key="n">{{ n }}</span> </template> <script setup> import { ref, reactive } from 'vue' const items = ref([ { id: 1, name: '苹果' }, { id: 2, name: '香蕉' }, { id: 3, name: '橙子' } ]) const userInfo = reactive({ name: '张三', age: 25, city: '北京' }) </script>

key的重要性

<!-- 正确:使用唯一标识 --> <li v-for="item in items" :key="item.id">{{ item.name }}</li> <!-- 错误:不要用 index 作为 key(会导致状态错乱) --> <li v-for="(item, index) in items" :key="index">{{ item.name }}</li>

key的作用:帮助 Vue 的虚拟 DOM 算法识别节点,确保列表更新时正确复用和排序元素。

<template>上使用v-for

<template v-for="item in items" :key="item.id"> <h3>{{ item.title }}</h3> <p>{{ item.content }}</p> </template>

五、事件处理v-on

基本用法

<template> <!-- 内联事件 --> <button @click="count++">{{ count }}</button> <!-- 方法事件 --> <button @click="handleClick">点击</button> <!-- 调用方法(可传参) --> <button @click="greet('Vue')">问候</button> <!-- 访问原生事件对象 --> <button @click="handleEvent($event)">获取事件</button> <!-- 同时传参和访问事件 --> <button @click="handle('hello', $event)">两者兼得</button> </template> <script setup> import { ref } from 'vue' const count = ref(0) function handleClick() { console.log('clicked') } function greet(name) { console.log(`Hello ${name}`) } function handleEvent(event) { console.log(event.target) } function handle(msg, event) { console.log(msg, event.target) } </script>

事件修饰符

<!-- 阻止冒泡 --> <div @click.stop="handleClick"> <!-- 阻止默认行为 --> <form @submit.prevent="onSubmit"> <!-- 事件仅在该元素自身触发时才回调 --> <div @click.self="handleClick"> <!-- 事件捕获模式 --> <div @click.capture="handleClick"> <!-- 只触发一次 --> <button @click.once="handleClick"> <!-- 滚动事件的默认行为立即触发 --> <div @scroll.passive="onScroll"> <!-- 链式调用 --> <a @click.stop.prevent="handleClick">

修饰符顺序:从左到右依次生效。

按键修饰符

<!-- 按键名 --> <input @keyup.enter="onEnter" /> <input @keyup.esc="onEsc" /> <!-- 系统修饰键 --> <div @keydown.ctrl="onCtrl" /> <div @keydown.ctrl.enter="onCtrlEnter" /> <!-- 鼠标按钮 --> <button @click.left="onLeftClick" /> <button @click.right="onRightClick" /> <button @click.middle="onMiddleClick" />

常用按键修饰符:.enter.tab.delete.esc.space.up.down.left.right


六、双向绑定v-model

基本用法

<template> <!-- 文本输入 --> <input v-model="text" placeholder="输入文本" /> <p>输入内容:{{ text }}</p> <!-- 多行文本 --> <textarea v-model="description"></textarea> <!-- 复选框 --> <input type="checkbox" v-model="checked" /> <!-- 多个复选框(绑定数组) --> <input type="checkbox" value="A" v-model="selectedItems" /> <input type="checkbox" value="B" v-model="selectedItems" /> <input type="checkbox" value="C" v-model="selectedItems" /> <!-- 单选按钮 --> <input type="radio" value="male" v-model="gender" /> <input type="radio" value="female" v-model="gender" /> <!-- 下拉选择 --> <select v-model="selected"> <option value="">请选择</option> <option value="a">A</option> <option value="b">B</option> </select> </template> <script setup> import { ref } from 'vue' const text = ref('') const description = ref('') const checked = ref(false) const selectedItems = ref([]) const gender = ref('') const selected = ref('') </script>

v-model修饰符

<!-- .lazy:在 change 事件后同步(而非 input) --> <input v-model.lazy="msg" /> <!-- .number:自动转为数字 --> <input v-model.number="age" type="number" /> <!-- .trim:自动去除首尾空格 --> <input v-model.trim="name" />

v-model本质

v-modelv-bind+v-on的语法糖:

<!-- v-model 写法 --> <input v-model="searchText" /> <!-- 等价于 --> <input :value="searchText" @input="searchText = $event.target.value" />

组件上的v-model

<!-- 父组件 --> <ChildComponent v-model="modelValue" /> <!-- 等价于 --> <ChildComponent :modelValue="modelValue" @update:modelValue="modelValue = $event" />
<!-- 子组件 ChildComponent.vue --> <script setup> const props = defineProps<{ modelValue: string }>() const emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>() function onInput(event: Event) { emit('update:modelValue', (event.target as HTMLInputElement).value) } </script> <template> <input :value="props.modelValue" @input="onInput" /> </template>

多个v-model绑定

<!-- 父组件 --> <UserForm v-model:first-name="firstName" v-model:last-name="lastName" />
<!-- 子组件 UserForm.vue --> <script setup> const props = defineProps<{ firstName: string lastName: string }>() const emit = defineEmits<{ (e: 'update:firstName', value: string): void (e: 'update:lastName', value: string): void }>() </script> <template> <input :value="props.firstName" @input="emit('update:firstName', $event.target.value)" /> <input :value="props.lastName" @input="emit('update:lastName', $event.target.value)" /> </template>

七、计算属性与侦听器(模板中的逻辑处理)

计算属性computed

模板中不应包含复杂逻辑,应使用计算属性:

<template> <p>原价:{{ price }}</p> <p>折扣价:{{ discountPrice }}</p> <p>全名:{{ fullName }}</p> </template> <script setup> import { ref, computed } from 'vue' const price = ref(100) // 只读计算属性 const discountPrice = computed(() => price.value * 0.8) // 可写计算属性 const firstName = ref('张') const lastName = ref('三') const fullName = computed({ get() { return firstName.value + lastName.value }, set(newValue) { firstName.value = newValue[0] lastName.value = newValue.slice(1) } }) </script>

computedvs 方法

对比项computed方法(methods
缓存有(依赖不变不重算)无(每次调用都执行)
调用方式{{ discountPrice }}{{ getDiscountPrice() }}
适用场景需要缓存的派生数据每次都需要重新计算的场景

侦听器watch

<script setup> import { ref, watch } from 'vue' const question = ref('') // 监听单个 ref watch(question, (newVal, oldVal) => { console.log(`从 "${oldVal}" 变为 "${newVal}"`) }) // 监听多个源 const x = ref(0) const y = ref(0) watch([x, y], ([newX, newY]) => { console.log(`坐标:(${newX}, ${newY})`) }) // 立即执行 watch(question, (val) => { console.log(val) }, { immediate: true }) // 深度监听 const user = ref({ name: '张三', address: { city: '北京' } }) watch(user, (newVal) => { console.log('用户信息变化', newVal) }, { deep: true }) </script>

watchEffect

<script setup> import { ref, watchEffect } from 'vue' const count = ref(0) const name = ref('Vue') // 自动追踪依赖,立即执行 watchEffect(() => { console.log(`count = ${count.value}, name = ${name.value}`) // 会自动追踪内部使用的响应式数据 }) </script>
对比项watchwatchEffect
依赖声明显式指定自动追踪
初始执行不执行(除非immediate立即执行
旧值访问可以不可以
适用场景需要精确控制、对比新旧值副作用逻辑、自动追踪依赖

八、模板引用ref

直接访问 DOM 元素或子组件实例:

<template> <input ref="inputRef" /> <ChildComponent ref="childRef" /> </template> <script setup> import { ref, onMounted } from 'vue' const inputRef = ref(null) const childRef = ref(null) onMounted(() => { inputRef.value.focus() // 操作 DOM childRef.value.someMethod() // 调用子组件方法(需 defineExpose 暴露) }) </script>

模板引用的变量名必须与ref属性值一致,且在onMounted之后才能访问。


九、总结速查

语法用途示例
{{ }}文本插值{{ message }}
v-html渲染 HTMLv-html="rawHtml"
v-bind/:属性绑定:src="url"
v-on/@事件监听@click="handler"
v-model双向绑定v-model="value"
v-if/else条件渲染v-if="show"
v-show条件显示v-show="visible"
v-for列表渲染v-for="item in list"
v-slot/#插槽#default="slotProps"
computed计算属性computed(() => ...)
watch侦听器watch(source, callback)
ref模板引用ref="inputRef"
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 15:42:23

使用Vitest进行可维护性测试:10个实用技巧提升代码质量

使用Vitest进行可维护性测试&#xff1a;10个实用技巧提升代码质量 【免费下载链接】vitest Next generation testing framework powered by Vite. 项目地址: https://gitcode.com/GitHub_Trending/vi/vitest Vitest是由Vite驱动的下一代测试框架&#xff0c;它提供了快…

作者头像 李华
网站建设 2026/5/1 15:41:26

KUKA C4/C2软限位修改避坑指南:$machine.dat文件详解与重启生效的正确姿势

KUKA C4/C2软限位修改避坑指南&#xff1a;$machine.dat文件详解与重启生效的正确姿势 在工业机器人调试过程中&#xff0c;软限位的精确设置直接关系到设备运行安全与工作效率。作为KUKA机器人系统的核心参数之一&#xff0c;软限位定义了各轴的运动范围边界&#xff0c;其配置…

作者头像 李华
网站建设 2026/5/1 15:39:52

2025届最火的五大降AI率工具推荐榜单

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 把AIGC&#xff08;人工智能生成内容&#xff09;的识别概率降下来&#xff0c;要从文本特征…

作者头像 李华
网站建设 2026/5/1 15:39:50

告别电脑自动锁屏:Move Mouse智能防休眠解决方案

告别电脑自动锁屏&#xff1a;Move Mouse智能防休眠解决方案 【免费下载链接】movemouse Move Mouse is a simple piece of software that is designed to simulate user activity. 项目地址: https://gitcode.com/gh_mirrors/mo/movemouse 你是否曾因电脑自动锁屏而错过…

作者头像 李华
网站建设 2026/5/1 15:39:49

魔兽世界GSE宏编辑器:三步实现技能自动化终极指南

魔兽世界GSE宏编辑器&#xff1a;三步实现技能自动化终极指南 【免费下载链接】GSE-Advanced-Macro-Compiler GSE is an alternative advanced macro editor and engine for World of Warcraft. 项目地址: https://gitcode.com/gh_mirrors/gs/GSE-Advanced-Macro-Compiler …

作者头像 李华