原生渲染指令

代碼javascript

原生html渲染v-html

有時數據中攜帶了Html標籤,輸出它們時,按文本解析,如:css

new Vue({
    data: {
        title:'<h3>使用<code>v-html</code>輸出原生的html</h3>',
    }
}).$mount('#app-1')
<div id="app-1" >
    <div>{{title}}</div>
</div>

clipboard.png

使用原生指令v-html解析數據中標籤爲原生htmlhtml

<div id="app-1" >
    <div v-html="title"></div>
</div>

clipboard.png

你的站點上動態渲染的任意 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>

clipboard.png

使用時要注意這種狀況。插入<script>幾乎能夠作任何事情,還有插入無數<img>佔用帶寬。java

條件渲染v-if、v-show

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-elsev-else-if做分支,注意前後順序,順序錯誤則無效。app

<div v-else style="font-size:30px;color:orange;background: lightblue;width:300px">
    ? it's day
</div>

<template>

上面都在外包元素<div>上使用條件指令,若是不想使用可見元素包裹內容,可使用<template>標籤測試

<template v-if="isNight">
    <span>?</span>
    <span>it's night</span>
</template>

相似其餘語言{}的做用

if(isNight){
    //...
}

key

以上,若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>

clipboard.png

inputlabel倆元素自己沒有被替換,所以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>

clipboard.png

設置key後,切換內容時input的值不在保留。key主要在v-for裏使用,以區分列表項,還有動畫部分會大量使用,由於元素複用致使淡入淡出動畫失效。

列表渲染 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' }
        ]
    }
})

clipboard.png

以上的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>

clipboard.png

在列表遍歷中還能夠引用列表索引,對象的遍歷中引用鍵值與索引,索引從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>

clipboard.png

在遍歷對象時,是按 Object.keys() 的結果遍歷,可是不能保證它的結果在不一樣的 JavaScript 引擎下是一致的。

v-for中的key

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;
    }
}

clipboard.png

當列表從新排列時,動畫沒有中斷從新開始,說明這些<li>元素沒有被從新渲染,它們被複用了。

如今爲列表加上key

<li v-for="(bo,index) in sortBySells" :key="bo.sells" class="animate">

clipboard.png

設置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>

clipboard.png

如上,可使用一個計算屬性返回過濾結果,也能夠直接連續調用兩個方法。

又好比,咱們根據文本輸入來進行過濾。

<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
}

clipboard.png

Vue.set

如下兩種情形的數據變化,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>

clipboard.png

沒有任何響應,但事實上值已經更新,

clipboard.png

不過設置某索引對應對象的屬性,時會有響應的

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'
}

clipboard.png

索引值和長度的改變是由於其餘改變(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'
}

此時,點擊按鈕設置新狀態,馬上做出響應。

clipboard.png

對於對象而言,屬性的添加或刪除沒法響應,如

//添加對象屬性
modifyObject(){
    this.boxOffice[0].director.sex = 'male'
}

可使用Vue.set解決這個問題

clipboard.png

或者將對象原先屬性和新增屬性合併成新對象再賦給該對象,這使咱們能夠添加多個屬性,如:

//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'
    })
}

clipboard.png

template

同 v-if,包裹多個元素,下節有使用到。

v-if、v-for優先級

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>

clipboard.png

若是想設置在某條件下循環是否執行,那麼能夠在外層加上 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>

組件上的v-for

和在原生元素上使用同樣,只是必須使用 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>

更多內容參見組件與單文件組件部分

相關文章
相關標籤/搜索