Vue笔记-001-声明式渲染
https://cn.vuejs.org/tutorial/#step-2https://cn.vuejs.org/tutorial/#step-2
Vue 单文件组件 (Single-File Component,缩写为 SFC)
单文件组件是一种可复用的代码组织形式,它将从属于同一个组件的 HTML、CSS 和 JavaScript 封装在使用 .vue
后缀的文件中。
声明式渲染
Vue 的核心功能是声明式渲染:通过扩展于标准 HTML 的模板语法,我们可以根据 JavaScript 的状态来描述 HTML 应该是什么样子的。当状态改变时,HTML 会自动更新。
能在改变时触发更新的状态被称作是响应式的。我们可以使用 Vue 的 reactive()
API 来声明响应式状态。由 reactive()
创建的对象都是 JavaScript Proxy,其行为与普通对象一样。
reactive()
只适用于对象 (包括数组和内置类型,如 Map
和 Set
)。而另一个 API ref()
则可以接受任何值类型。ref
会返回一个包裹对象,并在 .value
属性下暴露内部值。
template是一个内容模板,里面是内容的各个小模块。
<template>
<div>
<h1>{{ message }}</h1>
<p>Count is: {{ counter.count }}</p>
<button @click="increment">Increase Count</button>
<h1>Make me dynamic!</h1>
</div>
</template>
script setup是业务逻辑层
<script setup>
import { ref, reactive } from 'vue'
// 定义响应式数据
const counter = reactive({
count: 0
})
const message = ref('Hello, Vue!')
// 定义方法
function increment() {
counter.count++
}
// 初始化时递增一次
console.log(counter.count) // 0
counter.count++
</script>
style是内容模块的美化层
<style scoped>
/* 添加一些样式,使页面更美观 */
div {
text-align: center;
margin-top: 50px;
}
button {
padding: 10px 20px;
font-size: 16px;
}
</style>
示例
<!-- CounterComponent.vue -->
<template>
<div class="counter-container">
<h1 class="message">{{ message }}</h1>
<p class="count-display">Count is: {{ counter.count }}</p>
<button class="increment-button" @click="increment">Increase Count</button>
<h1 class="dynamic-header">Make me dynamic!</h1>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
// 定义计数器接口
interface Counter {
count: number
}
// 定义响应式数据
const counter = reactive<Counter>({
count: 0
})
// 定义消息内容
const message = ref<string>('Hello, Vue!')
// 定义增加计数的方法
function increment(): void {
counter.count++
}
// 生命周期钩子:组件挂载后执行
onMounted(() => {
console.log(`Initial count: ${counter.count}`) // 0
counter.count++
})
</script>
<style scoped>
/* 容器样式 */
.counter-container {
text-align: center;
margin-top: 50px;
}
/* 消息样式 */
.message {
font-size: 2em;
color: #42b983;
}
/* 计数显示样式 */
.count-display {
font-size: 1.5em;
margin: 20px 0;
}
/* 按钮样式 */
.increment-button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border: none;
background-color: #42b983;
color: white;
border-radius: 5px;
transition: background-color 0.3s;
}
.increment-button:hover {
background-color: #369870;
}
/* 动态标题样式 */
.dynamic-header {
margin-top: 30px;
font-size: 1.2em;
color: #333;
}
</style>
1. 文件整体结构
这段代码是一个单文件组件(Single File Component),通常保存在一个以 .vue
结尾的文件里,比如 CounterComponent.vue
。它被分成三个主要部分:
<template>
:页面上要显示的结构(HTML)。<script setup lang="ts">
:组件的逻辑和数据处理部分。这里用了 TypeScript(lang="ts"
)。<style scoped>
:样式部分,给这个组件的元素增加视觉样式,并用scoped
限制样式范围。
Vue 3 推荐使用这种“单文件组件”格式,让结构、逻辑、样式都集中在同一个文件里,便于管理和协作。
2. <template>
部分:页面结构与显示内容
<template>
<div class="counter-container">
<h1 class="message">{{ message }}</h1>
<p class="count-display">Count is: {{ counter.count }}</p>
<button class="increment-button" @click="increment">Increase Count</button>
<h1 class="dynamic-header">Make me dynamic!</h1>
</div>
</template>
<div class="counter-container">
:这是最外层的容器,用于包裹整段内容。给它一个类名是为了在样式里定位并做样式修饰。<h1 class="message">{{ message }}</h1>
:{{ message }}
是插值语法,用于显示脚本中定义的message
变量的值。class="message"
用于给<h1>
元素添加样式。
<p class="count-display">Count is: {{ counter.count }}</p>
:- 同样使用插值语法,
counter.count
表示一个名为counter
的对象的count
属性。 class="count-display"
用于样式管理。
- 同样使用插值语法,
<button class="increment-button" @click="increment">Increase Count</button>
:- 这是一个按钮,点击后会触发
increment()
方法(事件绑定语法:@click="increment"
)。 class="increment-button"
用于样式管理。
- 这是一个按钮,点击后会触发
<h1 class="dynamic-header">Make me dynamic!</h1>
:- 纯文本标题,让页面看起来更丰富一些,暂时没有绑定任何逻辑。
小结:<template>
就像是 HTML,但是可以使用 Vue 的插值和指令(如 @click
)来展示和控制数据。
3. <script setup lang="ts">
部分:业务逻辑与数据管理
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
// 定义计数器接口
interface Counter {
count: number
}
// 定义响应式数据
const counter = reactive<Counter>({
count: 0
})
// 定义消息内容
const message = ref<string>('Hello, Vue!')
// 定义增加计数的方法
function increment(): void {
counter.count++
}
// 生命周期钩子:组件挂载后执行
onMounted(() => {
console.log(`Initial count: ${counter.count}`) // 0
counter.count++
})
</script>
3.1 import { ref, reactive, onMounted } from 'vue'
ref
、reactive
和onMounted
是 Vue 3 组合式 API 的核心方法。ref()
:创建一个单值的响应式数据,通常用于字符串、数字、布尔值等基本类型。reactive()
:创建一个对象或数组的响应式数据,能让其中所有属性都具备响应式。onMounted()
:Vue 的生命周期钩子,当组件第一次加载(挂载)到页面上时会执行这里的回调。
3.2 TypeScript 接口 Counter
interface Counter {
count: number
}
- 这是 TypeScript 的语法,定义了一个接口
Counter
,表示这个对象里应该有一个count
属性且类型为number
。 - 给
reactive
用上这个接口,可以让代码编辑器对counter.count
做类型检查,更好地规避错误。
3.3 定义响应式数据 counter
const counter = reactive<Counter>({
count: 0
})
reactive<Counter>()
表示用Counter
这个接口来约束对象结构。count: 0
表示初始值是 0。- 任何使用
counter.count
的地方,都会在它改变时自动刷新页面上对应的位置(也就是响应式的特点)。
3.4 定义消息内容 message
const message = ref<string>('Hello, Vue!')
message
用ref()
定义,初始值'Hello, Vue!'
。<string>
明确说明message.value
会是一个字符串类型。- 在模板里,你可以直接用
{{ message }}
,Vue 会自动解包(unref)ref
,无需写message.value
。
3.5 定义方法 increment()
function increment(): void {
counter.count++
}
- 当用户点击按钮时,会执行这个函数,让
counter.count
递增 1。 : void
表示这是一个不返回值的函数(TypeScript 语法)。
3.6 生命周期钩子 onMounted
onMounted(() => {
console.log(`Initial count: ${counter.count}`)
counter.count++
})
- 在组件加载(挂载)时打印当前的
count
值,然后再让它自增 1。 - 这个回调只会在组件第一次挂载到页面时运行一次,适合做初始化逻辑、获取数据等操作。
4. <style scoped>
部分:样式
<style scoped>
/* 容器样式 */
.counter-container {
text-align: center;
margin-top: 50px;
}
/* 消息样式 */
.message {
font-size: 2em;
color: #42b983;
}
/* 计数显示样式 */
.count-display {
font-size: 1.5em;
margin: 20px 0;
}
/* 按钮样式 */
.increment-button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
border: none;
background-color: #42b983;
color: white;
border-radius: 5px;
transition: background-color 0.3s;
}
.increment-button:hover {
background-color: #369870;
}
/* 动态标题样式 */
.dynamic-header {
margin-top: 30px;
font-size: 1.2em;
color: #333;
}
</style>
scoped
表示样式只作用于当前组件,不会影响其它组件或全局页面。- 每个 CSS 选择器都对应我们在
<template>
中写的 class 名称,比如.counter-container
、.message
、.count-display
等等。 - 给按钮设置了鼠标悬停(
:hover
)时的背景色变换,还加了一点圆角和过渡动画,让交互更友好。
5. 代码的工作流程
- 组件加载
- 当这个
CounterComponent.vue
被导入并在页面中使用时,Vue 会解析<template>
、<script setup>
和<style>
。
- 当这个
- 初始化数据
counter.count = 0
,message = 'Hello, Vue!'
。
- onMounted
- 组件挂载到页面后,
onMounted()
回调被执行,打印出初始的count
值,然后立即将count
改成 1。 - 这样你的页面在初始化时,
{{ counter.count }}
可能很快就会从0
变成1
,你在控制台也能看到 “Initial count: 0” 的日志。
- 组件挂载到页面后,
- 用户交互
- 当用户点击 “Increase Count” 按钮时,会调用
increment()
方法,让counter.count++
。 - Vue 自动检测到
counter.count
的变化,重新渲染页面,让{{ counter.count }}
显示新的值。
- 当用户点击 “Increase Count” 按钮时,会调用
- 样式呈现
- 由于
scoped
,这些 CSS 样式只对当前组件生效,不会影响全局或其他组件。
- 由于
6. 总结与提示
- 单文件组件 (SFC):
<template>
、<script setup>
、<style>
这三部分合在一起,方便你把界面、逻辑、样式都集中在同一个文件维护,清晰易于管理。 - 组合式 API (Composition API):通过
ref()
,reactive()
,onMounted()
等函数,让数据和业务逻辑更灵活地组合、拆分。学会它之后,你可以更轻松地管理复杂的应用逻辑。 - TypeScript:在
<script setup lang="ts">
里,TypeScript 能帮助你检查数据类型,避免一些低级错误。对于大型项目或多人协作,非常有用。如果你暂时对 TS 不熟悉,也可以先使用普通的 JavaScript(去掉lang="ts"
和相关类型注解),等熟悉后再进阶。 scoped
样式:让当前组件的 CSS 不会跑去影响其它地方,减少样式冲突。对于大型项目中,样式维护也更有条理。- 学习路径:建议你先熟悉 Vue 的基本概念(如数据响应式、指令、插值语法),再了解
<script setup>
中的组合式 API,最后再考虑引入 TypeScript 或更多高级特性。