Vue3 基础语法
模板语法
文本插值
<template>
<div>
<!-- 基本插值 -->
<p>{{ message }}</p>
<!-- 表达式 -->
<p>{{ number + 1 }}</p>
<p>{{ ok ? 'YES' : 'NO' }}</p>
<p>{{ message.split('').reverse().join('') }}</p>
<!-- 函数调用 -->
<p>{{ formatMessage(message) }}</p>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const message = ref('Hello Vue3!')
const number = ref(42)
const ok = ref(true)
const formatMessage = (msg) => {
return msg.toUpperCase()
}
return {
message,
number,
ok,
formatMessage
}
}
}
</script>
原始HTML
<template>
<div>
<!-- 普通插值会转义HTML -->
<p>{{ rawHtml }}</p>
<!-- v-html指令输出原始HTML -->
<p v-html="rawHtml"></p>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const rawHtml = ref('<span style="color: red">这是红色文本</span>')
return {
rawHtml
}
}
}
</script>
响应式基础
ref和reactive
<template>
<div>
<h2>ref示例</h2>
<p>计数: {{ count }}</p>
<button @click="increment">增加</button>
<h2>reactive示例</h2>
<p>姓名: {{ user.name }}</p>
<p>年龄: {{ user.age }}</p>
<button @click="updateUser">更新用户</button>
<h2>数组示例</h2>
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<button @click="addItem">添加项目</button>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
// ref:用于基本类型
const count = ref(0)
// reactive:用于对象类型
const user = reactive({
name: '张三',
age: 25
})
// reactive:用于数组
const items = reactive([
{ id: 1, name: '项目1' },
{ id: 2, name: '项目2' }
])
// 方法
const increment = () => {
count.value++
}
const updateUser = () => {
user.name = '李四'
user.age = 30
}
const addItem = () => {
const newId = items.length + 1
items.push({
id: newId,
name: `项目${newId}`
})
}
return {
count,
user,
items,
increment,
updateUser,
addItem
}
}
}
</script>
computed计算属性
<template>
<div>
<h2>计算属性示例</h2>
<p>原始消息: {{ message }}</p>
<p>反转消息: {{ reversedMessage }}</p>
<h2>购物车示例</h2>
<div v-for="item in cart" :key="item.id">
<span>{{ item.name }} - ¥{{ item.price }} x {{ item.quantity }}</span>
</div>
<p><strong>总价: ¥{{ totalPrice }}</strong></p>
<button @click="addToCart">添加商品</button>
</div>
</template>
<script>
import { ref, reactive, computed } from 'vue'
export default {
setup() {
const message = ref('Hello Vue3')
// 计算属性
const reversedMessage = computed(() => {
return message.value.split('').reverse().join('')
})
// 购物车数据
const cart = reactive([
{ id: 1, name: '苹果', price: 5, quantity: 2 },
{ id: 2, name: '香蕉', price: 3, quantity: 3 }
])
// 计算总价
const totalPrice = computed(() => {
return cart.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
})
const addToCart = () => {
cart.push({
id: cart.length + 1,
name: '橙子',
price: 4,
quantity: 1
})
}
return {
message,
reversedMessage,
cart,
totalPrice,
addToCart
}
}
}
</script>
指令
v-bind属性绑定
<template>
<div>
<!-- 基本属性绑定 -->
<img v-bind:src="imageSrc" v-bind:alt="imageAlt">
<!-- 简写语法 -->
<img :src="imageSrc" :alt="imageAlt">
<!-- 动态属性名 -->
<button :[attributeName]="attributeValue">动态属性</button>
<!-- 绑定对象 -->
<div v-bind="objectOfAttrs">多个属性</div>
<!-- 类绑定 -->
<div :class="{ active: isActive, 'text-danger': hasError }">
类绑定示例
</div>
<!-- 数组类绑定 -->
<div :class="[activeClass, errorClass]">数组类绑定</div>
<!-- 样式绑定 -->
<div :style="{ color: textColor, fontSize: fontSize + 'px' }">
样式绑定示例
</div>
<!-- 数组样式绑定 -->
<div :style="[baseStyles, overridingStyles]">数组样式绑定</div>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
const imageSrc = ref('https://via.placeholder.com/150')
const imageAlt = ref('示例图片')
const attributeName = ref('title')
const attributeValue = ref('这是一个动态属性')
const objectOfAttrs = reactive({
id: 'dynamic-id',
class: 'dynamic-class'
})
const isActive = ref(true)
const hasError = ref(false)
const activeClass = ref('active')
const errorClass = ref('text-danger')
const textColor = ref('red')
const fontSize = ref(16)
const baseStyles = reactive({
color: 'blue',
fontSize: '14px'
})
const overridingStyles = reactive({
fontWeight: 'bold'
})
return {
imageSrc,
imageAlt,
attributeName,
attributeValue,
objectOfAttrs,
isActive,
hasError,
activeClass,
errorClass,
textColor,
fontSize,
baseStyles,
overridingStyles
}
}
}
</script>
<style scoped>
.active {
background-color: #42b983;
color: white;
}
.text-danger {
color: #dc3545;
}
</style>
v-on事件处理
<template>
<div>
<!-- 基本事件监听 -->
<button v-on:click="handleClick">点击我</button>
<!-- 简写语法 -->
<button @click="handleClick">点击我(简写)</button>
<!-- 内联处理器 -->
<button @click="count++">计数: {{ count }}</button>
<!-- 传递参数 -->
<button @click="greet('Vue3')">问候</button>
<!-- 访问事件对象 -->
<button @click="handleEvent">事件对象</button>
<!-- 传递参数和事件对象 -->
<button @click="handleWithEvent('参数', $event)">参数和事件</button>
<!-- 事件修饰符 -->
<form @submit.prevent="onSubmit">
<input type="text" v-model="inputValue">
<button type="submit">提交</button>
</form>
<!-- 键盘事件 -->
<input @keyup.enter="onEnter" @keyup.esc="onEsc" placeholder="按Enter或Esc">
<!-- 鼠标事件修饰符 -->
<button @click.left="onLeftClick" @click.right.prevent="onRightClick">
鼠标事件
</button>
<!-- 多个事件处理器 -->
<button @click="one($event), two($event)">多个处理器</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const inputValue = ref('')
const handleClick = () => {
alert('按钮被点击了!')
}
const greet = (name) => {
alert(`Hello, ${name}!`)
}
const handleEvent = (event) => {
console.log('事件对象:', event)
console.log('目标元素:', event.target)
}
const handleWithEvent = (message, event) => {
console.log('消息:', message)
console.log('事件:', event)
}
const onSubmit = () => {
console.log('表单提交:', inputValue.value)
}
const onEnter = () => {
console.log('按下了Enter键')
}
const onEsc = () => {
console.log('按下了Esc键')
}
const onLeftClick = () => {
console.log('左键点击')
}
const onRightClick = () => {
console.log('右键点击')
}
const one = (event) => {
console.log('处理器1', event)
}
const two = (event) => {
console.log('处理器2', event)
}
return {
count,
inputValue,
handleClick,
greet,
handleEvent,
handleWithEvent,
onSubmit,
onEnter,
onEsc,
onLeftClick,
onRightClick,
one,
two
}
}
}
</script>
v-model双向绑定
<template>
<div>
<!-- 文本输入 -->
<div>
<label>文本输入:</label>
<input v-model="text" placeholder="输入文本">
<p>输入的内容: {{ text }}</p>
</div>
<!-- 多行文本 -->
<div>
<label>多行文本:</label>
<textarea v-model="textarea" placeholder="输入多行文本"></textarea>
<p>多行文本: {{ textarea }}</p>
</div>
<!-- 复选框 -->
<div>
<label>
<input type="checkbox" v-model="checked">
复选框: {{ checked }}
</label>
</div>
<!-- 多个复选框 -->
<div>
<label>选择爱好:</label>
<label><input type="checkbox" value="读书" v-model="hobbies"> 读书</label>
<label><input type="checkbox" value="运动" v-model="hobbies"> 运动</label>
<label><input type="checkbox" value="音乐" v-model="hobbies"> 音乐</label>
<p>选择的爱好: {{ hobbies }}</p>
</div>
<!-- 单选按钮 -->
<div>
<label>选择性别:</label>
<label><input type="radio" value="男" v-model="gender"> 男</label>
<label><input type="radio" value="女" v-model="gender"> 女</label>
<p>选择的性别: {{ gender }}</p>
</div>
<!-- 选择框 -->
<div>
<label>选择城市:</label>
<select v-model="selectedCity">
<option disabled value="">请选择</option>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
</select>
<p>选择的城市: {{ selectedCity }}</p>
</div>
<!-- 多选选择框 -->
<div>
<label>选择多个城市:</label>
<select v-model="selectedCities" multiple>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
</select>
<p>选择的城市: {{ selectedCities }}</p>
</div>
<!-- 修饰符 -->
<div>
<label>懒更新 (.lazy):</label>
<input v-model.lazy="lazyText" placeholder="失去焦点时更新">
<p>{{ lazyText }}</p>
</div>
<div>
<label>数字类型 (.number):</label>
<input v-model.number="numberValue" type="number">
<p>值: {{ numberValue }}, 类型: {{ typeof numberValue }}</p>
</div>
<div>
<label>去除空格 (.trim):</label>
<input v-model.trim="trimText" placeholder="自动去除首尾空格">
<p>"{{ trimText }}"</p>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const text = ref('')
const textarea = ref('')
const checked = ref(false)
const hobbies = ref([])
const gender = ref('')
const selectedCity = ref('')
const selectedCities = ref([])
const lazyText = ref('')
const numberValue = ref(0)
const trimText = ref('')
return {
text,
textarea,
checked,
hobbies,
gender,
selectedCity,
selectedCities,
lazyText,
numberValue,
trimText
}
}
}
</script>
<style scoped>
div {
margin-bottom: 15px;
}
label {
display: inline-block;
margin-right: 10px;
}
input, textarea, select {
margin: 5px;
padding: 5px;
}
textarea {
width: 200px;
height: 60px;
}
select[multiple] {
height: 80px;
}
</style>
条件渲染
v-if、v-else-if、v-else
<template>
<div>
<h2>条件渲染示例</h2>
<!-- 基本条件渲染 -->
<div>
<button @click="toggleShow">切换显示</button>
<p v-if="isShow">这段文字会显示/隐藏</p>
</div>
<!-- 多条件判断 -->
<div>
<label>选择类型:</label>
<select v-model="type">
<option value="A">类型A</option>
<option value="B">类型B</option>
<option value="C">类型C</option>
<option value="">其他</option>
</select>
<div v-if="type === 'A'">
<h3>类型A的内容</h3>
<p>这是类型A的详细信息</p>
</div>
<div v-else-if="type === 'B'">
<h3>类型B的内容</h3>
<p>这是类型B的详细信息</p>
</div>
<div v-else-if="type === 'C'">
<h3>类型C的内容</h3>
<p>这是类型C的详细信息</p>
</div>
<div v-else>
<h3>未知类型</h3>
<p>请选择一个有效的类型</p>
</div>
</div>
<!-- template条件渲染 -->
<div>
<button @click="toggleGroup">切换组显示</button>
<template v-if="showGroup">
<h3>这是一组元素</h3>
<p>第一个段落</p>
<p>第二个段落</p>
<p>第三个段落</p>
</template>
</div>
<!-- v-show vs v-if -->
<div>
<button @click="toggleVisibility">切换可见性</button>
<p v-if="isVisible">v-if: {{ isVisible ? '显示' : '隐藏' }}</p>
<p v-show="isVisible">v-show: {{ isVisible ? '显示' : '隐藏' }}</p>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const isShow = ref(true)
const type = ref('A')
const showGroup = ref(true)
const isVisible = ref(true)
const toggleShow = () => {
isShow.value = !isShow.value
}
const toggleGroup = () => {
showGroup.value = !showGroup.value
}
const toggleVisibility = () => {
isVisible.value = !isVisible.value
}
return {
isShow,
type,
showGroup,
isVisible,
toggleShow,
toggleGroup,
toggleVisibility
}
}
}
</script>
列表渲染
v-for指令
<template>
<div>
<h2>列表渲染示例</h2>
<!-- 遍历数组 -->
<div>
<h3>水果列表</h3>
<ul>
<li v-for="(fruit, index) in fruits" :key="fruit.id">
{{ index + 1 }}. {{ fruit.name }} - ¥{{ fruit.price }}
</li>
</ul>
</div>
<!-- 遍历对象 -->
<div>
<h3>用户信息</h3>
<ul>
<li v-for="(value, key) in user" :key="key">
{{ key }}: {{ value }}
</li>
</ul>
</div>
<!-- 遍历对象(包含索引) -->
<div>
<h3>用户信息(带索引)</h3>
<ul>
<li v-for="(value, key, index) in user" :key="key">
{{ index + 1 }}. {{ key }}: {{ value }}
</li>
</ul>
</div>
<!-- 遍历数字 -->
<div>
<h3>数字序列</h3>
<span v-for="n in 10" :key="n">{{ n }} </span>
</div>
<!-- 嵌套循环 -->
<div>
<h3>嵌套列表</h3>
<div v-for="category in categories" :key="category.id">
<h4>{{ category.name }}</h4>
<ul>
<li v-for="item in category.items" :key="item.id">
{{ item.name }}
</li>
</ul>
</div>
</div>
<!-- 动态列表操作 -->
<div>
<h3>动态列表</h3>
<button @click="addItem">添加项目</button>
<button @click="removeItem">删除项目</button>
<button @click="shuffleItems">打乱顺序</button>
<ul>
<li v-for="item in dynamicItems" :key="item.id">
{{ item.name }}
<button @click="removeSpecificItem(item.id)">删除</button>
</li>
</ul>
</div>
<!-- 过滤和排序 -->
<div>
<h3>过滤和排序</h3>
<input v-model="searchText" placeholder="搜索...">
<button @click="toggleSort">切换排序</button>
<ul>
<li v-for="item in filteredAndSortedItems" :key="item.id">
{{ item.name }} - {{ item.score }}
</li>
</ul>
</div>
</div>
</template>
<script>
import { ref, reactive, computed } from 'vue'
export default {
setup() {
// 基础数据
const fruits = reactive([
{ id: 1, name: '苹果', price: 5 },
{ id: 2, name: '香蕉', price: 3 },
{ id: 3, name: '橙子', price: 4 }
])
const user = reactive({
name: '张三',
age: 25,
email: 'zhangsan@example.com',
city: '北京'
})
const categories = reactive([
{
id: 1,
name: '水果',
items: [
{ id: 1, name: '苹果' },
{ id: 2, name: '香蕉' }
]
},
{
id: 2,
name: '蔬菜',
items: [
{ id: 3, name: '白菜' },
{ id: 4, name: '萝卜' }
]
}
])
// 动态列表
const dynamicItems = reactive([
{ id: 1, name: '项目1' },
{ id: 2, name: '项目2' },
{ id: 3, name: '项目3' }
])
let nextId = 4
const addItem = () => {
dynamicItems.push({
id: nextId++,
name: `项目${nextId - 1}`
})
}
const removeItem = () => {
if (dynamicItems.length > 0) {
dynamicItems.pop()
}
}
const removeSpecificItem = (id) => {
const index = dynamicItems.findIndex(item => item.id === id)
if (index > -1) {
dynamicItems.splice(index, 1)
}
}
const shuffleItems = () => {
for (let i = dynamicItems.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[dynamicItems[i], dynamicItems[j]] = [dynamicItems[j], dynamicItems[i]]
}
}
// 过滤和排序
const searchText = ref('')
const sortAsc = ref(true)
const itemsWithScore = reactive([
{ id: 1, name: 'Alice', score: 85 },
{ id: 2, name: 'Bob', score: 92 },
{ id: 3, name: 'Charlie', score: 78 },
{ id: 4, name: 'David', score: 95 }
])
const filteredAndSortedItems = computed(() => {
let filtered = itemsWithScore.filter(item =>
item.name.toLowerCase().includes(searchText.value.toLowerCase())
)
return filtered.sort((a, b) => {
if (sortAsc.value) {
return a.score - b.score
} else {
return b.score - a.score
}
})
})
const toggleSort = () => {
sortAsc.value = !sortAsc.value
}
return {
fruits,
user,
categories,
dynamicItems,
addItem,
removeItem,
removeSpecificItem,
shuffleItems,
searchText,
filteredAndSortedItems,
toggleSort
}
}
}
</script>
<style scoped>
div {
margin-bottom: 20px;
}
button {
margin: 5px;
padding: 5px 10px;
}
input {
margin: 5px;
padding: 5px;
}
ul {
list-style-type: disc;
margin-left: 20px;
}
li {
margin: 5px 0;
}
</style>
总结
本课我们学习了Vue3的基础语法:
- 模板语法:文本插值、表达式、原始HTML
- 响应式基础:ref、reactive、computed
- 指令系统:v-bind、v-on、v-model
- 条件渲染:v-if、v-else-if、v-else、v-show
- 列表渲染:v-for遍历数组、对象、数字
下一课预告
在下一课中,我们将深入学习Vue3的Composition API,包括:
- setup函数详解
- 生命周期钩子
- 响应式API进阶
- 逻辑复用和组合
💡 小贴士:Vue3的响应式系统基于Proxy,比Vue2的Object.defineProperty更强大。理解ref和reactive的区别是掌握Vue3的关键。
📚 文章对你有帮助?请关注我的公众号,万分感谢!
获取更多优质技术文章,第一时间掌握最新技术动态

关注公众号
第一时间获取最新技术文章

添加微信
技术交流 · 问题答疑 · 学习指导
评论讨论
欢迎留下你的想法和建议