Vue 3 入门教程 2- Vue 组件基础与模板语法
一、Vue 组件基础
在 Vue 中,组件是构建用户界面的基本单位,它可以将页面拆分成多个独立、可复用的部分。一个 Vue 组件通常以 .vue 文件名结尾,包含三个核心部分:模板(Template)、脚本(Script)和样式(Style)。
1.1 单文件组件(.vue 文件)结构
单文件组件(SFC)是 Vue 推荐的组件组织方式,其结构清晰,便于维护。
<template><!-- 模板部分:定义组件的 HTML 结构 --><div class="hello"><h1>{{ msg }}</h1></div></template><script setup><!-- 脚本部分:处理组件的逻辑 -->// 导入需要的模块或组件import { ref } from 'vue'// 定义组件的数据const msg = ref('Hello Vue 3!')</script><style scoped>
<!-- 样式部分:定义组件的样式 -->.hello {color: blue;text-align: center;}</style>
- 模板(Template):必须包含在 <template> 标签内,用于定义组件的渲染结构。一个组件的模板只能有一个根元素(Vue 3 支持多根元素,但通常建议使用一个根元素包裹)。
- 脚本(Script):使用 <script setup> 语法(Vue 3 推荐),用于编写组件的逻辑,包括数据定义、方法声明、生命周期钩子等。setup 是 Vue 3 组合式 API 的入口点。
- 样式(Style):包含在 <style> 标签内,用于定义组件的样式。添加 scoped 属性后,样式仅作用于当前组件,避免样式污染。
1.2 组件的注册与使用
组件分为全局注册和局部注册两种方式,全局注册的组件可在整个应用中使用,局部注册的组件仅能在注册它的父组件中使用。
1.2.1 全局注册
在 main.js 中通过 app.component() 方法全局注册组件:
// main.js
import { createApp } from 'vue'import App from './App.vue'import HelloWorld from './components/HelloWorld.vue'const app = createApp(App)// 全局注册 HelloWorld 组件,第一个参数是组件名,第二个参数是组件对象app.component('HelloWorld', HelloWorld)app.mount('#app')
注册后,可在任意组件的模板中直接使用:
<template><div><HelloWorld /></div>
</template>
1.2.2 局部注册
在需要使用组件的父组件中,通过 import 导入组件后,在 components 选项中注册:
<template><div><LocalComponent /></div></template><script setup>import LocalComponent from './components/LocalComponent.vue'// 在 setup 语法中,导入的组件会自动注册,无需额外配置</script>
1.3 组件通信基础(父传子)
父组件通过 props 向子组件传递数据,子组件通过定义 props 接收数据。
父组件示例
<template><div><ChildComponent :message="parentMsg" :count="10" /></div></template><script setup>import { ref } from 'vue'import ChildComponent from './components/ChildComponent.vue'const parentMsg = ref('来自父组件的消息')</script>
子组件示例
<template>
<div>
<p>{{ message }}</p>
<p>接收的数字:{{ count }}</p>
</div>
</template>
<script setup>
import { defineProps } from 'vue'
// 定义 props,指定接收的属性名和类型
const props = defineProps({
message: String,
count: Number
})
// 使用 props 中的数据(直接通过 props.属性名访问)console.log(props.message)
</script>
在子组件中,defineProps 用于声明接收的 props,可以指定属性的类型、默认值、验证规则等。父组件传递数据时,通过 v-bind(简写为 :)将数据绑定到子组件的属性上。
二、模板语法
Vue 的模板语法是一种基于 HTML 的模板系统,它允许在 HTML 中嵌入 Vue 特有的语法,实现数据绑定、条件渲染、列表渲染等功能。
2.1 文本插值
使用双大括号 {{ }} 可以将响应式数据插入到模板中,这称为文本插值。
<template><div><p>基本文本:{{ username }}</p><p>表达式计算:{{ 1 + 2 * 3 }}</p><p>函数调用:{{ formatMessage('Hello') }}</p></div></template><script setup>import { ref } from 'vue'const username = ref('Vue 用户')const formatMessage = (str) => {return str + ',欢迎使用 Vue 3'}</script>
双大括号内可以是变量、表达式或函数调用,Vue 会自动计算并将结果渲染到页面上。当数据发生变化时,插值内容会自动更新。
2.2 指令
指令是带有 v- 前缀的特殊属性,用于在模板中实现复杂的逻辑操作。
2.2.1 v-bind:绑定属性
v-bind 用于动态绑定 HTML 属性,可简写为 :。
<template>
<div>
<img v-bind:src="imageUrl" alt="图片">
<a :href="linkUrl" :class="{ active: isActive }">链接</a>
</div>
</template>
<script setup>
import { ref } from 'vue'
const imageUrl = ref('https://vuejs.org/images/logo.png')
const linkUrl = ref('https://vuejs.org')
const isActive = ref(true)
</script>
<style>
.active {
color: red;
text-decoration: underline;
}
</style>
上述示例中,src、href、class 属性的值通过 v-bind 绑定到响应式数据上,当数据变化时,属性值会自动更新。class 还支持对象语法,根据 isActive 的值动态添加或移除 active 类。
2.2.2 v-on:事件绑定
v-on 用于绑定事件监听器,可简写为 @。
<template>
<div>
<button v-on:click="handleClick">点击按钮</button>
<button @dblclick="handleDoubleClick">双击按钮</button>
<input @input="handleInput" placeholder="输入内容">
</div>
</template>
<script setup>
import { ref } from 'vue'
const handleClick = () => {
console.log('按钮被点击了')
}
const handleDoubleClick = () => {
console.log('按钮被双击了')
}
const handleInput = (e) => {
console.log('输入的内容:', e.target.value)
}
</script>
v-on 可以绑定各种 DOM 事件,事件处理函数可以接收事件对象 e,通过 e.target 等属性获取事件相关信息。
2.2.3 v-model:双向数据绑定
v-model 用于在表单元素(如输入框、复选框等)和响应式数据之间建立双向绑定,即数据变化时表单元素的值会更新,表单元素的值变化时数据也会同步更新。
<template>
<div>
<input v-model="username" placeholder="输入用户名">
<p>您输入的用户名:{{ username }}</p>
<textarea v-model="content" placeholder="输入内容"></textarea>
<p>文本域内容:{{ content }}</p>
<label>
<input type="checkbox" v-model="isAgree"> 同意协议
</label>
<p>是否同意:{{ isAgree }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
const content = ref('')
const isAgree = ref(false)
</script>
v-model 会根据表单元素的类型自动选择合适的绑定方式,例如文本输入框绑定 value 属性和 input 事件,复选框绑定 checked 属性和 change 事件。
2.2.4 条件渲染(v-if /v-else/v-else-if)
v-if、v-else、v-else-if 用于根据条件动态渲染元素。
<template><div><p v-if="score >= 90">优秀</p><p v-else-if="score >= 60">及格</p><p v-else>不及格</p><button @click="score += 10">加分</button><button @click="score -= 10" :disabled="score < 10">减分</button><p>当前分数:{{ score }}</p></div></template><script setup>import { ref } from 'vue'const score = ref(70)</script>
v-if 会根据条件决定是否渲染元素,如果条件为 false,元素会被从 DOM 中移除;而 v-show 则是通过 display: none 控制元素的显示与隐藏,元素始终存在于 DOM 中。通常,频繁切换显示状态时使用 v-show 性能更好,条件很少改变时使用 v-if 更合适。
2.2.5 列表渲染(v-for)
v-for 用于基于数组或对象渲染列表,语法为 v-for="(item, index) in items",其中 item 是数组元素,index 是元素的索引(可选)。
<template><div><h3>数组渲染</h3><ul><li v-for="(fruit, index) in fruits" :key="index">{{ index + 1 }}. {{ fruit }}</li></ul><h3>对象渲染</h3><ul><li v-for="(value, key) in user" :key="key">{{ key }}: {{ value }}</li></ul></div></template><script setup>import { ref, reactive } from 'vue'const fruits = ref(['苹果', '香蕉', '橙子'])const user = reactive({name: '张三',age: 25,gender: '男'})</script>
使用 v-for 时,必须为每个列表项指定 key 属性,key 的值应该是唯一的(通常使用数据的唯一标识,如 ID),以便 Vue 能够高效地跟踪列表项的变化,优化渲染性能。
2.3 事件修饰符
事件修饰符用于处理事件的默认行为或事件冒泡等问题,通过 .修饰符 的形式添加到 v-on 指令后。
常用的事件修饰符:
- .stop:阻止事件冒泡
- .prevent:阻止事件的默认行为
- .once:事件只触发一次
- .self:只有事件目标是当前元素时才触发事件
<template><div @click="parentClick"><button @click.stop="childClick">点击(阻止冒泡)</button><a href="https://vuejs.org" @click.prevent="handleLinkClick">Vue 官网(阻止跳转)</a><button @click.once="onceClick">只点击一次</button></div></template><script setup>const parentClick = () => {console.log('父元素点击事件')}const childClick = () => {console.log('子元素点击事件')}const handleLinkClick = () => {console.log('链接被点击')}const onceClick = () => {console.log('只触发一次')}</script>
在上述示例中:
- .stop 阻止了子元素的点击事件冒泡到父元素,因此点击按钮时只会触发 childClick,不会触发 parentClick。
- .prevent 阻止了链接的默认跳转行为,点击链接时只会执行 handleLinkClick。
- .once 使按钮的点击事件只触发一次。