目录
-
-
- [1. `<script setup>` ------ 逻辑的"自动暴露"入口](#1.
<script setup>—— 逻辑的“自动暴露”入口) - [2. `<style scoped>` ------ 样式的"局部隔离罩"](#2.
<style scoped>—— 样式的“局部隔离罩”) - [3. 多根节点 ------ 模板不再需要"一个根"](#3. 多根节点 —— 模板不再需要“一个根”)
- [4. `v-bind`(简写 `:`) ------ 动态绑定 HTML 属性](#4.
v-bind(简写:) —— 动态绑定 HTML 属性) - [5. `v-on`(简写 `@`)+ 修饰符 ------ 事件绑定与便捷操作](#5.
v-on(简写@)+ 修饰符 —— 事件绑定与便捷操作) - 总结
- 练习:点击按钮改变文字颜色或字体大小
- [1. `<script setup>` ------ 逻辑的"自动暴露"入口](#1.
-
单文件组件(Single-File Component,简称 SFC)就是以一个 .vue 文件结尾的文件。这个文件把 HTML、JavaScript、CSS 三个部分写在一起,用来描述一个独立的、可复用的 UI 部件(比如一个按钮、一张卡片、一个输入框,甚至整个页面)。
一个Vue单文件组件的标准结构如下:
Vue
<template>
<!-- 放 HTML 结构 -->
</template>
<script setup>
// 放 JavaScript 逻辑(数据、函数等)
</script>
<style scoped>
/* 放 CSS 样式 */
</style>
接下来,我们逐一拆解这三个部分以及相关的核心语法。
1. <script setup> ------ 逻辑的"自动暴露"入口
它是做什么的?
<script setup> 是 Vue 3 中一种更简洁的写法,用来写组件的 JavaScript 逻辑。你可以在里面定义 变量、函数、导入其他组件或工具 。重点在于:所有定义在顶层的东西,都会自动被 <template> 使用 ,不需要像 Vue 2 那样手动 return。
有什么用?
让你写代码更简单、更直观。例如,你想在页面上显示一段文字,并绑定一个点击事件,可以这样写:
vue
<template>
<h1>{{ message }}</h1>
<button @click="showAlert">点我</button>
</template>
<script setup>
// 普通变量(非响应式,适合静态展示)
const message = '你好,Vue 3!'
// 普通函数
function showAlert() {
alert('按钮被点击了')
}
</script>
这里要说明,{{ }} 是 Vue 模板中的 插值语法。它的作用是把 JavaScript 表达式的值直接显示到页面上。
注意 :如果后续需要让 message 随用户操作而变化(比如点击按钮后改变文字),就需要用到 ref 或 reactive。现在我们主要使用它来定义普通变量和函数,用于简单的静态展示或事件触发。
2. <style scoped> ------ 样式的"局部隔离罩"
它是做什么的?
给 <style> 标签加上 scoped 属性,表示这个样式 只对当前组件的模板生效 ,不会影响到其他组件。Vue 在编译时会自动给当前组件的 HTML 元素添加一个唯一的属性(比如 data-v-7ba5bd90),然后重写你的 CSS 选择器,使其只匹配带有该属性的元素。
有什么用?
防止样式冲突。在一个大项目中,很可能多个组件里都有类名 .title 或 .box,如果不加 scoped,后面引入的样式会覆盖前面的,导致样式错乱。使用 scoped 后,每个组件的样式都是独立的,互不干扰。
示例:
vue
<!-- 组件 A -->
<template>
<div class="box">组件 A 的盒子</div>
</template>
<style scoped>
.box { background-color: red; }
</style>
<!-- 组件 B -->
<template>
<div class="box">组件 B 的盒子</div>
</template>
<style scoped>
.box { background-color: blue; }
</style>
渲染后,组件 A 的盒子背景是红色,组件 B 的盒子背景是蓝色,互不影响。
注意 :如果需要让父组件的样式影响子组件内部的元素(比如想统一设置所有按钮的样式),可以用 :deep() 选择器,但这属于进阶用法,先了解 scoped 的作用即可。
3. 多根节点 ------ 模板不再需要"一个根"
它是做什么的?
在 Vue 2 中,每个组件的 <template> 里必须有一个唯一的根元素 (通常用一个 <div> 包裹所有内容)。Vue 3 移除了这个限制,你可以直接写多个并列的顶层元素。
有什么用?
减少不必要的包裹元素,让生成的 HTML 结构更干净。例如,一个组件要输出一个标题 + 一段描述 + 一个按钮,以前必须这样:
vue
<!-- Vue 2 写法 -->
<template>
<div>
<h1>标题</h1>
<p>描述文字</p>
<button>按钮</button>
</div>
</template>
现在 Vue 3 可以这样:
vue
<!-- Vue 3 写法 -->
<template>
<h1>标题</h1>
<p>描述文字</p>
<button>按钮</button>
</template>
注意 :多根节点在某些边界情况下会有一些小问题(比如父组件向子组件传递 class 或 style 时,不知道应该加到哪个根节点上)。但现在我们暂时不需要纠结这些,只需知道 Vue 3 支持多根节点即可。
以上三个知识点(<script setup>、<style scoped>、多根节点)构成了 .vue 文件的基本骨架。接下来,我们要学习在模板中动态控制元素的属性和行为。
4. v-bind(简写 :) ------ 动态绑定 HTML 属性
它是做什么的?
把 Vue 的数据(变量、表达式)绑定到 HTML 标签的属性 上。常见的属性包括:src、href、class、style、disabled、alt 等。普通情况下,这些属性是写死的(比如 <img src="/logo.png">),但使用 v-bind 后,属性值可以动态变化。
有什么用?
让页面可以根据数据状态自动调整元素的样式或行为。比如:
- 根据条件给某个按钮添加
disabled属性。 - 根据图片 ID 动态生成图片 URL。
- 根据某个布尔值切换 CSS 类名。
基本用法:
vue
<template>
<!-- 绑定图片地址 -->
<img :src="imageUrl" alt="动态图片">
<!-- 绑定 disabled 属性 -->
<button :disabled="isDisabled">提交</button>
<!-- 绑定 class(对象语法:键是类名,值是布尔值) -->
<div :class="{ active: isActive, 'text-bold': isBold }">动态类</div>
<!-- 绑定 class(数组语法) -->
<div :class="['base', isActive ? 'active' : '']">数组方式</div>
<!-- 绑定 style(对象语法) -->
<div :style="{ color: textColor, fontSize: fontSize + 'px' }">动态样式</div>
</template>
<script setup>
const imageUrl = 'https://picsum.photos/200/150'
const isDisabled = true
const isActive = true
const isBold = false
const textColor = 'red'
const fontSize = 20
</script>
注意 :v-bind: 可以简写为 :,这是最常用的写法。另外,class 和 style 的增强写法在实际开发中使用频率极高,一定要熟练。
: 的本质是:把属性从"静态字符串"变成"动态响应式绑定",让属性值能够跟随数据变化。这就是它与普通 HTML 写法的根本区别。
也就是会把属性等号后面的引号里的内容被当作 JavaScript 代码来执行,而不是纯文本。
5. v-on(简写 @)+ 修饰符 ------ 事件绑定与便捷操作
它是做什么的?
监听 DOM 事件(如点击、键盘输入、鼠标移动等),在事件发生时执行指定的 JavaScript 函数。
有什么用?
实现用户交互。比如按钮点击后提交表单、输入框按下回车后搜索、鼠标移入时显示提示等。
基本用法:
vue
<template>
<button @click="handleClick">点我</button>
</template>
<script setup>
function handleClick(event) {
console.log('点击了', event.target)
}
</script>
事件修饰符 :这是 Vue 提供的一组便捷语法,用来处理常见的事件细节,例如阻止冒泡、阻止默认行为、只在特定按键时触发等。它们以 . 加后缀的形式写在事件名后面。
| 修饰符 | 作用 | 示例 |
|---|---|---|
.stop |
阻止事件冒泡(不再触发父元素的事件) | @click.stop |
.prevent |
阻止默认行为(如 <form> 提交刷新页面) |
@submit.prevent |
.enter |
只在回车键触发(用于 @keyup) |
@keyup.enter |
.once |
事件只触发一次 | @click.once |
.self |
只有 event.target 是当前元素时才触发 |
@click.self |
组合使用示例:
vue
<template>
<!-- 阻止冒泡 + 阻止默认行为 -->
<form @submit.prevent.stop="onSubmit">
<input type="text" />
<button type="submit">提交(页面不刷新,且不冒泡)</button>
</form>
<!-- 按回车触发搜索 -->
<input @keyup.enter="search" placeholder="输入后按回车" />
<!-- 只触发一次 -->
<button @click.once="onceClick">仅生效一次</button>
</template>
<script setup>
const onSubmit = () => console.log('表单提交了')
const search = (e) => console.log('搜索:', e.target.value)
const onceClick = () => alert('只能点出一次')
</script>
注意 :修饰符可以串联,比如 @click.stop.prevent 表示同时阻止冒泡和默认行为。
总结
- 我们先学习了
.vue文件的三个组成部分:逻辑 (<script setup>)、样式 (<style scoped>)、模板(支持多根节点)。 - 在模板中,为了让页面"活"起来,我们需要根据数据动态控制 HTML 属性 → 使用
v-bind(:)。 - 同时,还需要响应用户的操作(点击、键盘等)→ 使用
v-on(@) 绑定事件,并用修饰符简化常见操作。 - 至此,我们已经能够写出一个具有基本交互能力的 Vue 组件了。
练习:点击按钮改变文字颜色或字体大小
要求 :
创建一个 Vue 组件,包含一段文字和几个按钮。点击按钮可以改变文字的颜色或字体大小。
提示:
- 颜色和字体大小是动态变化的数据,需要使用
ref来定义(这是阶段2的知识点,但请先按下面的方式照做,后续会系统学习)。 - 在
<script setup>中:import { ref } from 'vue',然后用const textColor = ref('red')定义响应式数据,修改时用textColor.value = 'blue',模板中直接写textColor(不带.value)。 - 字体大小同理:
const fontSize = ref(16),修改时fontSize.value += 4。
完整代码(可直接复制到 src/App.vue 中运行):
vue
<template>
<div>
<!-- 动态绑定颜色和字体大小 -->
<p :style="{ color: textColor, fontSize: fontSize + 'px' }" class="demo-text">
这是一段可变化的文字
</p>
<div class="button-group">
<button @click="textColor = 'red'">红色</button>
<button @click="textColor = 'green'">绿色</button>
<button @click="textColor = 'blue'">蓝色</button>
<button @click="fontSize += 2">放大字体</button>
<button @click="fontSize -= 2">缩小字体</button>
<button @click="reset">重置</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const textColor = ref('black')
const fontSize = ref(16)
function reset() {
textColor.value = 'black'
fontSize.value = 16
}
</script>
<style scoped>
.demo-text {
transition: all 0.2s;
margin-bottom: 16px;
padding: 8px;
border: 1px solid #ddd;
border-radius: 6px;
}
.button-group button {
margin-right: 8px;
margin-bottom: 8px;
padding: 6px 12px;
cursor: pointer;
}
</style>
第一句代码中,:style加上的是内联样式,除非加上!important,它的优先级就是最高的。还有px就是单位,如果不加上浏览器就识别不出来。