Vue基礎(chǔ)學(xué)習(xí)之ref響應(yīng)式數(shù)據(jù)、v-指令、computed
前言
本文將帶你從一個(gè)Todos清單組件,上手Vue基礎(chǔ)語法以及核心思想,設(shè)計(jì)內(nèi)容有ref響應(yīng)式數(shù)據(jù),v-指令、computed計(jì)算屬性
完整代碼:
<!-- App.vue -->
<script setup>
import { ref, computed } from 'vue'
// 1. 響應(yīng)式數(shù)據(jù):所有 UI 都靠它們驅(qū)動(dòng)
const title = ref('') // 輸入框內(nèi)容
const todos = ref([
{ id: 1, title: '睡覺', done: true },
{ id: 2, title: '吃飯', done: true }
])
// 添加任務(wù)
function addTodo() {
if (!title.value.trim()) return
todos.value.push({
id: Math.random(),
title: title.value.trim(),
done: false
})
title.value = '' // 清空輸入框
}
// 2. 計(jì)算屬性:派生數(shù)據(jù),自動(dòng)更新
// 統(tǒng)計(jì)未完成的數(shù)量
const active = computed(() => {
return todos.value.filter(t => !t.done).length
})
// 全選/全不選的高級(jí)玩法
const allDone = computed({
get() {
return todos.value.length > 0 && todos.value.every(t => t.done)
},
set(val) {
todos.value.forEach(t => t.done = val)
}
})
</script>
<template>
<div class="container">
<h2>我的 Todos 任務(wù)清單</h2>
<!-- 雙向綁定 + 回車添加 -->
<input type="text" placeholder="今天還要干啥?回車添加" v-model="title" @keydown.enter="addTodo" />
<!-- 任務(wù)列表 -->
<ul v-if="todos.length">
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done">
<span :class="{ done: todo.done }">{{ todo.title }}</span>
</li>
</ul>
<div v-else class="empty">暫無計(jì)劃,摸魚去吧~</div>
<!-- 統(tǒng)計(jì) + 全選 -->
<div class="footer">
<label>
<input type="checkbox" v-model="allDone" />
全選
</label>
<span>未完成 {{ active }} / 共 {{ todos.length }} 條</span>
</div>
</div>
</template>
<style scoped>
.container {
max-width: 400px;
margin: 40px auto;
font-family: sans-serif;
}
input[type="text"] {
width: 100%;
padding: 8px;
font-size: 16px;
}
ul {
padding-left: 0;
list-style: none;
}
li {
padding: 8px 0;
display: flex;
align-items: center;
gap: 8px;
}
.done {
color: #999;
text-decoration: line-through;
}
.empty {
color: #999;
text-align: center;
padding: 20px;
}
.footer {
margin-top: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
實(shí)際展示:

一、拆解Vue代碼
其實(shí)Vue主界面的代碼就是我們的HTML+JS+CSS,它是一個(gè)三明治結(jié)構(gòu)
<script setup></script> //JavaScript
<template></template> //HTML
<style scoped></style> //CSS
二、 響應(yīng)式數(shù)據(jù):Vue 的靈魂
傳統(tǒng)寫法(jQuery 時(shí)代):
// 想改標(biāo)題?先找 DOM 再改 innerText
document.querySelector('h2').innerText = '新標(biāo)題'
Vue 寫法:
const title = ref('Todos任務(wù)清單')
然后模板里直接 {{ title }},你改 title.value = '新標(biāo)題',頁(yè)面就自動(dòng)變了。
為什么這么神奇?因?yàn)?Vue 把 todos、title 這些 ref 包裝成了響應(yīng)式對(duì)象,只要你通過 .value 去改它,Vue 就知道「有數(shù)據(jù)變了」,然后自動(dòng)把所有用到這個(gè)數(shù)據(jù)的地方更新一遍。
記住一句話:在 Vue 里,你只需要操心數(shù)據(jù)怎么變,頁(yè)面怎么變 Vue 幫你搞定。
三、 Vue 基礎(chǔ)指令
| 指令 | 作用 | 本例中的用法 |
|---|---|---|
| v-model | 雙向綁定,表單專屬神器 | 輸入框和任務(wù)的 checkbox 都用了它 |
| v-for | 循環(huán)渲染數(shù)組 | 遍歷 todos 渲染每一行 |
| v-if / v-else | 條件渲染 | 沒任務(wù)時(shí)顯示「暫無計(jì)劃」 |
| v-bind | 動(dòng)態(tài)綁定HTML屬或者組件的props | 完成的任務(wù)加上刪除線和灰色 |
| @click / @keydown.enter | 事件監(jiān)聽簡(jiǎn)寫 | 回車添加任務(wù) |
這些指令就是 Vue 給我們提供的「魔法語法糖」,讓我們幾乎不用寫原生 DOM 操作。
1.v-model——雙向數(shù)據(jù)綁定
<input type="text" v-model="title" @keydown.enter="addTodo" /> <input type="checkbox" v-model="todo.done"> <input type="checkbox" v-model="allDone" />
作用:
自動(dòng)同步表單輸入和響應(yīng)式數(shù)據(jù)。
對(duì)于
<input type="text">:v-model="title"等價(jià)于::value="title" @input="title = $event.target.value"
用戶輸入 →
title.value自動(dòng)更新;title.value變化 → 輸入框內(nèi)容更新。對(duì)于
<input type="checkbox">:v-model="todo.done"綁定的是布爾值::checked="todo.done" @change="todo.done = $event.target.checked"
對(duì)于
allDone(計(jì)算屬性):
因?yàn)?allDone有get和set,所以v-model能讀也能寫,實(shí)現(xiàn)“全選”聯(lián)動(dòng)。
2.v-for——列表渲染
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done">
<span :class="{ done: todo.done }">{{ todo.title }}</span>
</li>
作用:
- 遍歷數(shù)組(或?qū)ο螅?,為每個(gè)元素生成一個(gè) DOM 節(jié)點(diǎn)。
todo in todos:todos是源數(shù)組,todo是當(dāng)前項(xiàng)。- 必須加
:key:Vue 用key來高效追蹤每個(gè)節(jié)點(diǎn)的身份(避免復(fù)用錯(cuò)誤)。你用了todo.id,很好!
注意:
- 不要使用
index作為key(除非列表只增不刪),否則可能引發(fā)狀態(tài)錯(cuò)亂。 v-for的優(yōu)先級(jí)高于v-if(如果同時(shí)用),但一般建議避免兩者同用。
3.v-if與v-else——條件渲染
<ul v-if="todos.length"> <!-- 渲染任務(wù)列表 --> </ul> <div v-else class="empty">暫無計(jì)劃,摸魚去吧~</div>
作用:
v-if="todos.length":當(dāng)todos.length > 0(真值)時(shí),渲染<ul>。v-else:必須緊跟在v-if或v-else-if后面,表示“否則”。- 完全銷毀/重建 DOM(不是隱藏),適合切換不頻繁的場(chǎng)景。
對(duì)比v-show:
v-show是通過 CSSdisplay: none切換,DOM 始終存在。- 你的場(chǎng)景用
v-if/v-else更合適,因?yàn)?ldquo;空狀態(tài)”和“有任務(wù)”是互斥的兩種 UI。
4.v-bind(簡(jiǎn)寫:)——動(dòng)態(tài)綁定屬性
<span :class="{ done: todo.done }">{{ todo.title }}</span>
<li v-for="todo in todos" :key="todo.id">
作用:
- 將 HTML 屬性(如
class、id、src、key等)綁定到 JS 表達(dá)式。 :class="{ done: todo.done }":
當(dāng)todo.done === true時(shí),給<span>添加class="done",從而應(yīng)用樣式(刪除線+灰色)。:key="todo.id":將key屬性綁定到todo.id的值。
其他常見用法:
<img :src="imageUrl" />
<div :style="{ color: textColor }"></div>
<a :href="linkUrl" rel="external nofollow" >鏈接</a>
v-bind是 Vue 實(shí)現(xiàn)“數(shù)據(jù)驅(qū)動(dòng)視圖”的關(guān)鍵橋梁。
5.@(即v-on)——事件監(jiān)聽
在你的代碼中:
<input ... @keydown.enter="addTodo" />
作用:
監(jiān)聽 DOM 事件,并執(zhí)行方法。
@keydown.enter是修飾符寫法,等價(jià)于:@keydown="(e) => { if (e.key === 'Enter') addTodo() }"常見修飾符:
.enter:回車鍵.stop:阻止事件冒泡.prevent:阻止默認(rèn)行為.once:只觸發(fā)一次
其他例子:
<button @click="deleteTodo(id)">刪除</button> <input @input="handleInput" /> <form @submit.prevent="handleSubmit">...</form>
@是v-on:的縮寫,就像:是v-bind:的縮寫。
總結(jié):
用戶在輸入框輸入 →
v-model同步到title按回車 →
@keydown.enter觸發(fā)addTodo()→ 新任務(wù)加入todosv-for重新遍歷todos,渲染新<li>每個(gè)任務(wù)的復(fù)選框用
v-model雙向綁定todo.done勾選復(fù)選框 →
todo.done更新 →active計(jì)算屬性自動(dòng)更新(未完成數(shù))allDone.get()重新計(jì)算(是否全選)
底部全選框用
v-model="allDone"→ 點(diǎn)擊時(shí)調(diào)用allDone.set()→ 批量更新所有todo.done如果
todos為空 →v-if切換到v-else顯示“摸魚”提示
四、 computed 計(jì)算屬性:自動(dòng)緩存的派生數(shù)據(jù)

我們想顯示「未完成的任務(wù)有幾條」,最笨的寫法是:
{{ todos.filter(t => !t.done).length }} / {{ todos.length }}
這樣每次渲染都會(huì)重新 filter 一遍,數(shù)據(jù)一大就廢。
聰明做法:
const active = computed(() => todos.value.filter(t => !t.done).length )
computed 有兩大殺招:
- 緩存:只有當(dāng) todos 真的變了,它才會(huì)重新計(jì)算
- 響應(yīng)式:todos 一變,頁(yè)面上所有用了 active 的地方立刻更新
更牛的全選 checkbox:

const allDone = computed({
get() {
return todos.value.length > 0 && todos.value.every(t => t.done)
},
set(val) {
todos.value.forEach(t => t.done = val)
}
})
這樣 就能實(shí)現(xiàn)「全選/全不選」雙向功能,代碼量少到令人發(fā)指。
在 Vue 3 的 computed 中,get 和 set 是用于定義「可讀寫計(jì)算屬性」的兩個(gè)函數(shù)。默認(rèn)情況下,computed 只有一個(gè) getter(即只讀),但當(dāng)你需要讓計(jì)算屬性也能被賦值(比如用在 v-model 中),就需要提供一個(gè) setter(即 set 函數(shù))。
const myComputed = computed({
get() {
// 返回派生值(必須)
return someDerivedValue
},
set(newValue) {
// 處理賦值邏輯(可選)
// 根據(jù) newValue 更新原始數(shù)據(jù)
}
})
get()——讀取時(shí)觸發(fā)
- 當(dāng)你在模板中使用
{{ myComputed }},或在 JS 中讀取myComputed.value時(shí),會(huì)調(diào)用get()。 - 它應(yīng)該返回一個(gè)值,這個(gè)值通?;谄渌憫?yīng)式數(shù)據(jù)(如
ref或reactive對(duì)象)計(jì)算而來。 - Vue 會(huì)自動(dòng)追蹤
get()內(nèi)部訪問的所有響應(yīng)式依賴,并在它們變化時(shí)重新計(jì)算。
set(newValue)——賦值時(shí)觸發(fā)
- 當(dāng)你執(zhí)行
myComputed.value = someValue(例如通過v-model),就會(huì)調(diào)用set(newValue)。 newValue就是你試圖賦給計(jì)算屬性的值。- 在
set中,你不能直接修改計(jì)算屬性本身(因?yàn)樗鼪]有存儲(chǔ)空間),而是要反向更新它所依賴的原始數(shù)據(jù)。
五、 Vue 開發(fā)的核心思維轉(zhuǎn)變
| 傳統(tǒng)開發(fā)(操作 DOM) | Vue 開發(fā)(操作數(shù)據(jù)) |
|---|---|
| 想加一條任務(wù) → appendChild 一個(gè) li | 想加一條任務(wù) → todos.push(新對(duì)象) |
| 想改標(biāo)題 → getElementById().innerText = xxx | 想改標(biāo)題 → title.value = '新標(biāo)題' |
| 想全選 → 遍歷所有 checkbox 打鉤 | 想全選 → allDone = true |
你看,Vue 讓我們徹底從「操作頁(yè)面元素」變成了「操作數(shù)據(jù)」,代碼更清晰、更容易維護(hù)、也更好測(cè)試。
最后總結(jié):
- ref 響應(yīng)式數(shù)據(jù)(核心核心)
- v-model 雙向綁定(表單必備)
- v-for / v-if 指令(模板必備)
- computed 計(jì)算屬性(性能+優(yōu)雅)
- Composition API 的 script setup(現(xiàn)代寫法)
到此這篇關(guān)于Vue基礎(chǔ)學(xué)習(xí)之ref響應(yīng)式數(shù)據(jù)、v-指令、computed的文章就介紹到這了,更多相關(guān)Vue ref響應(yīng)式數(shù)據(jù)、v-指令、computed內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue實(shí)現(xiàn)遠(yuǎn)程獲取路由與頁(yè)面刷新導(dǎo)致404錯(cuò)誤的解決
這篇文章主要介紹了Vue實(shí)現(xiàn)遠(yuǎn)程獲取路由與頁(yè)面刷新導(dǎo)致404錯(cuò)誤的解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
vue-router?導(dǎo)航完成后獲取數(shù)據(jù)的實(shí)現(xiàn)方法
這篇文章主要介紹了vue-router?導(dǎo)航完成后獲取數(shù)據(jù),通過使用生命周期的 created() 函數(shù),在組件創(chuàng)建完成后調(diào)用該方法,本文結(jié)合實(shí)例代碼給大家講解的非常詳細(xì)需要的朋友可以參考下2022-11-11
解決vue單頁(yè)面應(yīng)用進(jìn)入頁(yè)面加載所有 js 的問題
這篇文章主要介紹了解決vue單頁(yè)面應(yīng)用進(jìn)入頁(yè)面加載所有 js 的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
vue實(shí)現(xiàn)靜態(tài)頁(yè)面點(diǎn)贊和取消點(diǎn)贊功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)靜態(tài)頁(yè)面點(diǎn)贊和取消點(diǎn)贊的功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
vue+ElementUI 關(guān)閉對(duì)話框清空驗(yàn)證,清除form表單的操作
這篇文章主要介紹了vue+ElementUI 關(guān)閉對(duì)話框清空驗(yàn)證,清除form表單的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
Vue 刷新當(dāng)前路由的實(shí)現(xiàn)代碼
這篇文章主要介紹了Vue 刷新當(dāng)前路由的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

