iT邦幫忙

3

[筆記][Vue.js]打開Vue.js世界的大門(3)-既然長得差不多,就用迴圈吧!

終於輪到迴圈了(其實也才剛開始三篇而已XD)!說到迴圈大家一定不陌生,除了最初的起點Hello!world!以外,應該就是九九乘法表了,那當迴圈融入前端框架時,會迸出什麼火花,讓我們來看看吧!


迴圈

一、for的使用方法

在上一篇文章中大家都知道Vue.js中的if寫作v-if,那for呢?

v-for嗎?

沒錯!就是v-for!直接來看用法吧:

<div id="todoList">
    <div v-for="list in lists">
        {{list.item}}
    </div>
</div>

JavaScript

let listData = {
    //lists屬性中存著陣列
    lists:[
        //陣列中擁有多個相同key的物件
        {item:'學Vue.js'},
        {item:'學React'},
        {item:'學Angular2'}
    ]
}

let todoList = new Vue({
    el:'#todoList',
    data:listData,
})

這一次從JavaScript的部分先說,首先像平常一樣定義一個listData物件,可以看到裡面有一個紀錄陣列的lists,陣列裡面的內容則是一個個擁有相同key的物件,差別是值不一樣,而我們new的Vue物件抓取外層的div,讓該div的內容都可以綁定listData的資料。

好的,那再來是HTML的部分,我們把v-for寫在內層,裡面的值是list in lists這裡的語法和JavaScript一樣,v-for會將lists也就是listData中的陣列資料一個一個讀取並把值放進list中,再往更裡面看一點,內層的div目前綁定的資料是list.item也就是lists中每一個物件的item值,所以設定了v-fordiv會被迴圈重覆輸出,唯一會變的只有{{list.item}}的值而已,來看看綁定後的結果吧!
https://ithelp.ithome.com.tw/upload/images/20180816/20106935Y6FQBJjzBn.jpg
登愣!原本只有一個的div也變成了三個,而且裡面的值也都被綁定item了!

當然,只要是在data中的資料,就算沒在lists裡也可以綁定,而且很貼心的是,v-for還可以有第二個參數,來紀錄目前是陣列中的第幾項:
HTML

<div id="todoList">
    <!--在這裡增加了第二個參數index,記得兩個參數以上要用括號-->
    <div v-for="(list,index) in lists">
        {{index}}.{{titleText}} - {{list.item}}
    </div>
</div>

JavaScript

//增加一個titleText屬性
let listData = {
    titleText:'要做的事情',
    lists:[
      {item:'學Vue.js'},
      {item:'學React'},
      {item:'學Angular2'}
    ]
}

HTML中為v-for增加了第二個參數,他會記錄著目前是陣列中的第幾個索引,記得索引值都是從0開始哦!除此之外我也在JavaScript中的listData增加了一的屬性titleText,執行他吧!
https://ithelp.ithome.com.tw/upload/images/20180816/20106935byyW1VO3rx.jpg
內容就分別是索引的index加上listDatatitleText還有listsitem,這邊特別的是字串的組合不需要使用加號,不過說不定其他前端框架也是這樣,因為小弟碰過的框架目前只有Vue.js,所以可以請板上大大們留言分享一下XD,那我們繼續下去吧!

二、免不了提一下效能問題吧

其實v-forv-if會遇到的問題一樣,沒辦法本是同根身,總會有些習慣相同,就是為了效能,v-for會在我們調整lists順序的時候只對不同的地方做替換而已,我們把今天學到的v-for用法加進昨天的例子裡來看這個狀況:
HTML

<div id="formList">
    <div v-for="list in lists">
        {{titleText}}{{list.item}}:
        <!--用第一天學到的v-bind綁定placeholder屬性為list.item的值-->
        <input :placeholder="list.item">
    </div>
    <!--昨天是切換輸入,今天是反轉陣列-->
    <input type="button" value="反轉陣列" @click="changeSort">
</div>

JavaScript

let listData = {
    titleText:'請輸入',
    lists:[
      {item:'姓名'},
      {item:'信箱'},
      {item:'電話'}
    ]
}
let listMethods = {
    changeSort: () => {
        //反轉陣列
        listData.lists.reverse()
    }
}
let formList = new Vue({
    el:'#formList',
    data:listData,
    methods:listMethods,
})

Vue.js處理過的畫面會如下:
https://ithelp.ithome.com.tw/upload/images/20180816/20106935i2rdNGNZ8x.jpg
看起來也滿像樣的,對吧?不過這不是重點,讓我們來看看以下操作:
https://ithelp.ithome.com.tw/upload/images/20180816/20106935b2OVVP6mrN.jpg
我先在第一個input輸入姓名,之後反轉陣列lists中的元素,Vue.js的動態綁定資料會迅速的刷新畫面,原本第一個的姓名跑到最後一個,電話跑到第一個,但是有沒有一個強烈的既視感,那就是inputvalue值還在啊!因為Vue.js不會重新繪製,而是只刷新了原本input不同的地方,也就是placeholder。好的,既然問題發生了,還是得解決,想想昨天v-if的處理方式,怎麼辦呢?

設定key嗎?

對!就是他!不過設定方法和昨天稍微有點不同,我們必須用v-bind的方式去綁定key值,像下方這樣:
HTML

<div id="formList">
    <div v-for="list in lists">
        {{titleText}}{{list.item}}:
        <!--增加v-bind設定key值-->
        <input :placeholder="list.item" :key="list.id">
    </div>
    <input type="button" value="反轉陣列" @click="changeSort">
</div>

JavaScript

let listData = {
    titleText:'請輸入',
    //為lists中的各個物件加上id
    lists:[
      {id:'name',item:'姓名'},
      {id:'mail',item:'信箱'},
      {id:'tel',item:'電話'}
    ]
}

HTML的部分就像上面說的,用v-bind綁定一個key屬性,他的值是list.id,所以在JavaScipt中要記得在listData中的lists中的物件加入id的資料,加上key值的他們,如果重新綁定就會進行重新繪製了!
https://ithelp.ithome.com.tw/upload/images/20180816/20106935s1C6tGYEp1.jpg
然而因為重新繪製的關係,所以一反轉陣列內容,我們輸入過的value自然就不見啦!而官方文件上面也有說建議大家在使用v-for的時候,除非是有特殊原因需要刻意的讓效能提升,不然都盡量綁定key屬性。

三、陣列的異動方式

以下先用上方加入key的程式碼下去說明,重複的部分就不會再打上去了!

首先是增加的push()

增加項目非常簡單,直接對listData內的listspush(),Vue.js就會幫你處理好剩下的事情!
https://ithelp.ithome.com.tw/upload/images/20180816/20106935fpd7X3DuSI.jpg

再來是移除的splice()

移除和增加一樣,直接對listDatalistssplice()就可以了。
https://ithelp.ithome.com.tw/upload/images/20180816/201069355N3059DmZ4.jpg
這邊我補充一下splice()的用法,上面我用在移除的時候給他兩個參數listData.lists.splice(3,1),因為前一次我在listspush()ageage在陣列中的索引為3,所以就是從第3個索引開始移除掉1個,也就是把age給移除。

循序漸進的替換資料來源

JavaScript有許多操作陣列的function,但並不是所有function都會改變原有的陣列內容,有些是回傳新的陣列,例如官網舉例篩選資料用的filter()、合併兩個陣列的concat()或是截取陣列內容的slice(),怎麼辦?

其實很簡單,非常非常簡單,就把處理後的資料指定回去而已。這邊我以concat()說明,其他兩個方式的做法也一樣。
https://ithelp.ithome.com.tw/upload/images/20180817/201069351WqFvlyI1l.jpg
conosle的第一行我先新增另一個陣列arr1,之後用concat()datalists陣列和arr1做合併,但是concat()不會異動原本的lists,所以我在同時也把他指定回去。

最後的注意事項

  1. 當想要調整lists中第二個索引的值時,千千萬萬別這麼做listData.lists[2] = {id:'test',item:'測試'},這樣會讓Vue.js無法動態刷新畫面,解套方法當然是有,可以改成Vue.set(list, index, value)讓Vue.js刷新,以下範例:
    https://ithelp.ithome.com.tw/upload/images/20180817/20106935QKd1GEhvsZ.jpg
    小補充一下,上圖中的語法也可以用Vue.js的全域方法$set寫成這樣:formList.$set(listData.lists, 2, {id:'test',item:'測試'})
  2. 透過設定陣列長度減少元素listData.lists.length = 2,也不會被Vue.js抓到哦!如果要移除元素,請使用上面提到的splice()來做處理。

剛剛打完文章,順手看了一下Vue.js官方文件的目錄,突然覺得未來的路還好長XD,不過相信It這條路不孤單,大家都會一起走下去的對吧!哈哈哈。

最後感謝各位大大的觀看,如果文章中有任何錯誤或是講解不清楚的部分,還請留言告訴我,我會盡快修正!謝謝大家/images/emoticon/emoticon41.gif


尚未有邦友留言

立即登入留言