1.前言
用vue做專案也有一段時間了,之前也是寫過關於vue和webpack構建專案的相關文章,大家有興趣可以去看下webpack+vue專案實戰(一,搭建執行環境和相關配置)(這個系列一共有5篇文章,這是第一篇,其它幾篇文章連結就不貼了)。但是關於vue入門基礎的文章,我還沒有寫過,那麼今天就寫vue入門的三個小例項,這三個小例項是我剛接觸vue的時候的練手作品,難度從很簡單到簡單,都是入門級的。希望能幫到大家更好的學習和了解vue,也是讓自己能夠複習一下vue。如果發現文章寫得有什麼不好,寫錯了,或者有什麼建議!歡迎大家指點迷津!
1.本篇文章使用的vue版本是
2.4.2
,大家要注意版本問題
2.現在我也是假設您有基礎的html,css,javascript的知識,也已經看過了官網的基本介紹,對vue有了一個大概的認識了,瞭解了常用的vue指令(v-model,v-show,v-if,v-for,v-on,v-bind等)!如果剛接觸前端的話,你看著文章可能會蒙圈,建議先學習基礎,掌握了基礎知識再來看!
3.下面的例項,建議大家邊看文章邊動手做!這樣思路會非常清晰,不易混亂!也不會覺得文章長!如果只看文章,你可能未必會看完,因為文章我講得比較細,比較長!
2.什麼是vue
vue是現在很火的一個前端MVVM框架,它以資料驅動和元件化的思想構建,與angular和react並稱前端三大框架。相比angular和react,vue更加輕巧、高效能、也很容易上手。大家也可以移步,看一下vue的介紹和核心功能官網介紹。簡單粗暴的理解就是:用vue開發的時候,就是運算元據,然後vue就會處理,以資料驅動去改變DOM(不知道有沒有理解錯,理解錯了指點下)。
下面就是一個最簡單的說明例子
程式碼如下
1 2 3 4 |
<div id="app"> <p>{{ message }}</p> <input v-model="message"> </div> |
js
1 2 3 4 5 6 |
new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) |
栗子
相信也不難理解,就是input
繫結了message
這個值,然後在input
修改的時候,message
就改了,由於雙向繫結,同時頁面的html({{ message }}
)進行了修改!
好,下面進入例子學習!
3.選項卡
執行效果
原理分析和實現
這個很簡單,無非就是一個點選切換顯示而已。但是大家也要實現。如果這個看明白了,再看下面兩個!這個例項應該只是一個熱身和熟悉的作用!
這個的步驟只有一步,原理也沒什麼。我直接在程式碼打註釋,看了註釋,大家就明白了!
完整程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <style> body{ font-family:"Microsoft YaHei"; } #tab{ width: 600px; margin: 0 auto; } .tab-tit{ font-size: 0; width: 600px; } .tab-tit a{ display: inline-block; height: 40px; line-height: 40px; font-size: 16px; width: 25%; text-align: center; background: #ccc; color: #333; text-decoration: none; } .tab-tit .cur{ background: #09f; color: #fff; } .tab-con div{ border: 1px solid #ccc; height: 400px; padding-top: 20px; } </style> <body> <div id="tab"> <div class="tab-tit"> <!--點選設定curId的值 如果curId等於0,第一個a新增cur類名,如果curId等於1,第二個a新增cur類名,以此類推。新增了cur類名,a就會改變樣式 @click,:class ,v-show這三個是vue常用的指令或新增事件的方式--> <a href="javascript:;" @click="curId=0" :class="{'cur':curId===0}">html</a> <a href="javascript:;" @click="curId=1" :class="{'cur':curId===1}">css</a> <a href="javascript:;" @click="curId=2" :class="{'cur':curId===2}">javascript</a> <a href="javascript:;" @click="curId=3" :class="{'cur':curId===3}">vue</a> </div> <div class="tab-con"> <!--根據curId的值顯示div,如果curId等於0,第一個div顯示,其它三個div不顯示。如果curId等於1,第二個div顯示,其它三個div不顯示。以此類推--> <div v-show="curId===0"> html<br/> </div> <div v-show="curId===1"> css </div> <div v-show="curId===2"> javascript </div> <div v-show="curId===3"> vue </div> </div> </div> </body> <script src="vue.min.js"></script> <script> new Vue({ el: '#tab', data: { curId: 0 }, computed: {}, methods: {}, mounted: function () { } }) </script> </html> |
4.統計總價
執行效果
原理分析和實現
首先,還是先把佈局寫好,和引入vue,準備vue例項,這個不多說,程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .fl{ float: left; } .fr{ float: right; } blockquote, body, dd, div, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, img, input, li, ol, p, table, td, textarea, th, ul { margin: 0; padding: 0; } .clearfix{ zoom: 1; } .clearfix:after { clear: both; } .clearfix:after { content: '.'; display: block; overflow: hidden; visibility: hidden; font-size: 0; line-height: 0; width: 0; height: 0; } a{ text-decoration: none; color: #333; } img{vertical-align: middle;} .page-shopping-cart { width: 1200px; margin: 50px auto; font-size: 14px; border: 1px solid #e3e3e3; border-top: 2px solid #317ee7; } .page-shopping-cart .cart-title { color: #317ee7; font-size: 16px; text-align: left; padding-left: 20px; line-height: 68px; } .page-shopping-cart .red-text { color: #e94826; } .page-shopping-cart .check-span { display: block; width: 24px; height: 20px; background: url("shopping_cart.png") no-repeat 0 0; } .page-shopping-cart .check-span.check-true { background: url("shopping_cart.png") no-repeat 0 -22px; } .page-shopping-cart .td-check { width: 70px; } .page-shopping-cart .td-product { width: 460px; } .page-shopping-cart .td-num, .page-shopping-cart .td-price, .page-shopping-cart .td-total { width: 160px; } .page-shopping-cart .td-do { width: 150px; } .page-shopping-cart .cart-product-title { text-align: center; height: 38px; line-height: 38px; padding: 0 20px; background: #f7f7f7; border-top: 1px solid #e3e3e3; border-bottom: 1px solid #e3e3e3; } .page-shopping-cart .cart-product-title .td-product { text-align: center; font-size: 14px; } .page-shopping-cart .cart-product-title .td-check { text-align: left; } .page-shopping-cart .cart-product-title .td-check .check-span { margin: 9px 6px 0 0; } .page-shopping-cart .cart-product { padding: 0 20px; text-align: center; } .page-shopping-cart .cart-product table { width: 100%; text-align: center; font-size: 14px; } .page-shopping-cart .cart-product table td { padding: 20px 0; } .page-shopping-cart .cart-product table tr { border-bottom: 1px dashed #e3e3e3; } .page-shopping-cart .cart-product table tr:last-child { border-bottom: none; } .page-shopping-cart .cart-product table .product-num { border: 1px solid #e3e3e3; display: inline-block; text-align: center; } .page-shopping-cart .cart-product table .product-num .num-do { width: 24px; height: 28px; display: block; background: #f7f7f7; } .page-shopping-cart .cart-product table .product-num .num-reduce span { background: url("shopping_cart.png") no-repeat -40px -22px; display: block; width: 6px; height: 2px; margin: 13px auto 0 auto; } .page-shopping-cart .cart-product table .product-num .num-add span { background: url("shopping_cart.png") no-repeat -60px -22px; display: block; width: 8px; height: 8px; margin: 10px auto 0 auto; } .page-shopping-cart .cart-product table .product-num .num-input { width: 42px; height: 28px; line-height: 28px; border: none; text-align: center; } .page-shopping-cart .cart-product table .td-product { text-align: left; font-size: 12px; line-height: 20px; } .page-shopping-cart .cart-product table .td-product img { border: 1px solid #e3e3e3; margin-right: 10px; } .page-shopping-cart .cart-product table .td-product .product-info { display: inline-block; vertical-align: middle; } .page-shopping-cart .cart-product table .td-do { font-size: 12px; } .page-shopping-cart .cart-product-info { height: 50px; line-height: 50px; background: #f7f7f7; padding-left: 20px; } .page-shopping-cart .cart-product-info .delect-product { color: #666; } .page-shopping-cart .cart-product-info .delect-product span { display: inline-block; vertical-align: top; margin: 18px 8px 0 0; width: 13px; height: 15px; background: url("shopping_cart.png") no-repeat -60px 0; } .page-shopping-cart .cart-product-info .product-total { font-size: 14px; color: #e94826; } .page-shopping-cart .cart-product-info .product-total span { font-size: 20px; } .page-shopping-cart .cart-product-info .check-num { color: #333; } .page-shopping-cart .cart-product-info .check-num span { color: #e94826; } .page-shopping-cart .cart-product-info .keep-shopping { color: #666; margin-left: 40px; } .page-shopping-cart .cart-product-info .keep-shopping span { display: inline-block; vertical-align: top; margin: 18px 8px 0 0; width: 15px; height: 15px; background: url("shopping_cart.png") no-repeat -40px 0; } .page-shopping-cart .cart-product-info .btn-buy { height: 50px; color: #fff; font-size: 20px; display: block; width: 110px; background: #ff7700; text-align: center; margin-left: 30px; } .page-shopping-cart .cart-worder { padding: 20px; } .page-shopping-cart .cart-worder .choose-worder { color: #fff; display: block; background: #39e; width: 140px; height: 40px; line-height: 40px; border-radius: 4px; text-align: center; margin-right: 20px; } .page-shopping-cart .cart-worder .choose-worder span { display: inline-block; vertical-align: top; margin: 9px 10px 0 0; width: 22px; height: 22px; background: url("shopping_cart.png") no-repeat -92px 0; } .page-shopping-cart .cart-worder .worker-info { color: #666; } .page-shopping-cart .cart-worder .worker-info img { border-radius: 100%; margin-right: 10px; } .page-shopping-cart .cart-worder .worker-info span { color: #000; } .choose-worker-box { width: 620px; background: #fff; } .choose-worker-box .box-title { height: 40px; line-height: 40px; background: #F7F7F7; text-align: center; position: relative; font-size: 14px; } .choose-worker-box .box-title a { display: block; position: absolute; top: 15px; right: 16px; width: 10px; height: 10px; background: url("shopping_cart.png") no-repeat -80px 0; } .choose-worker-box .box-title a:hover { background: url("shopping_cart.png") no-repeat -80px -22px; } .choose-worker-box .worker-list { padding-top: 30px; height: 134px; overflow-y: auto; } .choose-worker-box .worker-list li { float: left; width: 25%; text-align: center; margin-bottom: 30px; } .choose-worker-box .worker-list li p { margin-top: 8px; } .choose-worker-box .worker-list li.cur a { color: #f70; } .choose-worker-box .worker-list li.cur a img { border: 1px solid #f70; } .choose-worker-box .worker-list li a:hover { color: #f70; } .choose-worker-box .worker-list li a:hover img { border: 1px solid #f70; } .choose-worker-box .worker-list li img { border: 1px solid #fff; border-radius: 100%; } </style> </head> <body> <div class="page-shopping-cart" id="shopping-cart"> <h4 class="cart-title">購物清單</h4> <div class="cart-product-title clearfix"> <div class="td-check fl"><span class="check-span fl check-all"></span>全選</div> <div class="td-product fl">商品</div> <div class="td-num fl">數量</div> <div class="td-price fl">單價(元)</div> <div class="td-total fl">金額(元)</div> <div class="td-do fl">操作</div> </div> <div class="cart-product clearfix"> <table> <tbody><tr> <td class="td-check"><span class="check-span"></span></td> <td class="td-product"><img src="testimg.jpg" width="98" height="98"> <div class="product-info"> <h6>【斯文】甘油 | 丙三醇</h6> <p>品牌:韓國skc 產地:韓國</p> <p>規格/純度:99.7% 起定量:215千克</p> <p>配送倉儲:上海倉海倉儲</p> </div> <div class="clearfix"></div> </td> <td class="td-num"> <div class="product-num"> <a href="javascript:;" class="num-reduce num-do fl"><span></span></a> <input type="text" class="num-input" value="3"> <a href="javascript:;" class="num-add num-do fr"><span></span></a> </div> </td> <td class="td-price"> <p class="red-text">¥<span class="price-text">800</span>.00</p> </td> <td class="td-total"> <p class="red-text">¥<span class="total-text">800</span>.00</p> </td> <td class="td-do"><a href="javascript:;" class="product-delect">刪除</a></td> </tr> <tr> <td class="td-check"><span class="check-span check-true"></span></td> <td class="td-product"><img src="testimg.jpg" width="98" height="98"> <div class="product-info"> <h6>【斯文】甘油 | 丙三醇</h6> <p>品牌:韓國skc 產地:韓國</p> <p>規格/純度:99.7% 起定量:215千克</p> <p>配送倉儲:上海倉海倉儲</p> </div> <div class="clearfix"></div> </td> <td class="td-num"> <div class="product-num"> <a href="javascript:;" class="num-reduce num-do fl"><span></span></a> <input type="text" class="num-input" value="1"> <a href="javascript:;" class="num-add num-do fr"><span></span></a> </div> </td> <td class="td-price"> <p class="red-text">¥<span class="price-text">800</span>.00</p> </td> <td class="td-total"> <p class="red-text">¥<span class="total-text">800</span>.00</p> </td> <td class="td-do"><a href="javascript:;" class="product-delect">刪除</a></td> </tr> </tbody></table> </div> <div class="cart-product-info"> <a class="delect-product" href="javascript:;"><span></span>刪除所選商品</a> <a class="keep-shopping" href="#"><span></span>繼續購物</a> <a class="btn-buy fr" href="javascript:;">去結算</a> <p class="fr product-total">¥<span>1600</span></p> <p class="fr check-num"><span>2</span>件商品總計(不含運費):</p> </div> <div class="cart-worder clearfix"> <a href="javascript:;" class="choose-worder fl"><span></span>繫結跟單員</a> <div class="worker-info fl"> </div> </div> </div> </body> <script src="vue.min.js"></script> <script> new Vue({ el:'#shopping-cart', data:{ }, computed: {}, methods:{ } }) </script> </html> |
然後準備下列表資料,根據下面表格的箭頭
所以大家就知道嗎,下面的資料大概是漲這樣
1 2 3 4 5 6 7 8 9 10 11 12 13 |
productList:[ { 'pro_name': '【斯文】甘油 | 丙三醇',//產品名稱 'pro_brand': 'skc',//品牌名稱 'pro_place': '韓國',//產地 'pro_purity': '99.7%',//規格 'pro_min': "215千克",//最小起訂量 'pro_depot': '上海倉海倉儲',//所在倉庫 'pro_num': 3,//數量 'pro_img': '../../images/ucenter/testimg.jpg',//圖片連結 'pro_price': 800//單價 } ] |
準備了這麼多,大家可能想到,還缺少一個,就是記錄產品是否有選中,但是這個欄位,雖然可以在上面那裡加,但是意義不大,比如在平常專案那裡!後臺的資料不會這樣返回,資料庫也不會有這個欄位,這個欄位應該是自己新增的。程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
new Vue({ el:'#shopping-cart', data:{ productList:[ { 'pro_name': '【斯文】甘油 | 丙三醇',//產品名稱 'pro_brand': 'skc',//品牌名稱 'pro_place': '韓國',//產地 'pro_purity': '99.7%',//規格 'pro_min': "215千克",//最小起訂量 'pro_depot': '上海倉海倉儲',//所在倉庫 'pro_num': 3,//數量 'pro_img': '../../images/ucenter/testimg.jpg',//圖片連結 'pro_price': 800//單價 } ] }, computed: {}, methods:{ }, mounted:function () { //為productList新增select(是否選中)欄位,初始值為true this.productList.map(function(item){item.select=true;console.log(item)}) } }) |
步驟1
為了著重表示我修改了什麼地方,程式碼我現在只貼出修改的部分,大家對著上面的佈局,就很容易知道我改的是什麼地方了!下面也是這樣操作!
點選增加和減少按鈕(箭頭指向地方),所屬列的金額改變(紅框地方)
執行步驟1之前,要先把列表的資料給鋪出來。利用v-for指令。程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<tr v-for="item in productList"> <td class="td-check"><span class="check-span"></span></td> <td class="td-product"><img :src="item.pro_img" width="98" height="98"> <div class="product-info"> <h6>{{item.pro_name}}</h6> <p>品牌:{{item.pro_brand}} 產地:{{item.pro_place}}</p> <p>規格/純度:{{item.pro_purity}} 起定量:{{item.pro_min}}</p> <p>配送倉儲:{{item.pro_depot}}</p> </div> <div class="clearfix"></div> </td> <td class="td-num"> <div class="product-num"> <a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num--"><span></span></a> <input type="text" class="num-input" v-model="item.pro_num"> <a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a> </div> </td> <td class="td-price"> <p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p> </td> <td class="td-total"> <p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p> </td> <td class="td-do"><a href="javascript:;" class="product-delect">刪除</a></td> </tr> |
這樣,列表的資料就有了!
也可以發現,這兩個按鈕的功能已經實現了,後面的金額也會發生變化!是不是感到很驚喜!其實這裡沒什麼特別的,就是因為輸入框利用v-model繫結了數量(pro_num
),然後兩個按鈕分別新增了事件@click="item.pro_num--"
和@click="item.pro_num++"
。比如剛開始pro_num是3,點選,pro_num
就變成2,點選
,pro_num
就變成4,然後後面的金額會改改,是因為{{item.pro_price*item.pro_num}}
。只要pro_price或者pro_num的值改變了,整一塊也會改變,檢視就會重新整理,我們就能看到變化(這些事情是vue做的,這就是MVVM的魅力,資料驅動檢視改變)。
步驟2
點選所屬列選擇按鈕(箭頭指向地方),總計的金額(紅框地方)和已選產品的列數(藍框地方)和全選(黃框地方)會改變(如果已經全選了,全選按鈕自動變成全選,如果沒有全選,全選按鈕,自動取消全選)!
首先,選擇與取消選擇,在這裡只有兩個操作(其實只有一個:改變這條記錄的select
欄位)。
然後改變,如果這條記錄select
為false
,就顯示,否則就顯示。
程式碼如下
1 |
<td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td> |
其實就是等於新增了@click="item.select=!item.select" :class="{'check-true':item.select}"
這裡。點選這個,這條資料的select
欄位就取反(true->false或者false->true)。然後:class="{'check-true':item.select}"
,就會根據這條資料的select
欄位進行判斷,是否新增check-true
類名,如果select
欄位為true,就新增類名,顯示。否則不新增類名,顯示
。
然後,全選按鈕,是否變成。這裡用一個computed(計算屬性)就好。程式碼如下
1 |
<div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}"></span>全選</div> |
js
1 2 3 4 5 6 |
computed: { isSelectAll:function(){ //如果productList中每一條資料的select都為true,返回true,否則返回false; return this.productList.every(function (val) { return val.select}); } } |
程式碼我解釋下,就是計算屬性中,定義的isSelectAll依賴productList。只要productList改變,isSelectAll的返回值就會改變,然後:class="{'check-true':isSelectAll}"
根絕isSelectAll返回值是否新增'check-true'
類名,顯示對應的樣式!
最後,,這裡的多少件產品和總價,也是使用計算屬性,有了上一步的基礎,給出程式碼,大家一看就明白了!
html
1 2 |
<p class="fr product-total">¥<span>{{getTotal.totalPrice}}</span></p> <p class="fr check-num"><span>{{getTotal.totalNum}}</span>件商品總計(不含運費):</p> |
js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
computed: { //檢測是否全選 isSelectAll:function(){ //如果productList中每一條資料的select都為true,返回true,否則返回false; return this.productList.every(function (val) { return val.select}); }, //獲取總價和產品總件數 getTotal:function(){ //獲取productList中select為true的資料。 var _proList=this.productList.filter(function (val) { return val.select}),totalPrice=0; for(var i=0,len=_proList.length;i<len;i++){ //總價累加 totalPrice+=_proList[i].pro_num*_proList[i].pro_price; } //選擇產品的件數就是_proList.length,總價就是totalPrice return {totalNum:_proList.length,totalPrice:totalPrice} } }, |
程式碼很簡單,html根據getTotal返回值顯示資料,getTotal依賴productList的資料,只要productList改變,返回值會改變,檢視也會改變!
步驟3
點選全選按鈕(箭頭指向部分),會自動的對產品進行全選或者取消全選,下面的總計也會發生改變
做到這一步,大家應該知道,全選或者取消全選,就是改變記錄的select
。但是怎麼知道現在的列表有沒有全選呢?這個很賤,不需要在操作函式(全選與取消全選函式)裡面遍歷,大家應該還記得第二步的計算屬性isSelectAll
(為true就是全選,否則不是全選),把這個傳進操作函式就好,然後操作函式,根據引數,決定執行全選,還是取消全選操作。程式碼如下!
html
1 |
<div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}" @click="selectProduct(isSelectAll)"></span>全選</div> |
js
1 2 3 4 5 6 7 8 9 |
methods: { //全選與取消全選 selectProduct:function(_isSelect){ //遍歷productList,全部取反 for (var i = 0, len = this.productList.length; i < len; i++) { this.productList[i].select = !_isSelect; } } }, |
步驟4
點選刪除產品,會刪除已經選中的,全選按鈕和下面的總計,都會變化!點選每條記錄後面的刪除,會刪除當前的這條記錄。全選按鈕和下面的總計,也都會變化!
首先,點選刪除產品,刪除已經選中。這個大家知道了怎麼做了!就是遍歷productList,如果哪條記錄的select為true,就刪除。
然後,點選每條記錄後面的刪除,刪除當前的這條記錄。這個在html遍歷productList的時候。順便帶上索引,然後把索引當成引數,傳進操作函式,然後根據索引引數,刪除productList的哪一條記錄。即可實現!程式碼如下!
html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<!--遍歷的時候帶上索引--> <tr v-for="(item,index) in productList"> <td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td> <td class="td-product"><img :src="item.pro_img" width="98" height="98"> <div class="product-info"> <h6>{{item.pro_name}}</h6> <p>品牌:{{item.pro_brand}} 產地:{{item.pro_place}}</p> <p>規格/純度:{{item.pro_purity}} 起定量:{{item.pro_min}}</p> <p>配送倉儲:{{item.pro_depot}}</p> </div> <div class="clearfix"></div> </td> <td class="td-num"> <div class="product-num"> <a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num--"><span></span></a> <input type="text" class="num-input" v-model="item.pro_num"> <a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a> </div> </td> <td class="td-price"> <p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p> </td> <td class="td-total"> <p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p> </td> <td class="td-do"><a href="javascript:;" class="product-delect" @click="deleteOneProduct(index)">刪除</a></td> </tr> ... <a class="delect-product" href="javascript:;" @click="deleteProduct"><span></span>刪除所選商品</a><code><!--遍歷的時候帶上索引--> |
js
1 2 3 4 5 6 7 8 9 |
//刪除已經選中(select=true)的產品 deleteProduct:function () { this.productList=this.productList.filter(function (item) {return !item.select}) }, //刪除單條產品 deleteOneProduct:function (index) { //根據索引刪除productList的記錄 this.productList.splice(index,1); }, |
完整程式碼
樣式圖片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .fl { float: left; } .fr { float: right; } blockquote, body, dd, div, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, img, input, li, ol, p, table, td, textarea, th, ul { margin: 0; padding: 0; } .clearfix { zoom: 1; } .clearfix:after { clear: both; } .clearfix:after { content: '.'; display: block; overflow: hidden; visibility: hidden; font-size: 0; line-height: 0; width: 0; height: 0; } a { text-decoration: none; color: #333; } img { vertical-align: middle; } .page-shopping-cart { width: 1200px; margin: 50px auto; font-size: 14px; border: 1px solid #e3e3e3; border-top: 2px solid #317ee7; } .page-shopping-cart .cart-title { color: #317ee7; font-size: 16px; text-align: left; padding-left: 20px; line-height: 68px; } .page-shopping-cart .red-text { color: #e94826; } .page-shopping-cart .check-span { display: block; width: 24px; height: 20px; background: url("shopping_cart.png") no-repeat 0 0; } .page-shopping-cart .check-span.check-true { background: url("shopping_cart.png") no-repeat 0 -22px; } .page-shopping-cart .td-check { width: 70px; } .page-shopping-cart .td-product { width: 460px; } .page-shopping-cart .td-num, .page-shopping-cart .td-price, .page-shopping-cart .td-total { width: 160px; } .page-shopping-cart .td-do { width: 150px; } .page-shopping-cart .cart-product-title { text-align: center; height: 38px; line-height: 38px; padding: 0 20px; background: #f7f7f7; border-top: 1px solid #e3e3e3; border-bottom: 1px solid #e3e3e3; } .page-shopping-cart .cart-product-title .td-product { text-align: center; font-size: 14px; } .page-shopping-cart .cart-product-title .td-check { text-align: left; } .page-shopping-cart .cart-product-title .td-check .check-span { margin: 9px 6px 0 0; } .page-shopping-cart .cart-product { padding: 0 20px; text-align: center; } .page-shopping-cart .cart-product table { width: 100%; text-align: center; font-size: 14px; } .page-shopping-cart .cart-product table td { padding: 20px 0; } .page-shopping-cart .cart-product table tr { border-bottom: 1px dashed #e3e3e3; } .page-shopping-cart .cart-product table tr:last-child { border-bottom: none; } .page-shopping-cart .cart-product table .product-num { border: 1px solid #e3e3e3; display: inline-block; text-align: center; } .page-shopping-cart .cart-product table .product-num .num-do { width: 24px; height: 28px; display: block; background: #f7f7f7; } .page-shopping-cart .cart-product table .product-num .num-reduce span { background: url("shopping_cart.png") no-repeat -40px -22px; display: block; width: 6px; height: 2px; margin: 13px auto 0 auto; } .page-shopping-cart .cart-product table .product-num .num-add span { background: url("shopping_cart.png") no-repeat -60px -22px; display: block; width: 8px; height: 8px; margin: 10px auto 0 auto; } .page-shopping-cart .cart-product table .product-num .num-input { width: 42px; height: 28px; line-height: 28px; border: none; text-align: center; } .page-shopping-cart .cart-product table .td-product { text-align: left; font-size: 12px; line-height: 20px; } .page-shopping-cart .cart-product table .td-product img { border: 1px solid #e3e3e3; margin-right: 10px; } .page-shopping-cart .cart-product table .td-product .product-info { display: inline-block; vertical-align: middle; } .page-shopping-cart .cart-product table .td-do { font-size: 12px; } .page-shopping-cart .cart-product-info { height: 50px; line-height: 50px; background: #f7f7f7; padding-left: 20px; } .page-shopping-cart .cart-product-info .delect-product { color: #666; } .page-shopping-cart .cart-product-info .delect-product span { display: inline-block; vertical-align: top; margin: 18px 8px 0 0; width: 13px; height: 15px; background: url("shopping_cart.png") no-repeat -60px 0; } .page-shopping-cart .cart-product-info .product-total { font-size: 14px; color: #e94826; } .page-shopping-cart .cart-product-info .product-total span { font-size: 20px; } .page-shopping-cart .cart-product-info .check-num { color: #333; } .page-shopping-cart .cart-product-info .check-num span { color: #e94826; } .page-shopping-cart .cart-product-info .keep-shopping { color: #666; margin-left: 40px; } .page-shopping-cart .cart-product-info .keep-shopping span { display: inline-block; vertical-align: top; margin: 18px 8px 0 0; width: 15px; height: 15px; background: url("shopping_cart.png") no-repeat -40px 0; } .page-shopping-cart .cart-product-info .btn-buy { height: 50px; color: #fff; font-size: 20px; display: block; width: 110px; background: #ff7700; text-align: center; margin-left: 30px; } .page-shopping-cart .cart-worder { padding: 20px; } .page-shopping-cart .cart-worder .choose-worder { color: #fff; display: block; background: #39e; width: 140px; height: 40px; line-height: 40px; border-radius: 4px; text-align: center; margin-right: 20px; } .page-shopping-cart .cart-worder .choose-worder span { display: inline-block; vertical-align: top; margin: 9px 10px 0 0; width: 22px; height: 22px; background: url("shopping_cart.png") no-repeat -92px 0; } .page-shopping-cart .cart-worder .worker-info { color: #666; } .page-shopping-cart .cart-worder .worker-info img { border-radius: 100%; margin-right: 10px; } .page-shopping-cart .cart-worder .worker-info span { color: #000; } .choose-worker-box { width: 620px; background: #fff; } .choose-worker-box .box-title { height: 40px; line-height: 40px; background: #F7F7F7; text-align: center; position: relative; font-size: 14px; } .choose-worker-box .box-title a { display: block; position: absolute; top: 15px; right: 16px; width: 10px; height: 10px; background: url("shopping_cart.png") no-repeat -80px 0; } .choose-worker-box .box-title a:hover { background: url("shopping_cart.png") no-repeat -80px -22px; } .choose-worker-box .worker-list { padding-top: 30px; height: 134px; overflow-y: auto; } .choose-worker-box .worker-list li { float: left; width: 25%; text-align: center; margin-bottom: 30px; } .choose-worker-box .worker-list li p { margin-top: 8px; } .choose-worker-box .worker-list li.cur a { color: #f70; } .choose-worker-box .worker-list li.cur a img { border: 1px solid #f70; } .choose-worker-box .worker-list li a:hover { color: #f70; } .choose-worker-box .worker-list li a:hover img { border: 1px solid #f70; } .choose-worker-box .worker-list li img { border: 1px solid #fff; border-radius: 100%; } </style> </head> <body> <div class="page-shopping-cart" id="shopping-cart"> <h4 class="cart-title">購物清單</h4> <div class="cart-product-title clearfix"> <div class="td-check fl"><span class="check-span fl check-all" :class="{'check-true':isSelectAll}" @click="selectProduct(isSelectAll)"></span>全選</div> <div class="td-product fl">商品</div> <div class="td-num fl">數量</div> <div class="td-price fl">單價(元)</div> <div class="td-total fl">金額(元)</div> <div class="td-do fl">操作</div> </div> <div class="cart-product clearfix"> <table> <tbody> <!--遍歷的時候帶上索引--> <tr v-for="(item,index) in productList"> <td class="td-check"><span class="check-span" @click="item.select=!item.select" :class="{'check-true':item.select}"></span></td> <td class="td-product"><img :src="item.pro_img" width="98" height="98"> <div class="product-info"> <h6>{{item.pro_name}}</h6> <p>品牌:{{item.pro_brand}} 產地:{{item.pro_place}}</p> <p>規格/純度:{{item.pro_purity}} 起定量:{{item.pro_min}}</p> <p>配送倉儲:{{item.pro_depot}}</p> </div> <div class="clearfix"></div> </td> <td class="td-num"> <div class="product-num"> <a href="javascript:;" class="num-reduce num-do fl" @click="item.pro_num>0?item.pro_num--:''"><span></span></a> <input type="text" class="num-input" v-model="item.pro_num"> <a href="javascript:;" class="num-add num-do fr" @click="item.pro_num++"><span></span></a> </div> </td> <td class="td-price"> <p class="red-text">¥<span class="price-text">{{item.pro_price.toFixed(2)}}</span></p> </td> <td class="td-total"> <p class="red-text">¥<span class="total-text">{{item.pro_price*item.pro_num}}</span>.00</p> </td> <td class="td-do"><a href="javascript:;" class="product-delect" @click="deleteOneProduct(index)">刪除</a></td> </tr> </tbody> </table> </div> <div class="cart-product-info"> <a class="delect-product" href="javascript:;" @click="deleteProduct"><span></span>刪除所選商品</a> <a class="keep-shopping" href="#"><span></span>繼續購物</a> <a class="btn-buy fr" href="javascript:;">去結算</a> <p class="fr product-total">¥<span>{{getTotal.totalPrice}}</span></p> <p class="fr check-num"><span>{{getTotal.totalNum}}</span>件商品總計(不含運費):</p> </div> </div> </body> <script src="vue.min.js"></script> <script> new Vue({ el: '#shopping-cart', data: { productList: [ { 'pro_name': '【斯文】甘油 | 丙三醇',//產品名稱 'pro_brand': 'skc',//品牌名稱 'pro_place': '韓國',//產地 'pro_purity': '99.7%',//規格 'pro_min': "215千克",//最小起訂量 'pro_depot': '上海倉海倉儲',//所在倉庫 'pro_num': 3,//數量 'pro_img': '../../images/ucenter/testimg.jpg',//圖片連結 'pro_price': 800//單價 }, { 'pro_name': '【斯文】甘油 | 丙三醇',//產品名稱 'pro_brand': 'skc',//品牌名稱 'pro_place': '韓國',//產地 'pro_purity': '99.7%',//規格 'pro_min': "215千克",//最小起訂量 'pro_depot': '上海倉海倉儲',//所在倉庫 'pro_num': 3,//數量 'pro_img': '../../images/ucenter/testimg.jpg',//圖片連結 'pro_price': 800//單價 }, { 'pro_name': '【斯文】甘油 | 丙三醇',//產品名稱 'pro_brand': 'skc',//品牌名稱 'pro_place': '韓國',//產地 'pro_purity': '99.7%',//規格 'pro_min': "215千克",//最小起訂量 'pro_depot': '上海倉海倉儲',//所在倉庫 'pro_num': 3,//數量 'pro_img': '../../images/ucenter/testimg.jpg',//圖片連結 'pro_price': 800//單價 } ] }, computed: { //檢測是否全選 isSelectAll:function(){ //如果productList中每一條資料的select都為true,返回true,否則返回false; return this.productList.every(function (val) { return val.select}); }, //獲取總價和產品總件數 getTotal:function(){ //獲取productList中select為true的資料。 var _proList=this.productList.filter(function (val) { return val.select}),totalPrice=0; for(var i=0,len=_proList.length;i<len;i++){ //總價累加 totalPrice+=_proList[i].pro_num*_proList[i].pro_price; } //選擇產品的件數就是_proList.length,總價就是totalPrice return {totalNum:_proList.length,totalPrice:totalPrice} } }, methods: { //全選與取消全選 selectProduct:function(_isSelect){ //遍歷productList,全部取反 for (var i = 0, len = this.productList.length; i < len; i++) { this.productList[i].select = !_isSelect; } }, //刪除已經選中(select=true)的產品 deleteProduct:function () { this.productList=this.productList.filter(function (item) {return !item.select}) }, //刪除單條產品 deleteOneProduct:function (index) { //根據索引刪除productList的記錄 this.productList.splice(index,1); }, }, mounted: function () { var _this=this; //為productList新增select(是否選中)欄位,初始值為true this.productList.map(function (item) { _this.$set(item, 'select', true); }) } }) </script> </html> |
5.todoList
執行效果
原理分析和實現
首先,還是先把佈局寫好,和引入vue,準備vue例項,這個不多說,程式碼如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> body{font-family: "微軟雅黑";font-size: 14px;} input{font-size: 14px;} body,ul,div,html{padding: 0;margin: 0;} .hidden{display: none;} .main{width: 800px;margin: 0 auto;} li{list-style-type: none;line-height: 40px;position: relative;border: 1px solid transparent;padding: 0 20px;} li .type-span{display: block;width: 10px;height: 10px;background: #ccc;margin: 14px 10px 0 0 ;float: left;} li .close{position: absolute;color: #f00;font-size: 20px;line-height: 40px;height: 40px;right: 20px;cursor: pointer;display: none;top: 0;} li:hover{border: 1px solid #09f;} li:hover .close{display: block;} li .text-keyword{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;} .text-keyword{box-sizing: border-box;width: 100%;height: 40px;padding-left: 10px;outline: none;} </style> </head> <body> <div id="app" class="main"> <h2>小目標列表</h2> <div class="list"> <h3>新增小目標</h3> <input type="text" class="text-keyword" placeholder="輸入小目標後,按回車確認"/> <p>共有N個目標</p> <p> <input type="radio" name="chooseType" checked="true"/><label>所有目標</label> <input type="radio" name="chooseType"/><label>已完成目標</label> <input type="radio" name="chooseType"/><label>未完成目標</label> </p> </div> <ul> <li class="li1"> <div> <span class="type-span"></span> <span>html5</span> <span class="close">X</span> </div> </li> <li class="li1"> <div> <span class="type-span"></span> <span>css3</span> <span class="close">X</span> </div> </li> </ul> </div> </body> <script src="vue2.4.2.js"></script> <script type="text/javascript"> new Vue({ el: "#app", data: { }, computed:{ }, methods:{ } }); </script> </html> |
佈局有了,相當於一個骨架就有了,下面實現功能,一個一個來
步驟1
輸入並回車,多一條記錄。下面的記錄文字也會改變
首先,大的輸入框回車要新增紀錄,那麼輸入框必須繫結一個值和一個新增紀錄的方法。
程式碼如下:
然後,下面的記錄也要改變,所以,下面的記錄也要幫一個值,因為這個記錄可能會有多個,這個值就是一個陣列,也可以看到,記錄除了名稱,還有記錄是否完成的狀態,所以,繫結記錄的這個值肯定是一個物件陣列!程式碼如下
最後,記錄文字要改變。這個只是一個當前記錄的長度即可!
為了著重表示我修改了什麼地方,程式碼我現在只貼出修改的部分,大家對著上面的佈局,就很容易知道我改的是什麼地方了!下面也是這樣操作!
html程式碼
1 2 3 4 5 6 7 8 9 10 11 |
<!--利用v-model把addText繫結到input--> <input type="text" class="text-keyword" placeholder="輸入小目標後,按回車確認" @keyup.13='addList' v-model="addText"/> <p>共有{{prolist.length}}個目標</p> <!--v-for遍歷prolist--> <li class="li1" v-for="list in prolist"> <div> <span class="type-span"></span> <span>{{list.name}}</span> <span class="close">X</span> </div> </li> |
js程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
new Vue({ el: "#app", data: { addText:'', //name-名稱,status-完成狀態 prolist:[ {name:"HTML5",status:false}, {name:"CSS3",status:false}, {name:"vue",status:false}, {name:"react",status:false} ] }, computed:{ }, methods:{ addList(){ //新增進來預設status=false,就是未完成狀態 this.prolist.push({ name:this.addText, status:false }); //新增後,清空addText this.addText=""; } } }); |
測試一下,沒問題
步驟2
點選切換,下面記錄會改變
看到三個選項,也很簡單,無非就是三個選擇,一個是所有的目標,一個是所有已經完成的目標,一個是所有沒完成的目標。
首先.新建一個新的變數(newList),儲存prolist。遍歷的時候不再遍歷prolist,而是遍歷newList。改變也是改變newList。
然後.選擇所有目標的時候,顯示全部prolist,把prolist賦值給newList。
然後.選擇所有已經完成目標的時候,只顯示prolist中,status為true的目標,把prolist中,status為true的項賦值給newList,
最後.選擇所有未完成目標的時候,只顯示status為false的目標,把prolist中,status為false的項賦值給newList。
程式碼如下
html
1 2 3 4 5 6 7 8 9 |
<ul> <li class="li1" v-for="list in newList"> <div> <span class="status-span"></span> <span>{{list.name}}</span> <span class="close" @click='delectList(index)'>X</span> </div> </li> </ul> |
js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
new Vue({ el: "#app", data: { addText:'', //name-名稱,status-完成狀態 prolist:[ {name:"HTML5",status:false}, {name:"CSS3",status:false}, {name:"vue",status:false}, {name:"react",status:false} ], newList:[] }, computed:{ noend:function(){ return this.prolist.filter(function(item){ return !item.status }).length; } }, methods:{ addList(){ //新增進來預設status=false,就是未完成狀態 this.prolist.push({ name:this.addText, status:false }); //新增後,清空addText this.addText=""; }, chooseList(type){ //type=1時,選擇所有目標 //type=2時,選擇所有已完成目標 //type=3時,選擇所有未完成目標 switch(type){ case 1:this.newList=this.prolist;break; case 2:this.newList=this.prolist.filter(function(item){return item.status});break; case 3:this.newList=this.prolist.filter(function(item){return !item.status});break; } }, delectList(index){ //根據索引,刪除陣列某一項 this.prolist.splice(index,1); //更新newList newList可能經過this.prolist.filter()賦值,這樣的話,刪除了prolist不會影響到newList 那麼就要手動更新newList this.newList=this.prolist; }, }, mounted(){ //初始化,把prolist賦值給newList。預設顯示所有目標 this.newList=this.prolist; } }); |
執行結果
步驟3
紅色關閉標識,點選會刪除該記錄。前面按鈕點選會切換該記錄完成狀態,顏色也改變,記錄文字也跟著改變
首先點選紅色關閉標識,點選會刪除該記錄。這個應該沒什麼問題,就是刪除prolist的一條記錄!
然後前面按鈕點選會切換該記錄完成狀態。這個也沒什麼,就是改變prolist的一條記錄的status欄位!
最後記錄文字的改變,就是記錄prolist中status為false的有多少條,prolist中status為true的有多少條而已
html程式碼
1 2 |
<!--如果noend等於0,就是全部完成了就顯示‘全部完成了’,如果沒有就是顯示已完成多少條(prolist.length-noend)和未完成多少條(noend)--> <p>共有{{prolist.length}}個目標,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',還有'+noend+'條未完成'}}</p><code><!--如果noend等於0,就是全部完成了就顯示‘全部完成了’,如果沒有就是顯示已完成多少條(prolist.length-noend)和未完成多少條(noend)--> |
1 2 3 4 5 6 7 8 9 |
<ul> <li class="li1" v-for="(list,index) in newList"> <div> <span class="status-span" @click="list.status=!list.status" :class="{'status-end':list.status}"></span> <span>{{list.name}}</span> <span class="close" @click='delectList(index)'>X</span> </div> </li> </ul> |
js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
new Vue({ el: "#app", data: { addText:'', //name-名稱,status-完成狀態 prolist:[ {name:"HTML5",status:false}, {name:"CSS3",status:false}, {name:"vue",status:false}, {name:"react",status:false} ], newList:[] }, computed:{ //計算屬性,返回未完成目標的條數,就是陣列裡面status=false的條數 noend:function(){ return this.prolist.filter(function(item){ return !item.status }).length; } }, methods:{ addList(){ //新增進來預設status=false,就是未完成狀態 this.prolist.push({ name:this.addText, status:false }); //新增後,清空addText this.addText=""; }, chooseList(type){ switch(type){ case 1:this.newList=this.prolist;break; case 2:this.newList=this.prolist.filter(function(item){return item.status});break; case 3:this.newList=this.prolist.filter(function(item){return !item.status});break; } }, delectList(index){ //根據索引,刪除陣列某一項 this.prolist.splice(index,1); //更新newList newList可能經過this.prolist.filter()賦值,這樣的話,刪除了prolist不會影響到newList 那麼就要手動更新newList this.newList=this.prolist; }, }, mounted(){ this.newList=this.prolist; } }); |
執行結果
步驟4
文字雙擊會出現輸入框,可輸入文字,如果回車或者失去焦點,就改變文字,如果按下ESC就恢復原來的文字
首先.雙擊出現輸入框,就是雙擊文字後,給當前的li設定一個類名(‘eidting
’),然後寫好樣式。當li出現這個類名的時候,就出現輸入框,並且隱藏其它內容。
然後.回車或者失去焦點,就改變文字這個只需要操作一個,就是把類名(‘eidting
’)清除掉。然後輸入框就會隱藏,其它內容顯示!
最後.按下ESC就恢復原來的文字,就是出現輸入框的時候,用一個變數(‘beforeEditText
’)先儲存當前的內容,然後按下了ESC,就把變數(‘beforeEditText
’)賦值給當前操作的值!
程式碼如下:
html
1 2 3 4 5 6 7 8 9 10 |
<ul> <li class="li1" v-for="(list,index) in newList" :class="{'eidting':curIndex===index}"> <div> <span class="status-span" @click="list.status=!list.status" :class="{'status-end':list.status}"></span> <span @dblclick="curIndex=index">{{list.name}}</span> <span class="close" @click='delectList(index)'>X</span> </div> <input type="text" class="text2" v-model='list.name' @keyup.esc='cancelEdit(list)' @blur='edited' @focus='editBefore(list.name)' @keyup.enter='edited'/> </li> </ul> |
css(加上)
1 2 3 4 |
li div{display: block;} li.eidting div{display: none;} li .text2{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;} li.eidting .text2{display: block;} |
js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
methods:{ addList(){ //新增進來預設status=false,就是未完成狀態 this.prolist.push({ name:this.addText, status:false }); //新增後,清空addText this.addText=""; }, chooseList(type){ //type=1時,選擇所有目標 //type=2時,選擇所有已完成目標 //type=3時,選擇所有未完成目標 switch(type){ case 1:this.newList=this.prolist;break; case 2:this.newList=this.prolist.filter(function(item){return item.status});break; case 3:this.newList=this.prolist.filter(function(item){return !item.status});break; } }, delectList(index){ //根據索引,刪除陣列某一項 this.prolist.splice(index,1); //更新newList newList可能經過this.prolist.filter()賦值,這樣的話,刪除了prolist不會影響到newList 那麼就要手動更新newList this.newList=this.prolist; }, //修改前 editBefore(name){ //先記錄當前項(比如這一項,{name:"HTML5",status:false}) //beforeEditText="HTML5" this.beforeEditText=name; }, //修改完成後 edited(){ //修改完了,設定curIndex="",這樣輸入框就隱藏,其它元素就會顯示。因為在li元素 寫了::class="{'eidting':curIndex===index}" 當curIndex不等於index時,eidting類名就清除了! //輸入框利用v-model繫結了當前項(比如這一項,{name:"HTML5",status:false})的name,當在輸入框編輯的時候,比如改成‘HTML’,實際上當前項的name已經變成了‘HTML’,所以,這一步只是清除eidting類名,隱藏輸入框而已 //還有一個要注意的就是雖然li遍歷的是newList,比如改了newList的這一項({name:"HTML5",status:false}),比如改成這樣({name:"HTML",status:true})。實際上prolist的這一項({name:"HTML5",status:false}),也會被改成({name:"HTML",status:true})。因為這裡是一個物件,而且公用一個堆疊!修改其中一個,另一個會被影響到 this.curIndex=""; }, //取消修改 cancelEdit(val){ //上面說了輸入框利用v-model繫結了當前項(比如這一項,{name:"HTML5",status:false})的name,當在輸入框編輯的時候,比如改成‘HTML’,實際上當前項的name已經變成了‘HTML’,所以,這一步就是把之前儲存的beforeEditText賦值給當前項的name屬性,起到一個恢復原來值得作用! val.name=this.beforeEditText; this.curIndex=""; } }, |
執行結果
還有一個小細節,大家可能注意到了,就是雙擊文字,出來輸入框的時候,還要自己手動點選一下,才能獲得焦點,我們想雙擊了,輸入框出來的時候,自動獲取焦點,怎麼辦?自定義指令就行了!
1 2 3 4 5 6 7 8 9 10 |
computed:{...}, methods:{...}, mounted(){...}, directives:{ "focus":{ update(el){ el.focus(); } } } |
然後html 呼叫指令
1 |
<input type="text" class="text2" v-model="list.name" v-focus=""/> |
完整程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> body{font-family: "微軟雅黑";font-size: 14px;} input{font-size: 14px;} body,ul,div,html{padding: 0;margin: 0;} .hidden{display: none;} .main{width: 800px;margin: 0 auto;} li{list-style-type: none;line-height: 40px;position: relative;border: 1px solid transparent;padding: 0 20px;} li .status-span{display: block;width: 10px;height: 10px;background: #ccc;margin: 14px 10px 0 0 ;float: left;} li .status-span.status-end{ background: #09f; } li .close{position: absolute;color: #f00;font-size: 20px;line-height: 40px;height: 40px;right: 20px;cursor: pointer;display: none;top: 0;} li:hover{border: 1px solid #09f;} li:hover .close{display: block;} li div{display: block;} li.eidting div{display: none;} li .text2{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;} li.eidting .text2{display: block;} li .text-keyword{height: 40px;padding-left: 10px;box-sizing: border-box;margin-left: 10px;width: 80%;display: none;} .text-keyword{box-sizing: border-box;width: 100%;height: 40px;padding-left: 10px;outline: none;} </style> </head> <body> <div id="app" class="main"> <h2>小目標列表</h2> <div class="list"> <h3>新增小目標</h3> <input type="text" class="text-keyword" placeholder="輸入小目標後,按回車確認" @keyup.13='addList' v-model="addText"/> <!--如果noend等於0,就是全部完成了就顯示‘全部完成了’,如果沒有就是顯示已完成多少條(prolist.length-noend)和未完成多少條(noend)--> <p>共有{{prolist.length}}個目標,{{noend==0?"全部完成了":'已完成'+(prolist.length-noend)+',還有'+noend+'條未完成'}}</p> <p> <input type="radio" name="chooseType" checked="true" @click='chooseList(1)'/><label>所有目標</label> <input type="radio" name="chooseType" @click='chooseList(2)'/><label>已完成目標</label> <input type="radio" name="chooseType" @click='chooseList(3)'/><label>未完成目標</label> </p> </div> <ul> <li class="li1" v-for="(list,index) in newList" :class="{'eidting':curIndex===index}"> <div> <span class="status-span" @click="changeType(index)" :class="{'status-end':list.status}"></span> <span @dblclick="curIndex=index">{{list.name}}</span> <span class="close" @click='delectList(list)'>X</span> </div> <input type="text" class="text2" v-model='list.name' @keyup.esc='cancelEdit(list)' @blur='edited' @focus='editBefore(list.name)' @keyup.enter='edited' v-focus/> </li> </ul> </div> </body> <script src="vue.min.js"></script> <script type="text/javascript"> new Vue({ el: "#app", data: { addText:'', //name-名稱,status-完成狀態 prolist:[ {name:"HTML5",status:false}, {name:"CSS3",status:false}, {name:"vue",status:false}, {name:"react",status:false} ], newList:[], curIndex:'', beforeEditText:"", curType:0 }, computed:{ //計算屬性,返回未完成目標的條數,就是陣列裡面status=false的條數 noend:function(){ return this.prolist.filter(function(item){ return !item.status }).length; } }, methods:{ addList(){ //新增進來預設status=false,就是未完成狀態 this.prolist.push({ name:this.addText, status:false }); //新增後,清空addText this.addText=""; }, chooseList(type){ //type=1時,選擇所有目標 //type=2時,選擇所有已完成目標 //type=3時,選擇所有未完成目標 this.curType=type; switch(type){ case 1:this.newList=this.prolist;break; case 2:this.newList=this.prolist.filter(function(item){return item.status});break; case 3:this.newList=this.prolist.filter(function(item){return !item.status});break; } }, /*改變單條資料的完成狀態*/ changeType(index){ this.newList[index].status=!this.newList[index].status; //更新資料 this.chooseList(this.curType); }, delectList(list){ var index=this.prolist.indexOf(list); //根據索引,刪除陣列某一項 this.prolist.splice(index,1); //更新newList newList可能經過this.prolist.filter()賦值,這樣的話,刪除了prolist不會影響到newList 那麼就要手動更新newList //this.newList=this.prolist; this.chooseList(this.curType); }, //修改前 editBefore(name){ //先記錄當前項(比如這一項,{name:"HTML5",status:false}) //beforeEditText="HTML5" this.beforeEditText=name; }, //修改完成後 edited(){ //修改完了,設定curIndex="",這樣輸入框就隱藏,其它元素就會顯示。因為在li元素 寫了::class="{'eidting':curIndex===index}" 當curIndex不等於index時,eidting類名就清除了! //輸入框利用v-model繫結了當前項(比如這一項,{name:"HTML5",status:false})的name,當在輸入框編輯的時候,比如改成‘HTML’,實際上當前項的name已經變成了‘HTML’,所以,這一步只是清除eidting類名,隱藏輸入框而已 //還有一個要注意的就是雖然li遍歷的是newList,比如改了newList的這一項({name:"HTML5",status:false}),比如改成這樣({name:"HTML",status:true})。實際上prolist的這一項({name:"HTML5",status:false}),也會被改成({name:"HTML",status:true})。因為這裡是一個物件,而且公用一個堆疊!修改其中一個,另一個會被影響到 this.curIndex=""; }, //取消修改 cancelEdit(val){ //上面說了輸入框利用v-model繫結了當前項(比如這一項,{name:"HTML5",status:false})的name,當在輸入框編輯的時候,比如改成‘HTML’,實際上當前項的name已經變成了‘HTML’,所以,這一步就是把之前儲存的beforeEditText賦值給當前項的name屬性,起到一個恢復原來值得作用! val.name=this.beforeEditText; this.curIndex=""; } }, mounted(){ //初始化,把prolist賦值給newList。預設顯示所有目標 this.newList=this.prolist; }, directives:{ "focus":{ update(el){ el.focus(); } } } }); </script> </html> |
6.小結
好了,三個小例項在這裡就說完了!別看文章這麼長,其實都是基礎,可能是我比較囉嗦而已!如果大家能熟透這幾個小例項,相信用vue做專案也是信手拈來。基礎的語法在這裡了,有了基礎,高階的寫法也不會很難學習!如果以後,我有什麼要分享的,我會繼續分享。最後一句老話,如果覺得我哪裡寫錯了,寫得不好,歡迎指點!