--- tags: Vue,第一章 --- ![](https://hackmd.io/_uploads/SyYdIvRun.png) 官方網站 https://cn.vuejs.org/ cdn引入 ``` <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> ``` ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app">{{msg}}</div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { msg: "你好", }, }); </script> </body> </html> ``` # 基礎語法 ## 插值表達式 一定是Vue實例有的資料 可以求值的代碼都能寫進插值表達式 語句不可以寫進插值表達式 if(){} for(){} while(){} 標籤屬性不能用插值表達式 `<a href="{{url}}">google</a>` ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <p>{{nickname}}</p> <p>{{nickname.substring(2)}}</p> <p>{{age}}</p> <p>{{age >= 18 ? '成年' : '未成年'}}</p> <p>{{friend.name}}---{{friend.introduce}}</p> <a href="{{url}}">google</a> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { nickname: "紫陽道長", age: 18, msg: "你好", friend: { name: "張三", introduce: "熱愛學習", }, }, }); </script> </body> </html> ``` ## F12檢查 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app">{{msg}}{{count}}</div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { msg: "你好", count:100 }, }); </script> </body> </html> ``` F12主控台可以查看與修改Vue實例 查看app.msg 修改app.msg = '不好' 查看app.count 修改app.count++ 切記不用加data了 ### 插件 官方測試網站 https://play.vuejs.org/#eNo9jDsOwjAQRK+yuDEUENEiJxIdN6Bxg5INRPJnZa/TWL47S5BSvnkzU9Wd6LIWVDdl8pgWYsjIhQYbFk8xMVRIOEODOUUPWqraBhvGGDKDz2/of/6oH+hchGdMbjrokw2m+9/JkQCjJ/diFAIwn+tQ6zZuzXRCW7oEKgzr2ccJXW+VeKtEmW5fq/YFaYM9HQ== 必裝插件 ![](https://hackmd.io/_uploads/SyYudyHUh.png) ## v-html 設置元素的innerHTML ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <div v-html="msg">我是看不見的喔</div> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { msg: "<h2>前端Vue</h2>", }, }); </script> </body> </html> ``` ## v-if和v-show ### v-show v-show = '表達式' 表達式結果必為布林值 原理:切換display:none ### v-if v-if = '表達式' 表達式結果必為布林值 原理:創建或移除元素節點 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <div v-show="isShow">我是show</div> <div v-if="isShow">我是if</div> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { isShow: false }, }); </script> </body> </html> ``` ## v-else和v-else-if 標籤跟標籤一定要緊貼 不過中間可以寫注釋 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <p v-if="gender===1">性別男</p> <!-- 我是注釋 --> <p v-else>性別女</p> <hr /> <p v-if="score>=90">A</p> <p v-else-if="score>=70">B</p> <p v-else-if="score>=60">C</p> <p v-else>D</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { gender: 1, score: 95, }, }); </script> </body> </html> ``` ## v-on基本 `v-on:click='count++'` 簡寫後 `@click='count++'` ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <button v-on:click="count--">-</button> <span>{{count}}</span> <button v-on:click="count++">+</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { count:100 }, }); </script> </body> </html> ``` ## v-on函式 method中的函式 其this都指向app(實例對象) ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <button @click="isShow= !isShow">切換顯示隱藏</button> <button @click="change">切換顯示隱藏</button> <h1 v-show="isShow">黑馬程序員</h1> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { isShow: true }, methods: { change() { this.isShow = !this.isShow; console.log(this === app); } } }); </script> </body> </html> ``` ### ES6函式簡寫 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <script> obj = { fun1:function(){ console.log(111); }, fun2(){ console.log(222); } }; obj.fun1(); obj.fun2(); </script> </body> </html> ``` ## v-on傳參 `@click="buy(5)"`小括號不是調用函數,只是綁定事件實參而已 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .box { width: 200px; height: 100px; border: 2px solid black; text-align: center; border-radius: 5px; } </style> </head> <body> <div id="app"> <div class="box"> <h3>小黑自動售貨機</h3> <button @click="buy(5)">可樂5元</button> <button @click="buy(10)">咖啡10元</button> </div> <p>銀行卡餘額:{{money}}元</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { money: 100 }, methods: { buy(price) { this.money > 0 ? (this.money -= price) : (this.money = 0); } } }); </script> </body> </html> ``` ## v-bind `v-bind:src="imgUrl"` 簡寫後 `:src="imgUrl"` ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <img v-bind:src="imgUrl" :title="msg"> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { imgUrl: "https://picsum.photos/200", msg: "我是假圖喔", }, }); </script> </body> </html> ``` ## 小案例-切換圖片 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <button v-show="index>0" @click="index--">上一頁</button> <div> <img :src="list[index]" /> </div> <button v-show="index<list.length-1" @click="index++">下一頁</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { index: 0, list: [ "https://picsum.photos/100", "https://picsum.photos/200", "https://picsum.photos/300", "https://picsum.photos/400", "https://picsum.photos/500", "https://picsum.photos/600", ], }, }); </script> </body> </html> ``` ## v-for ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <h3>小黑水果店</h3> <ul> <li v-for="(item,index) in list">{{item}}---{{index}}</li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { list: ["蘋果", "芭樂", "香蕉", "橘子"], }, }); </script> </body> </html> ``` ### v-for不用數組 ```htmlmixed= <ul> <子組件 v-for="item in 4" :key="item"></子組件> </ul> ``` ## 小案例-小黑書架 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <h3>小黑的書架</h3> <ul> <li v-for="item in bookList"> <span>{{item.name}}</span> <span>{{item.author}}</span> <button @click="del(item.id)">刪除</button> </li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { bookList: [ { id: 1, name: "《紅樓夢》", author: "曹雪芹", }, { id: 2, name: "《西遊記》", author: "吳承恩", }, { id: 3, name: "《水滸傳》", author: "施耐庵", }, { id: 4, name: "《三國演義》", author: "羅貫中", }, ], }, methods: { del(id) { // console.log("我要刪除", id); // const index = this.bookList.findIndex((item) => item.id === id); // this.bookList.splice(index, 1); // 更牛逼的方法 this.bookList = this.bookList.filter((item) => item.id !== id); }, }, }); </script> </body> </html> ``` ## v-for之key ### 不使用key Vue不會輕易刪除DOM元素 v-for默認複用策略: 單前刪除一個元素後 Vue實際上是刪除最後一個元素 裡面內容平移 以複用現存li ... 測試項目 ul li:first-child 不會砍掉 input type="checkbox" 不會砍掉 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> ul li:first-child { background-color: pink; } </style> </head> <body> <div id="app"> <h3>小黑的書架</h3> <ul> <li v-for="item in bookList"> <input type="checkbox" /> <span>{{item.name}}</span> <span>{{item.author}}</span> <button @click="del(item.id)">刪除</button> </li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { bookList: [ { id: 1, name: "《紅樓夢》", author: "曹雪芹", }, { id: 2, name: "《西遊記》", author: "吳承恩", }, { id: 3, name: "《水滸傳》", author: "施耐庵", }, { id: 4, name: "《三國演義》", author: "羅貫中", }, ], }, methods: { del(id) { // console.log("我要刪除", id); // const index = this.bookList.findIndex((item) => item.id === id); // this.bookList.splice(index, 1); // 更牛逼的方法 this.bookList = this.bookList.filter((item) => item.id !== id); }, }, }); </script> </body> </html> ``` ### 使用key key一般常用唯一標誌符:id 不推薦使用index key的設置要求: 1.一定要在當前v-for中唯一 2.必須是string或number 3.通常要配v-bind ... 測試項目 ul li:first-child 不會砍掉 input type="checkbox" 砍掉 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> ul li:first-child { background-color: pink; } </style> </head> <body> <div id="app"> <h3>小黑的書架</h3> <ul> <li v-for="item in bookList" :key="item.id"> <input type="checkbox" /> <span>{{item.name}}</span> <span>{{item.author}}</span> <button @click="del(item.id)">刪除</button> </li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { bookList: [ { id: 1, name: "《紅樓夢》", author: "曹雪芹", }, { id: 2, name: "《西遊記》", author: "吳承恩", }, { id: 3, name: "《水滸傳》", author: "施耐庵", }, { id: 4, name: "《三國演義》", author: "羅貫中", }, ], }, methods: { del(id) { // console.log("我要刪除", id); // const index = this.bookList.findIndex((item) => item.id === id); // this.bookList.splice(index, 1); // 更牛逼的方法 this.bookList = this.bookList.filter((item) => item.id !== id); }, }, }); </script> </body> </html> ``` ## v-model ![](https://hackmd.io/_uploads/B1B922vFn.png) ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> 帳戶: <input type="text" v-model="username" /><br /><br /> 密碼: <input type="password" v-model="password" /><br /><br /> <button @click="login">登錄</button> <button @click="reset">重置</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { username: "", password: "", }, methods: { login() { console.log(this.username, this.password); }, reset() { this.username = ""; this.password = ""; }, }, }); </script> </body> </html> ``` # 綜合案例-小黑記事本 ```javascript= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="./p018.css" /> <title>小黑記事本</title> </head> <body> <!-- 主區域 --> <section id="app"> <!-- 輸入框 --> <header> <h1 class="title">小黑記事本</h1> <div class="input"> <input class="mission" placeholder="請輸入任務" v-model="taskName" /> <button class="btn-big" @click="add">添加任務</button> </div> </header> <!-- 列表區域 --> <section> <ul> <li v-for="(item,index) in list" :key="item.id"> <div> <span>{{index+1}}.</span><label for="">{{item.name}}</label ><button class="x" @click="del(item.id)"></button> </div> </li> </ul> </section> <!-- 統計和清空 --> <footer v-show="list.length>0"> <!-- 統計 --> <span>合計:<strong>{{list.length}}</strong></span> <!-- 清空 --> <button @click="clear">清空任務</button> </footer> </section> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { list: [ { id: 1, name: "跑步一公里" }, { id: 2, name: "打球一小時" }, { id: 3, name: "游泳100米" }, ], taskName: "", }, methods: { del(id) { this.list = this.list.filter((item) => { return item.id !== id; }); }, add() { if (this.taskName.trim() === "") { return alert("請輸入任務名稱"); } this.list.unshift({ id: +new Date(), name: this.taskName, }); this.taskName = ""; }, clear() { this.list = []; }, }, }); </script> </body> </html> ``` ```css= /* 全局 */ * { list-style: none; } body { background-color: #f5f5f5; } #app { display: block; width: 1000px; height: 1000px; margin: 100px auto; text-align: center; } /* 輸入框 */ .title { color: red; font-size: 50px; } .input { width: 240px; border: 1px solid #ff5809; margin: 0 auto; display: flex; justify-content: center; } .mission { width: 160px; height: 40px; border: none; } .btn-big { width: 80px; height: 42px; border: none; background-color: #ff5809; } /* 列表區域 */ section ul li:hover .x::before { content: "x"; } .x{ border: none; } ```