前面的話
如果只使用Vue最基礎的聲明式渲染的功能,則完全可以把Vue當做一個模板引擎來使用。本文將詳細介紹Vue模板內容
概述
Vue.js使用了基于HTML的模板語法,允許聲明式地將DOM綁定至底層Vue實例的數據。所有Vue.js的模板都是合法的HTML ,所以能被遵循規范的瀏覽器和HTML解析器解析
在底層的實現上, Vue將模板編譯成虛擬DOM渲染函數。結合響應系統,在應用狀態改變時, Vue能夠智能地計算出重新渲染組件的最小代價并應用到DOM操作上
一般地,模板內容包括文本內容和元素特性
文本渲染
【文本插值】
文本渲染最常見的形式是使用雙大括號語法來進行文本插值,下面的message相當于一個變量或占位符,最終會表示為真正的文本內容
<div id="app"> {{ message }} </div>
<script> new Vue({ el: '#app', data:{ 'message': '<span>測試內容</span>' } }) </script>

【表達式插值】
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }}
上面這些表達式會在所屬Vue實例的數據作用域下作為JS被解析。有個限制就是,每個綁定都只能包含單個表達式,所以下面的例子都不會生效
模板表達式都被放在沙盒中,只能訪問全局變量的一個白名單,如Math
和Date
。不應該在模板表達式中試圖訪問用戶定義的全局變量
<!-- 這是語句,不是表達式 --> {{ var a = 1 }} <!-- 流控制也不會生效,請使用三元表達式 --> {{ if (ok) { return message } }}
[注意]關于表達式與語句的區別移步至此
<div id="app"> {{ num + 1 }} </div>
<script> new Vue({ el: '#app', data:{ 'num': -1 } }) </script>

【v-text】
實現插值類似效果的另一種寫法是使用v-text指令,該指令用于更新元素的innerText。如果要更新部分的innerText,需要使用模板插值
[注意]v-text優先級高于模板插值的優先級
<div id="app" v-text="message"> </div>
<script> new Vue({ el: '#app', data:{ message:"This is a <i>simple</i> document" } }) </script>

【v-html】
如果要輸出真正的 HTML ,需要使用 v-html
指令,該指令用于更新元素的 innerHTML
[注意]在網站上動態渲染任意 HTML 是非常危險的,因為容易導致 XSS 攻擊。只在可信內容上使用 v-html
,而不用在用戶提交的內容上
<div id="app" v-html="message"> </div>
<script> new Vue({ el: '#app', data:{ message:"This is a <i>simple</i> document" } }) </script>

靜態插值
上面介紹了模板插值,一般地,模板插值是動態插值。即無論何時,綁定的數據對象上的占位符內容發生了改變,插值處的內容都會更新
<div id="app"> {{ message }}</div>
<script> var vm = new Vue({ el: '#app', data:{ 'message': '測試內容' } }) </script>
結果如下圖所示,vm.message的內容發生了改變,DOM結構中的元素內容也相應地更新

【v-once】
如果要實現靜態插值,即執行一次性插值,數據改變時,插值處內容不會更新,這時需要用到v-once指令
<div id="app" v-once>{{ message }}</div>
<script> var vm = new Vue({ el: '#app', data:{ 'message': '測試內容' } }) </script>
由下圖所示,vm.message改變為123時,DOM結構中元素內容仍然是“測試內容”

不渲染
【v-pre】
如果要跳過這個元素和它的子元素的編譯過程,只用來顯示原始大括號及標識符,則可以使用v-pre指令。這樣,可以減少編譯時間
<div id="example" v-pre>{{message}}</div>
<script> var vm = new Vue({ el: '#example', data:{ //如果使用v-pre指令,則不會被表示為match message:'match' }, }) </script>

隱藏未編譯
一般地,使用模板差值時,頁面上會顯示大括號及占位符。編譯完成后,再轉換為真正的值。如果在網絡條件不好的情況下,這種現象更加明顯
<div id="example">{{message}}</div>
<script src="https://unpkg.com/vue"></script> <script> var vm = new Vue({ el: '#example', data:{ message:'match' }, }) </script>

【v-cloak】
這個指令保持在元素上直到關聯實例結束編譯。和 CSS 規則如 [v-cloak] { display: none }
一起用時,這個指令可以隱藏未編譯的 Mustache 標簽直到實例準備完畢
<style> [v-cloak]{display:none;} </style> <div id="example" v-cloak>{{message}}</div>
<script src="https://unpkg.com/vue"></script> <script> var vm = new Vue({ el: '#example', data:{ message:'match' }, }) </script>

特性渲染
HTML共有16個全局屬性(或稱為特性),Vue.js支持對特性的內容進行動態渲染
[注意]對象屬性(property)和元素特性(attribute)的區別移步至此
特性渲染時不能使用雙大括號語法
<div id="app" title={{my-title}}></div>
<script> var vm = new Vue({ el: '#app', data:{ 'my-title': '測試內容' } }) </script>
使用上面代碼時,控制臺會顯示如下錯誤

【v-bind】
上面的錯誤提示中提到,應該使用v-bind指令,通過v-bind指令可以動態地綁定一個或多個特性
在這里title是參數,告知v-bind
指令將該元素的title屬性與表達式message的值綁定
<div id="app" v-bind:title="message"></div>
由于v-bind指令非常常用,可縮寫如下
<div id="app" :title="message"></div>
<script> new Vue({ el: '#app', data:{ message:"我是小火柴" } }) </script>

對布爾值的屬性也有效——如果條件被求值為false,該屬性會被移除
<button id="app" :disabled="isButtonDisabled">按鈕</button>
<script> var vm = new Vue({ el: '#app', data:{ 'isButtonDisabled': true } }) </script>

class綁定
數據綁定一個常見需求是操作元素的class列表和它的內聯樣式。因為它們都是屬性 ,可以用v-bind
處理它們:只需要計算出表達式最終的字符串。不過,字符串拼接麻煩又易錯。因此,在v-bind
用于class
和style
時, Vue.js 專門增強了它。表達式的結果類型除了字符串之外,還可以是對象或數組
綁定class包括對象語法、數組語法和組件綁定
【對象語法】
可以傳給 v-bind:class
一個對象,以動態地切換 class
<div v-bind:class="{ active: isActive }"></div>
上面的語法表示 class active
的更新將取決于數據屬性 isActive
是否為真值
可以在對象中傳入更多屬性來動態切換多個class。v-bind:class
指令可以與普通的class屬性共存
<div id="app" class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div>
<script> var app = new Vue({ el: '#app', data:{ isActive:true, hasError:false } }) </script>

當 isActive
或者 hasError
變化時,class 列表將相應地更新。例如,如果 hasError
的值為 true
, class列表將變為 "static active text-danger"

也可以直接綁定數據里的一個對象
<div id="app" :class="classObject"></div>
<script> var app = new Vue({ el: '#app', data:{ classObject: { active: true, 'text-danger': false } } }) </script>

也可以在這里綁定返回對象的計算屬性。這是一個常用且強大的模式
<div id="app" :class="classObject"></div>
<script> var app = new Vue({ el: '#app', data: { isActive: true, error: null }, computed: { classObject: function () { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal', } } } }) </script>

【數組語法】
可以把一個數組傳給 v-bind:class
,以應用一個 class 列表
<div id="app" :class="[activeClass, errorClass]"></div>
<script> var app = new Vue({ el: '#app', data: { activeClass: 'active', errorClass: 'text-danger' } }) </script>

如果要根據條件切換列表中的 class ,可以用三元表達式
<div id="app" :class="[isActive ? activeClass : '', errorClass]"></div>
此例始終添加 errorClass
,但是只有在 isActive
是 true 時添加 activeClass
不過,當有多個條件 class 時這樣寫有些繁瑣。可以在數組語法中使用對象語法
<div id="app" :class="[{ active: isActive }, errorClass]"></div>
【組件綁定】
在一個定制組件上用到class
屬性時,這些類將被添加到根元素上面,這個元素上已經存在的類不會被覆蓋
<div id="app" class="test"> <my-component class="baz boo"></my-component> </div>
<script> Vue.component('my-component', { template: '<p class="foo bar">Hi</p>' }) var app = new Vue({ el: '#app' }) </script>
HTML 最終將被渲染為如下所示

同樣的適用于綁定 HTML class
<div id="app" class="test"> <my-component :class="{ active: isActive }"></my-component> </div>
<script> Vue.component('my-component', { template: '<p class="foo bar">Hi</p>' }) var app = new Vue({ el: '#app', data:{ isActive:true } }) </script>

style綁定
【對象語法】
v-bind:style
的對象語法十分直觀——看著非常像 CSS ,其實它是一個JS對象。 CSS屬性名可以用駝峰式 (camelCase)或(配合引號的)短橫分隔命名 (kebab-case)
<div id="app" :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<script> var app = new Vue({ el: '#app', data: { activeColor: 'red', fontSize: 30 } }) </script>

直接綁定到一個樣式對象通常更好,讓模板更清晰
<div id="app" :style="styleObject"></div>
<script> var app = new Vue({ el: '#app', data: { styleObject: { color: 'red', fontSize: '13px' } } }) </script>
【數組語法】
v-bind:style
的數組語法可以將多個樣式對象應用到一個元素上
<div id="app" :style="[baseStyles, overridingStyles]"></div>
<script> var app = new Vue({ el: '#app', data: { baseStyles: { color: 'red', fontSize: '13px' }, overridingStyles:{ height:'100px', width:'100px' } } }) </script>

【前綴】
當v-bind:style
使用需要特定前綴的CSS屬性時,如transform
,Vue.js會自動偵測并添加相應的前綴
可以為 style
綁定中的屬性提供一個包含多個值的數組,常用于提供多個帶前綴的值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">
這會渲染數組中最后一個被瀏覽器支持的值。在這個例子中,如果瀏覽器支持不帶瀏覽器前綴的 flexbox,那么渲染結果會是 display: flex
過濾器
Vue.js允許自定義過濾器,可被用作一些常見的文本格式化。過濾器可以用在兩個地方:模板插值和v-bind
表達式。過濾器應該被添加在JS表達式的尾部,由“管道”符指示
{{ message | capitalize }} <div v-bind:id="rawId | formatId"></div>
過濾器設計目的是用于文本轉換。為了在其他指令中實現更復雜的數據變換,應該使用計算屬性
過濾器有兩種注冊形式
1、一種是使用Vue.filter()方法
// 注冊
Vue.filter('my-filter', function (value) {
// 返回處理后的值
})
// getter,返回已注冊的過濾器
var myFilter = Vue.filter('my-filter')
2、另一種是在Vue構造函數或組件中使用filters參數
var app = new Vue({
el: '#app',
filters: {
'my-filter': function (value) {
//
}
}
})
過濾器函數總接受表達式的值 (之前的操作鏈的結果) 作為第一個參數。在這個例子中,capitalize
過濾器函數將會收到 message
的值作為第一個參數
<div id="app"> {{ message}} {{ message | capitalize }} </div>
<script> var app = new Vue({ el: '#app', data:{ message: '小火柴' }, filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.split('').reverse().join('') } } }) </script>

過濾器可以串聯
{{ message | filterA | filterB }}
在這個例子中,filterA
擁有單個參數,它會接收 message
的值,然后調用 filterB
,且 filterA
的處理結果將會作為 filterB
的單個參數傳遞進來
<div id="app"> {{ message}} {{ message | filterA | filterB }} </div>
<script> var app = new Vue({ el: '#app', data:{ message: '小火柴' }, filters: { filterA: function (value) { return value.split('').reverse().join('') }, filterB: function(value){ return value.length } } }) </script>

過濾器是JS函數,因此可以接受參數
{{ message | filterA('arg1', arg2) }}
這里,filterA
是個擁有三個參數的函數。message
的值將會作為第一個參數傳入。字符串 'arg1'
將作為第二個參數傳給 filterA
,表達式 arg2
的值將作為第三個參數
<div id="app"> {{ message}} {{ message | filterA('arg1', arg) }} </div>
<script> var app = new Vue({ el: '#app', data:{ message: '小火柴', arg: 'abc' }, filters: { filterA: function (value,arg1,arg2) { return value + arg1 + arg2 } } }) </script>

下面是過濾器在v-bind表達式中使用的一個例子
<div id="app" :class="raw | format"></div>
<script> var app = new Vue({ el: '#app', data:{ raw: 'active' }, filters: { format: function (value) { return value.split('').reverse().join('') } } }) </script>

文章列表