Vue框架之模板語法全面解析
- 一、模板語法的核心思想
- 二、插值表達式:數據渲染的基礎
- 2.1 基本用法:渲染文本
- 2.2 純HTML渲染:`v-html`指令
- 2.3 一次性插值:`v-once`指令
- 三、指令系統:控制DOM的行為
- 3.1 條件渲染:`v-if`與`v-show`
- 3.1.1 `v-if`:動態創建/銷毀元素
- 3.1.2 `v-else`與`v-else-if`:條件分支
- 3.1.3 `v-show`:動態顯示/隱藏元素
- 3.1.4 `v-if`與`v-show`的區別
- 3.2 列表渲染:`v-for`
- 3.2.1 遍歷數組
- 3.2.2 遍歷對象
- 3.2.3 `key`屬性的重要性
- 3.3 屬性綁定:`v-bind`
- 3.3.1 基礎用法
- 3.3.2 綁定class的特殊用法
- 3.3.3 綁定style的特殊用法
- 3.4 事件綁定:`v-on`
- 3.4.1 基礎用法
- 3.4.2 傳遞事件參數
- 3.4.3 事件修飾符
- 3.5 表單綁定:`v-model`
- 3.5.1 文本框與文本域
- 3.5.2 復選框與單選框
- 3.5.3 下拉框
- 3.5.4 修飾符
- 四、模板語法的進階技巧
- 4.1 計算屬性:`computed`
- 4.2 偵聽器:`watch`
- 4.3 模板中的注釋
- 五、常見問題與避坑指南
- 5.1 插值表達式不能使用語句
- 5.2 `v-for`與`v-if`同時使用的陷阱
- 5.3 響應式數據更新不觸發視圖
Vue的模板語法是連接數據與視圖的橋梁,它允許我們開發者以聲明式的方式將數據渲染到DOM中,同時支持豐富的指令和表達式,掌握模板語法是使用Vue開發頁面的基礎,本文我將從插值表達式、指令系統、事件處理到表單綁定,系統解析Vue模板語法的核心知識點,并結合實例演示其用法。
一、模板語法的核心思想
Vue的模板語法基于HTML擴展,核心思想是聲明式渲染:開發者只需關注“數據應該如何展示”,而無需手動操作DOM。模板中的特殊語法會被Vue編譯器處理,最終轉換為渲染函數,生成對應的DOM節點。
<!-- 示例:聲明式渲染 -->
<div id="app"><h1>{{ message }}</h1>
</div><script>
const app = new Vue({el: '#app',data() {return {message: 'Hello Vue Template!'}}
});
</script>
上述代碼中,{{ message }}
是模板語法的核心——插值表達式,它會將Vue實例中的message
數據實時渲染到頁面中。當message
的值變化時,頁面會自動更新,這就是Vue的響應式渲染特性。
二、插值表達式:數據渲染的基礎
插值表達式是模板中最基礎的語法,用于將數據插入到DOM中,語法為{{ 表達式 }}
。
2.1 基本用法:渲染文本
<div id="app"><!-- 直接渲染變量 --><p>姓名:{{ name }}</p><!-- 渲染表達式結果 --><p>年齡+1:{{ age + 1 }}</p><!-- 渲染函數返回值 --><p>大寫姓名:{{ name.toUpperCase() }}</p><!-- 三元表達式 --><p>是否成年:{{ age >= 18 ? '是' : '否' }}</p>
</div><script>
new Vue({el: '#app',data() {return {name: 'zhangsan',age: 20}}
});
</script>
特性:
- 支持JavaScript表達式(如
+
、toUpperCase()
、三元運算),但不能寫語句(如if
、for
); - 數據變化時自動更新(響應式);
- 會自動轉義HTML(防止XSS攻擊),例如
{{ '<h1>標題</h1>' }}
會渲染為純文本,而非HTML標簽。
2.2 純HTML渲染:v-html
指令
如果需要渲染包含HTML標簽的字符串,需使用v-html
指令(注意XSS風險):
<div id="app"><!-- 插值表達式:轉義HTML --><p>{{ rawHtml }}</p> <!-- 輸出:<span style="color: red">紅色文本</span> --><!-- v-html:渲染為HTML --><p v-html="rawHtml"></p> <!-- 輸出:紅色文本(實際為紅色) -->
</div><script>
new Vue({el: '#app',data() {return {rawHtml: '<span style="color: red">紅色文本</span>'}}
});
</script>
注意:
v-html
會覆蓋元素的子節點;- 動態渲染HTML存在XSS風險,僅在內容完全可信時使用;
- 不能用于單文件組件(SFC)的模板根節點。
2.3 一次性插值:v-once
指令
如果數據只需渲染一次,后續變化不再更新,可使用v-once
:
<div id="app"><p v-once>初始值:{{ message }}</p><p>實時值:{{ message }}</p><button @click="message = '新值'">修改值</button>
</div><script>
new Vue({el: '#app',data() {return {message: '初始值'}}
});
</script>
點擊按鈕后,v-once
所在的段落仍顯示“初始值”,而另一段落會更新為“新值”。
三、指令系統:控制DOM的行為
Vue提供了一系列內置指令(以v-
為前綴),用于控制DOM的行為,如條件渲染、列表渲染、事件綁定等。
3.1 條件渲染:v-if
與v-show
3.1.1 v-if
:動態創建/銷毀元素
v-if
根據表達式的真假,動態創建或銷毀元素(完全從DOM中移除):
<div id="app"><p v-if="isShow">這是v-if控制的內容</p><button @click="isShow = !isShow">切換顯示</button>
</div><script>
new Vue({el: '#app',data() {return {isShow: true}}
});
</script>
3.1.2 v-else
與v-else-if
:條件分支
<div id="app"><p v-if="score >= 90">優秀</p><p v-else-if="score >= 60">及格</p><p v-else>不及格</p>
</div><script>
new Vue({el: '#app',data() {return {score: 85}}
});
</script>
3.1.3 v-show
:動態顯示/隱藏元素
v-show
通過CSS的display
屬性控制元素顯示(display: none
),元素始終存在于DOM中:
<div id="app"><p v-show="isShow">這是v-show控制的內容</p><button @click="isShow = !isShow">切換顯示</button>
</div>
3.1.4 v-if
與v-show
的區別
特性 | v-if | v-show |
---|---|---|
原理 | 動態創建/銷毀DOM元素 | 通過display: none 控制顯示 |
初始渲染成本 | 條件為假時,無渲染成本 | 無論條件真假,都有初始渲染成本 |
切換成本 | 較高(涉及DOM操作) | 較低(僅修改CSS) |
適用場景 | 條件很少切換(如權限控制) | 條件頻繁切換(如標簽頁切換) |
3.2 列表渲染:v-for
v-for
用于循環渲染列表數據,支持數組、對象、字符串和數字,語法為v-for="(item, index) in items"
。
3.2.1 遍歷數組
<div id="app"><ul><!-- 遍歷數組:(元素, 索引) --><li v-for="(item, index) in fruits" :key="item.id">{{ index + 1 }}. {{ item.name }} - 價格:{{ item.price }}元</li></ul>
</div><script>
new Vue({el: '#app',data() {return {fruits: [{ id: 1, name: '蘋果', price: 5 },{ id: 2, name: '香蕉', price: 3 },{ id: 3, name: '橙子', price: 4 }]}}
});
</script>
3.2.2 遍歷對象
<div id="app"><ul><!-- 遍歷對象:(值, 鍵名, 索引) --><li v-for="(value, key, index) in user" :key="key">{{ index + 1 }}. {{ key }}: {{ value }}</li></ul>
</div><script>
new Vue({el: '#app',data() {return {user: {name: '張三',age: 25,gender: '男'}}}
});
</script>
3.2.3 key
屬性的重要性
v-for
渲染列表時,必須添加key
屬性(唯一標識),Vue通過key
識別元素的身份,優化DOM更新性能:
<!-- 錯誤:無key(不推薦) -->
<li v-for="item in list">{{ item }}</li><!-- 正確:使用唯一key(推薦) -->
<li v-for="item in list" :key="item.id">{{ item.name }}</li>
注意:
key
的值必須唯一,不能重復;- 不要用
index
作為key
(數組排序、刪除元素時會導致身份錯亂); - 推薦使用數據的唯一ID作為
key
(如后端返回的id
)。
3.3 屬性綁定:v-bind
v-bind
用于動態綁定HTML屬性,語法為v-bind:屬性名="表達式"
,可簡寫為:屬性名
。
3.3.1 基礎用法
<div id="app"><!-- 綁定src屬性 --><img :src="imgUrl" alt="圖片"><!-- 綁定class屬性 --><div :class="boxClass">這是一個div</div><!-- 綁定style屬性 --><p :style="textStyle">這是帶樣式的文本</p><!-- 綁定自定義屬性 --><div :data-id="itemId"></div>
</div><script>
new Vue({el: '#app',data() {return {imgUrl: 'https://picsum.photos/200',boxClass: 'container active',textStyle: {color: 'red',fontSize: '16px'},itemId: 123}}
});
</script>
3.3.2 綁定class的特殊用法
class
屬性支持對象和數組語法,動態控制類名:
<div id="app"><!-- 對象語法:{ 類名: 布爾值 } --><div :class="{ active: isActive, 'text-danger': hasError }"></div><!-- 數組語法:[類名1, 類名2] --><div :class="[baseClass, isActive ? 'active' : '']"></div>
</div><script>
new Vue({el: '#app',data() {return {isActive: true,hasError: false,baseClass: 'container'}}
});
</script>
3.3.3 綁定style的特殊用法
style
屬性支持對象和數組語法,動態控制樣式:
<div id="app"><!-- 對象語法:{ CSS屬性: 值 }(注意駝峰命名) --><div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div><!-- 數組語法:[樣式對象1, 樣式對象2] --><div :style="[baseStyle, highlightStyle]"></div>
</script><script>
new Vue({el: '#app',data() {return {textColor: 'blue',fontSize: 16,baseStyle: { padding: '10px' },highlightStyle: { backgroundColor: 'yellow' }}}
});
</script>
3.4 事件綁定:v-on
v-on
用于綁定事件監聽器,語法為v-on:事件名="處理函數"
,可簡寫為@事件名
。
3.4.1 基礎用法
<div id="app"><!-- 綁定點擊事件 --><button @click="handleClick">點擊我</button><!-- 綁定輸入事件 --><input @input="handleInput" placeholder="輸入內容"><!-- 直接執行表達式 --><button @click="count++">計數器:{{ count }}</button>
</div><script>
new Vue({el: '#app',data() {return {count: 0}},methods: {handleClick() {alert('按鈕被點擊了');},handleInput(e) {console.log('輸入內容:', e.target.value); // e是原生事件對象}}
});
</script>
3.4.2 傳遞事件參數
<div id="app"><!-- 無參數:默認傳遞事件對象e --><button @click="handleClick">無參數</button><!-- 傳遞自定義參數:需手動傳遞$event獲取原生事件對象 --><button @click="handleClickWithParams('參數1', $event)">帶參數</button>
</div><script>
new Vue({el: '#app',methods: {handleClick(e) {console.log('事件對象:', e);},handleClickWithParams(param, e) {console.log('參數:', param);console.log('事件對象:', e);}}
});
</script>
3.4.3 事件修飾符
Vue提供了事件修飾符,簡化事件處理(如阻止默認行為、阻止冒泡):
<div id="app"><!-- .prevent:阻止默認行為(如表單提交) --><form @submit.prevent="handleSubmit"><button type="submit">提交</button></form><!-- .stop:阻止事件冒泡 --><div @click="parentClick"><button @click.stop="childClick">點擊</button></div><!-- .once:事件只觸發一次 --><button @click.once="handleOnce">只觸發一次</button>
</div><script>
new Vue({el: '#app',methods: {handleSubmit() {console.log('表單提交');},parentClick() {console.log('父元素事件');},childClick() {console.log('子元素事件');},handleOnce() {console.log('只觸發一次');}}
});
</script>
常用事件修飾符:
.prevent
:阻止默認行為(如e.preventDefault()
);.stop
:阻止事件冒泡(如e.stopPropagation()
);.once
:事件只觸發一次;.self
:僅當事件目標是元素自身時觸發;.enter
:僅在按鍵為Enter時觸發(鍵盤事件專用)。
3.5 表單綁定:v-model
v-model
用于在表單元素(輸入框、復選框等)與數據之間創建雙向綁定,本質是v-bind
綁定value
和v-on
監聽input
事件的語法糖。
3.5.1 文本框與文本域
<div id="app"><!-- 單行文本框 --><input v-model="username" placeholder="用戶名"><p>用戶名:{{ username }}</p><!-- 多行文本域(與單行用法一致,無需使用textarea的value屬性) --><textarea v-model="message" rows="3" placeholder="留言"></textarea><p>留言:{{ message }}</p>
</div><script>
new Vue({el: '#app',data() {return {username: '',message: ''}}
});
</script>
3.5.2 復選框與單選框
<div id="app"><!-- 單選框(v-model綁定選中的值) --><div><label><input type="radio" v-model="gender" value="male"> 男</label><label><input type="radio" v-model="gender" value="female"> 女</label><p>性別:{{ gender }}</p></div><!-- 復選框(單個:綁定布爾值) --><div><label><input type="checkbox" v-model="isAgree"> 同意協議</label><p>是否同意:{{ isAgree }}</p></div><!-- 復選框(多個:綁定數組,value為選中的值) --><div><label><input type="checkbox" v-model="hobbies" value="reading"> 閱讀</label><label><input type="checkbox" v-model="hobbies" value="sports"> 運動</label><p>愛好:{{ hobbies }}</p></div>
</div><script>
new Vue({el: '#app',data() {return {gender: 'male',isAgree: false,hobbies: []}}
});
</script>
3.5.3 下拉框
<div id="app"><!-- 單選下拉框 --><select v-model="selectedCity"><option value="">請選擇城市</option><option value="beijing">北京</option><option value="shanghai">上海</option></select><p>選中城市:{{ selectedCity }}</p><!-- 多選下拉框(添加multiple屬性,v-model綁定數組) --><select v-model="selectedCities" multiple><option value="beijing">北京</option><option value="shanghai">上海</option><option value="guangzhou">廣州</option></select><p>選中城市:{{ selectedCities }}</p>
</div><script>
new Vue({el: '#app',data() {return {selectedCity: '',selectedCities: []}}
});
</script>
3.5.4 修飾符
v-model
提供了修飾符,處理表單數據:
.trim
:自動去除首尾空格;.number
:將輸入值轉為數字(無法轉換時保留字符串);.lazy
:在change
事件(而非input
)時更新數據(適合輸入完成后驗證)。
<div id="app"><input v-model.trim="username" placeholder="自動去空格"><input v-model.number="age" placeholder="僅數字"><input v-model.lazy="search" placeholder="失去焦點后更新">
</div>
四、模板語法的進階技巧
4.1 計算屬性:computed
當模板中的表達式邏輯復雜時,推薦使用計算屬性(computed
),它具有緩存特性,依賴數據不變時不會重新計算。
<div id="app"><p>原始價格:{{ price }}</p><p>折扣價(9折):{{ discountedPrice }}</p><p>折扣價(8折):{{ getDiscountedPrice(0.8) }}</p>
</div><script>
new Vue({el: '#app',data() {return {price: 100}},computed: {// 計算屬性(緩存)discountedPrice() {console.log('計算屬性執行');return this.price * 0.9;}},methods: {// 方法(無緩存,每次調用都執行)getDiscountedPrice(discount) {console.log('方法執行');return this.price * discount;}}
});
</script>
計算屬性 vs 方法:
- 計算屬性:依賴數據變化時才重新計算,適合頻繁訪問且邏輯復雜的場景;
- 方法:每次調用都執行,適合需要動態參數的場景。
4.2 偵聽器:watch
watch
用于監聽數據變化,執行異步或復雜邏輯(如數據變化后發送請求)。
<div id="app"><input v-model="username" placeholder="輸入用戶名">
</div><script>
new Vue({el: '#app',data() {return {username: ''}},watch: {// 監聽username變化username(newVal, oldVal) {console.log(`用戶名從${oldVal}變為${newVal}`);// 模擬異步請求(如驗證用戶名是否已存在)clearTimeout(this.timer);this.timer = setTimeout(() => {console.log(`驗證用戶名:${newVal}`);}, 500);}}
});
</script>
4.3 模板中的注釋
Vue模板支持HTML注釋和Vue特有的注釋(不會被渲染到DOM中):
<div id="app"><!-- 這是HTML注釋,會被渲染到DOM中 -->{{ /* 這是Vue注釋,不會被渲染 */ }}
</div>
五、常見問題與避坑指南
5.1 插值表達式不能使用語句
<!-- 錯誤:模板表達式不能用if語句 -->
<p>{{ if (isShow) { return '顯示' } else { return '隱藏' } }}</p><!-- 正確:用三元表達式 -->
<p>{{ isShow ? '顯示' : '隱藏' }}</p>
5.2 v-for
與v-if
同時使用的陷阱
不建議在同一元素上同時使用v-for
和v-if
,因為v-for
的優先級高于v-if
,會導致每次循環都執行條件判斷,影響性能。
錯誤示例:
<!-- 不推薦:每次循環都判斷 -->
<li v-for="item in list" v-if="item.isActive" :key="item.id">{{ item.name }}
</li>
正確示例:先過濾數據,再循環
<!-- 推薦:先過濾數據 -->
<li v-for="item in activeItems" :key="item.id">{{ item.name }}
</li><script>
new Vue({computed: {activeItems() {return this.list.filter(item => item.isActive);}}
});
</script>
5.3 響應式數據更新不觸發視圖
Vue的響應式系統依賴Object.defineProperty
(Vue 2),直接修改數組索引或對象屬性可能不會觸發視圖更新:
// 錯誤:直接修改數組索引
this.list[0] = '新值'; // 視圖不更新// 正確:使用Vue提供的方法或重新賦值
this.list.splice(0, 1, '新值'); // 或 this.list = [...this.list, 新值]// 錯誤:直接添加對象屬性
this.user.age = 25; // 視圖不更新// 正確:使用Vue.set或重新賦值
this.$set(this.user, 'age', 25); // 或 this.user = { ...this.user, age: 25 }
總結:Vue的模板語法是其聲明式編程模型的核心,通過簡潔的語法將數據與視圖關聯
- 簡化DOM操作:無需手動操作DOM,專注數據邏輯;
- 響應式更新:數據變化自動同步到視圖;
- 豐富的指令:
v-if
、v-for
、v-model
等指令覆蓋常見場景;- 靈活的擴展:計算屬性、偵聽器處理復雜邏輯。
若這篇內容幫到你,動動手指支持下!關注不迷路,干貨持續輸出!
ヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノ