代碼javascript
有時數據中攜帶了Html標籤,輸出它們時,按文本解析,如:css
new Vue({ data: { title:'<h3>使用<code>v-html</code>輸出原生的html</h3>', } }).$mount('#app-1')
<div id="app-1" > <div>{{title}}</div> </div>
使用原生指令v-html
解析數據中標籤爲原生htmlhtml
<div id="app-1" > <div v-html="title"></div> </div>
你的站點上動態渲染的任意 HTML 可能會很是危險,由於它很容易致使 XSS 攻擊。請只對可信內容使用 HTML 插值,毫不要對用戶提供的內容使用插值。
如:vue
new Vue({ data: { title:'<h3>使用<code>v-html</code>輸出原生的html</h3>', recieveMessage:'', } }).$mount('#app-1')
<div id="app-1" > <div v-html="title"></div> <input type="text" style="width:300px" v-model="recieveMessage"/> <div> <output v-html="recieveMessage"></output> </div> </div>
使用時要注意這種狀況。插入<script>
幾乎能夠作任何事情,還有插入無數<img>
佔用帶寬。java
當v-if
條件爲truthy時,動態插入內容。
好比在晚7點到早上7點咱們插入如下內容:git
new Vue({ computed: { isNight() { return new Date().getHours() < 7 || new Date().getHours() > 19 } } }).$mount('#app-2')
<div id="app-2"> <div v-if="isNight" style="font-size:30px;color:yellow;background: black;width:300px"> ? it's night </div> </div>
也可使用v-show="isNight"
顯示和隱藏內容web
<div id="app-2"> <div v-show="isNight" style="font-size:30px;color:yellow;background: black;width:300px"> ? it's night </div> </div>
二者區別爲:v-show
元素始終存在,經過display控制顯示/隱藏。而v-if
的轉換要經歷組件的銷燬和重建。使用v-show
初始會有開銷,而v-if
初始條件若爲falsy,那麼什麼也不會作,節省用戶的 CPU 時間。可是若是v-if
頻繁切換條件,那麼開銷又比v-show
大的多。數組
能夠用v-else
和v-else-if
做分支,注意前後順序,順序錯誤則無效。app
<div v-else style="font-size:30px;color:orange;background: lightblue;width:300px"> ? it's day </div>
上面都在外包元素<div>
上使用條件指令,若是不想使用可見元素包裹內容,可使用<template>
標籤測試
<template v-if="isNight"> <span>?</span> <span>it's night</span> </template>
相似其餘語言{}
的做用
if(isNight){ //... }
以上,若v-if
新插入部分與被移除部分有元素是類似的,那麼爲了效率這些元素會被複用,不會從新渲染。
new Vue({ el:'#app-3', data: { loginType: 'username' }, methods: { troggle(){ this.loginType = this.loginType==='username'?'email':'username' } } })
<div id="app-3"> <dl> <dt>key</dt> <dd v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username"> </dd> <dd v-else> <label>Email</label> <input placeholder="Enter your email address"> </dd> <dd> <button @click="troggle">switch</button> </dd> </dl> </div>
input
和label
倆元素自己沒有被替換,所以input
中輸入的內容在切換時會保留,而input
的 placeholder 和label
的內容被替換。
若是使用key
特性對元素做惟一標識,那麼該元素必備替換。
<div id="app-3"> <dl> <dt>不使用key</dt> <dd v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username" key="username"> </dd> <dd v-else> <label>Email</label> <input placeholder="Enter your email address" key="email"> </dd> <dd> <button @click="troggle">switch</button> </dd> </dl> </div>
設置key
後,切換內容時input
的值不在保留。key
主要在v-for
裏使用,以區分列表項,還有動畫部分會大量使用,由於元素複用致使淡入淡出動畫失效。
列表使用細節比較雜碎,按官網教程一個個試下就好了。
通常狀況下用法v-for="列表項 in|of 列表|整數"
如
<h3>以一個整數進行遍歷</h3> <span v-for='n in 10'> {{n}} </span> <h3>票房</h3> <ul> <li v-for="bo of boxOffice"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul>
new Vue({ el: '#app-4', data: { query: '', boxOffice: [ { name: 'Avatar', year: 2009, sells: '27.88' }, { name: 'Frozen', year: 2013, sells: '12.765' }, { name: 'Furious 7', year: 2015, sells: '15.15' }, { name: 'Iron Man 3', year: 2013, sells: '12.154' }, { name: 'Titanic', year: 1997, sells: '21.868' }, { name: 'Spectre', year: 2015, sells: '8.722' }, { name: 'Inception', year: 2010, sells: '8.255' }, { name: 'Jurassic World', year: 2015, sells: '16.99' } ] } })
以上的boxOffice
能夠是個數組,固然咱們也能夠遍歷一個對象的值。如給電影 Avatar 加一個導演屬性
{ name: 'Avatar', year: 2009, sells: '27.88', director:{firstname:'yannie',lastname:'cheung',age:'17'} },
在列表中嵌套一個列表顯示導演信息
<li v-for="bo of boxOffice"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) <ul> <li v-for="value of bo.director">{{value}}</li> </ul> </li>
在列表遍歷中還能夠引用列表索引,對象的遍歷中引用鍵值與索引,索引從0開始。
列表: (列表項,索引) in 列表
對象: (值,鍵值,索引) in 對象
修改示例以顯示這些內容
<ul> <li v-for="(bo,index) of boxOffice"> {{index+1}}、{{bo.name}} {{bo.year}} ({{bo.sells}}$ ) <ul> <li v-for="(value,key,index) of bo.director">{{index+1}}、{{key}}:{{value}}</li> </ul> </li> </ul>
在遍歷對象時,是按 Object.keys() 的結果遍歷,可是不能保證它的結果在不一樣的 JavaScript 引擎下是一致的。
與v-if
相似的,當列表被更新時,這些已被渲染的列表元素不會從新渲染,只會改變其中的內容。咱們修改以上示例,點擊按鈕列表會按票房從新排序,咱們再爲每個li
加上動畫。
data(){ //... isSort:false }, //...... //點擊按鈕,在原順序與票房順序切換 computed: { //點擊按鈕,在原順序與票房順序切換 sortBySells(){ var newArr = this.boxOffice.concat() if(this.isSort){ return newArr.sort((b1,b2) => b1.sells - b2.sells) }else{ return this.boxOffice } }, //... }
<h3>票房</h3> <ul> <!-- 測試基本功能 --> <!-- <li v-for="(bo,index) of boxOffice"> --> <!-- 測試特性key --> <li v-for="(bo,index) in sortBySells" class="animate"> {{index+1}}、{{bo.name}} {{bo.year}} ({{bo.sells}}$ ) <ul> <li v-for="(value,key,index) of bo.director">{{index+1}}、{{key}}:{{value}}</li> </ul> </li> </ul>
.animate { display: block; margin-bottom: 10px; color: #fff; background: #2e8b57; border-radius: 3px; -webkit-animation: animate 5s infinite; animation: animate 5s infinite; } @keyframes animate { 0% { width: 350px; } to { width: 600px; } }
當列表從新排列時,動畫沒有中斷從新開始,說明這些<li>
元素沒有被從新渲染,它們被複用了。
如今爲列表加上key
<li v-for="(bo,index) in sortBySells" :key="bo.sells" class="animate">
設置key
後,某些元素的動畫中斷並從新開始,說明元素的確被從新渲染了。咱們設置報價爲key
的值,若是設置index
爲值,列表仍是會被徹底的複用。
在以上key
的使用中已經看到咱們對列表進行的排序是在計算屬性中進行的,這種方法的形式通常爲這樣:v-for="項 in 計算屬性"
雖然處理列表首選計算屬性,但也可使用方法,特別是在計算屬性不適用的狀況下。v-for="項 in 方法(參數)"
改寫以上示例,使用方法對列表進行排序,只爲演示,最優仍是使用計算屬性
methods: { //點擊按鈕,在原順序與票房順序切換 sort(isSort) { var newArr = this.boxOffice.concat() return isSort ? newArr.sort((b1, b2) => b1.sells - b2.sells) : this.boxOffice } }
<li v-for="(bo,index) in sort(isSort)" :key="bo.sells" class="animate">
效果與使用計算屬性同樣。
變異方法和非變異方法:以上對列表使用了sort()
方法,這個方法會改變原始數組,因此咱們用concat()
複製出一份,不改變原數據。這裏sort()
爲變異方法,concat()
爲非變異方法。
filter()
是一個非變異方法,好比咱們過濾出2010年前的票房大於10億的電影
computed: { //... //2010以前票房大於10億的電影,調用兩個方法 filterBoxOffice() { return this.highSells(this.beforeYear(this.boxOffice)) }, //... }, methods: { //... beforeYear(list) { return list.filter(bo => bo.year <= 2010) }, highSells(list) { return list.filter(bo => bo.sells <= 10.0) }, }
<ul> <li v-for="bo in beforeYear(highSells(boxOffice))"> <!-- <li v-for="bo in filterBoxOffice"> --> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul>
如上,可使用一個計算屬性返回過濾結果,也能夠直接連續調用兩個方法。
又好比,咱們根據文本輸入來進行過濾。
<h3>過濾</h3> <input type="text" v-model="query" /> <ul> <li v-for="bo in queryBo"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul>
因爲在filter()
裏不能使用this
引用 vue 實例,所以在外部先把它賦給變量 vm
queryBo() { var vm = this var noblank = this.boxOffice.filter(item => Number(vm.query) === item.year) return this.query ? noblank : this.boxOffice }
如下兩種情形的數據變化,vue沒法再視圖中做出響應
當你利用索引直接設置一個項時,例如:vm.items[indexOfItem] = newValue
當你修改數組的長度時,例如:vm.items.length = newLength
如添加如下代碼,點擊按鈕修改
modifyItem(){ this.boxOffice[0] = { name: 'The Last Jedi', year: 201 ![clipboard.png](/img/bV8201) 7, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' } } this.boxOffice.length = 5 }
<button @click="modifyItem" style="margin-left:20px">vue.set test</button>
沒有任何響應,但事實上值已經更新,
不過設置某索引對應對象的屬性,時會有響應的
modifyItem(){ //無響應 this.boxOffice[0] = { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' } } this.boxOffice.length = 5 //有響應 this.boxOffice[1].name = 'somename' }
索引值和長度的改變是由於其餘改變(this.boxOffice[1].name = 'somename')觸發了響應,而並不是他們自身是響應式的。
爲了解決這個問題提供了兩種:使用變異方法splice()
和Vue.set
//設置 modifyItem(){ //無響應 // this.boxOffice[0] = { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' } } // this.boxOffice.length = 5 //無響應的解決方法 // this.$set 等價於 Vue.set Vue.set(this.boxOffice, 0, { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' }}) // this.boxOffice.splice(0, 1, { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' }}) //修改長度 this.boxOffice.splice(5) //有響應 // this.boxOffice[1].name = 'somename' }
此時,點擊按鈕設置新狀態,馬上做出響應。
對於對象而言,屬性的添加或刪除沒法響應,如
//添加對象屬性 modifyObject(){ this.boxOffice[0].director.sex = 'male' }
可使用Vue.set
解決這個問題
或者將對象原先屬性和新增屬性合併成新對象再賦給該對象,這使咱們能夠添加多個屬性,如:
//methods //添加對象屬性 modifyObject(){ // 無響應 // this.boxOffice[0].director.sex = 'male' //解決方法 Vue.set(this.boxOffice[0].director, 'sex', 'male') this.boxOffice[0].director = Object.assign({}, this.boxOffice[0].director,{ aliasname:'kanzaki urumi', graduation: 'NUIST' }) }
同 v-if,包裹多個元素,下節有使用到。
v-for 的優先級比 v-if 高。就是說能夠向下面這樣,先展開全部列表項,以後 v-if 將做用於每一個列表項。
爲影片添加是否上映屬性run
boxOffice: [ { name: 'Avatar', year: 2009, sells: '27.88',run:true, director: { firstname: 'yannie', lastname: 'cheung', age: '17' } }, { name: 'Frozen', year: 2013, sells: '12.765',run:false }, { name: 'Furious 7', year: 2015, sells: '15.15',run:true }, { name: 'Iron Man 3', year: 2013, sells: '12.154',run:false }, { name: 'Titanic', year: 1997, sells: '21.868',run:false }, { name: 'Spectre', year: 2015, sells: '8.722',run:true }, { name: 'Inception', year: 2010, sells: '8.255',run:false }, { name: 'Jurassic World', year: 2015, sells: '16.99',run:false } ]
<h3>v-for|if 的優先級</h3> <ul> <li v-for="bo in boxOffice" v-if="bo.run"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul> v>
若是想設置在某條件下循環是否執行,那麼能夠在外層加上 v-if
<h3>v-for|if 的優先級</h3> <ul> <template v-if="boxOffice.length"> <li v-for="bo in boxOffice" v-if="bo.run"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </template> <li v-else>沒有影片</li> </ul>
和在原生元素上使用同樣,只是必須使用 key
new Vue({ data: { boxOffice: [ { id:1,name: 'Avatar', year: 2009, sells: '27.88', run: true, director: { firstname: 'yannie', lastname: 'cheung', age: '17' } }, { id:2,name: 'Frozen', year: 2013, sells: '12.765', run: false }, { id:3,name: 'Furious 7', year: 2015, sells: '15.15', run: true }, { id:4,name: 'Iron Man 3', year: 2013, sells: '12.154', run: false }, { id:5,name: 'Titanic', year: 1997, sells: '21.868', run: false }, { id:6,name: 'Spectre', year: 2015, sells: '8.722', run: true }, { id:7,name: 'Inception', year: 2010, sells: '8.255', run: false }, { id:8,name: 'Jurassic World', year: 2015, sells: '16.99', run: false } ] }, components: { 'child': { props:['bo'], template: '<li>{{bo.id}}、{{bo.name}}</li>' } } }).$mount('#app-5')
<div id="app-5"> <child v-for="bo in boxOffice" :bo="bo" :key="bo.id"></child> </div>
更多內容參見組件與單文件組件部分