---
# System prepended metadata

title: Vue2第一章
tags: [第一章, Vue]

---

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