一,場景
通過使用checkbox,實現如圖的場景, 點擊某個tag,實現選中和非選中狀態。
二, 官網的例子
通過切換checked值為true或者false來實現,一個checkbox的狀態切換
<template> <!-- `checked` 為 true 或 false --> <el-checkbox v-model="checked">備選項</el-checkbox> </template> <script> export default { data() { return { checked: true }; } }; </script>
效果如下:
三, 思考。
通過循環li, 給數據添加checked屬性,並綁定到v-model上,來實現 一的場景。模板代碼如下:
<template> <div class="demo"> <ul> <li v-for="(item, index) in list" :key="index"> //循環li <el-checkbox v-model="item.checked"> //v-model綁定到每個item的checked屬性 {{ item.name }} </el-checkbox> </li> </ul> </div> </template>
后台返回數據格式(已精簡),如下(沒有checked屬性)
[ { id: 1, pid: 1, name: '地區' }, { id: 2, pid: 2, name: '游戲類型' }, { id: 3, pid: 4, name: '性別' }, { id: 4, pid: 5, name: '設備類型' }, { id: 5, pid: 6, name: '休閑時間' }, { id: 6, pid: 7, name: '王者榮耀' }, { id: 7, pid: 8, name: '音樂' }, { id: 8, pid: 9, name: '品牌手表' }, { id: 9, pid: 10, name: '相機' }, { id: 10, pid: 12, name: '游戲人群' }, ]
我要做的, mounted方法獲取后台數據,再給每條數據循環添加checked屬性,初始值為false。
<script> export default { name: 'demo', data() { return { list: [], allTags: [], } }, methods: { getList() {
//獲取數據用settimeout模擬 setTimeout(() => { this.allTags = [ { id: 1, pid: 1, name: '地區' }, { id: 2, pid: 2, name: '游戲類型' }, { id: 3, pid: 4, name: '性別' }, { id: 4, pid: 5, name: '設備類型' }, { id: 5, pid: 6, name: '休閑時間' }, { id: 6, pid: 7, name: '王者榮耀' }, { id: 7, pid: 8, name: '音樂' }, { id: 8, pid: 9, name: '品牌手表' }, { id: 9, pid: 10, name: '相機' }, { id: 10, pid: 12, name: '游戲人群' }, ] this.allTags.map(item => { item.checked = false return item }) this.list = this.allTags }, 1500) }, }, mounted() { this.getList() }, } </script>
到這以為實現了功能,看效果發現問題: 點擊時候,沒有勾上,只有框變了顏色。
排查問題.....
(腦補痛苦過程......)
猜測:
1,element不支持這種方法綁定,只能按官網例子中,循環el-checkbox來實現。
2,vue綁定問題
針對問題1: 換成了循環el-checkbox,發現結果是一樣的不行。 否定!
剩下的就是猜測二:
人為把返回數據默認加上checked屬性, 即data格式為:
[ { id: 1, pid: 1, name: '地區', checked: false}, { id: 2, pid: 2, name: '游戲類型' , checked: false}, { id: 3, pid: 4, name: '性別' , checked: false}, { id: 4, pid: 5, name: '設備類型' , checked: false}, { id: 5, pid: 6, name: '休閑時間' , checked: false}, { id: 6, pid: 7, name: '王者榮耀', checked: false }, { id: 7, pid: 8, name: '音樂', checked: false }, { id: 8, pid: 9, name: '品牌手表' , checked: false}, { id: 9, pid: 10, name: '相機' , checked: false}, { id: 10, pid: 12, name: '游戲人群' , checked: false}, ]
測試發現,這樣可以。
迷茫。。。
然后在控制台打印數據,對比了一下結果。
前端添加checked屬性的情況 和 后台返回數據本來就有checked屬性情況 打印出來分別如 1 和 圖2
圖1 圖2
對比一下發現,前端添加checked屬性, vue並沒有添加get set方法,因此,監聽不到checked值變化,進而不能更新view。這點,可以在瀏覽器vue調試中看到,點擊時候 數據的checked屬性 true和false是在交替變化,但是view上沒同步更新。截了個圖
四,解決方法
兩種方法,
1, 拿到值不賦值給data屬性的allTags,而是定義臨時變量let, 操作完之后,賦值給list,即:
<script> export default { name: 'demo', data() { return { list: [], } }, methods: { getList() { //獲取數據用settimeout模擬 setTimeout(() => { let allTags = [ //這里let定義allTags { id: 1, pid: 1, name: '地區' }, { id: 2, pid: 2, name: '游戲類型' }, { id: 3, pid: 4, name: '性別' }, { id: 4, pid: 5, name: '設備類型' }, { id: 5, pid: 6, name: '休閑時間' }, { id: 6, pid: 7, name: '王者榮耀' }, { id: 7, pid: 8, name: '音樂' }, { id: 8, pid: 9, name: '品牌手表' }, { id: 9, pid: 10, name: '相機' }, { id: 10, pid: 12, name: '游戲人群' }, ] allTags.map(item => { item.checked = false return item }) this.list = allTags }, 1500) }, }, mounted() { this.getList() }, } </script>
2(推薦),用vue.$set方法,強制vue監聽checked屬性
<script> export default { name: 'demo', data() { return { list: [], } }, methods: { getList() { //獲取數據用settimeout模擬 setTimeout(() => { this.allTags = [ //這里let定義allTags { id: 1, pid: 1, name: '地區' }, { id: 2, pid: 2, name: '游戲類型' }, { id: 3, pid: 4, name: '性別' }, { id: 4, pid: 5, name: '設備類型' }, { id: 5, pid: 6, name: '休閑時間' }, { id: 6, pid: 7, name: '王者榮耀' }, { id: 7, pid: 8, name: '音樂' }, { id: 8, pid: 9, name: '品牌手表' }, { id: 9, pid: 10, name: '相機' }, { id: 10, pid: 12, name: '游戲人群' }, ] this.allTags.map(item => { //item.checked = false this.$set(item, 'checked', false) // 這里,給對象添加屬性,用$set方法。 return item }) this.list = this.allTags }, 1500) }, }, mounted() { this.getList() }, } </script>
done!!
五,總結。
這個問題是我在項目中遇到的問題,通過一步一步鎖定問題之后,抽出來做了最精簡版本,故做此總結,也給其他遇到坑的童鞋一點點幫助。
ps,每次用element ui 都會有一些感觸,苦笑。