一篇帶你Vue快速入門

文章目錄

Vue基礎

1. Vue介紹

1.1 Vue是什麼

Vue.JS是優秀的前端 JavaScript 框架

react/angular/vue

庫和框架的區別:

  • 庫(如jQuery)

    庫是工具. 提供大量API,體現了封裝的思想、需要自己調用這些API

  • 框架

    框架提供了一套完整解決方案,

    使用者要按照框架所規定的某種規範進行開發

1.2 爲什麼要學習 Vue

傳統開發模式: JQuery+RequireJS/SeaJS+artTemplate+Gulp/Grunt

隨着項目業務場景的複雜,傳統模式已無法滿足需求

就出現了Angular/React/Vue等框架

  • 企業需求
  • 主流框架之一(React Angular Vue)
  • 易用、靈活、高效

1.3 Vue 能做什麼

  • 最大程度上解放了 DOM 操作
  • 單頁web項目(SinglePageApplication項目,例如Worktile官網)開發
  • 傳統網站開發

1.4 核心特性

  • 雙向數據綁定
  • vue(借鑑了react的虛擬DOM,借鑑了angular雙向數據綁定)
  • 通過 指令 擴展了 HTML,通過 表達式 綁定數據到 HTML
  • 解耦視圖與數據
  • 可複用組件
  • 虛擬DOM
  • M-V-VM
  • 數據驅動視圖

1.5 一些鏈接

Vue官方文檔

Vue開源項目彙總

Vue.js中文社區

2. Vue起步

2.1 安裝Vue

  1. 直接下載源碼然後通過路徑引入

    • 開發版本:https://vuejs.org/js/vue.js
    • 生產版本:https://vuejs.org/js/vue.min.js
  2. CDN

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
  1. 使用 npm 下載(默認安裝最新穩定版) 然後通過路徑引入
npm init -y
npm i vue

Vue.js 不支持 IE8 及其以下版本

2.2 HelloWorld

作用:將數據應用在html頁面中

1. body中,設置Vue管理的視圖<div id="app"></div>
2. 引入vue.js
3. 實例化Vue對象 new Vue();
4. 設置Vue實例的選項:如el、data...     
	new Vue({選項:值});
5. 在<div id='app'></div>中通過{{ }}使用data中的數據
<!-- 我是Vue所管理的視圖div#app -->
<div id="app">
    <!-- 在視圖裏使用Vue實例中data裏面的list數據 -->
    <p>{{list}}</p>
</div>
<!-- 引入vue.js -->
<script src="./vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            list: '我是模擬發起ajax請求後從服務端返回的數據'
        }
    })
</script>

2.3 Vue實例的選項(重要)

el
  • 作用:當前Vue實例所管理的html視圖
  • 值:通常是id選擇器(或者是一個 HTMLElement 實例)
  • 不要讓el所管理的視圖是html或者body!
data
  • Vue 實例的數據對象,是響應式數據(數據驅動視圖)
  • 可以通過 vm.$data 訪問原始數據對象
  • Vue 實例也代理了 data 對象上所有的屬性,因此訪問 vm.a 等價於訪問 vm.$data.a
  • 視圖中綁定的數據必須顯式的初始化到 data 中
methods
  • 其值爲可以一個對象
  • 可以直接通過 VM 實例訪問這些方法,或者在指令表達式中使用
  • 方法中的 this 自動綁定爲 Vue 實例。
  • 注意,不應該使用箭頭函數來定義 method 函數 (例如 plus: () => this.a++)。理由是箭頭函數綁定了父級作用域的上下文,所以 this 將不會按照期望指向 Vue 實例,this.a 將是 undefined
代碼演示
<div id="a">
    {{msgA}} -- {{fn1()}}
</div>

<script src="./vue.js"></script>
<script>
    const vm = new Vue({
        // el作用:指定當前Vue實例所管理的視圖,值通常是id選擇器
        // 1. el的值可以是css選擇器,通常是id選擇器
        // 2. el的值不能是html標籤和body標籤

        el: '#a',
        // data作用:指定當前Vue實例的數據對象
        // 1. data中的數據是響應式數據
        // 2. 值可以是一個對象 {屬性: 值}
        // 3. 所有數據部分寫在data中
        // 4. 在當前Vue實例所管理的視圖中通過屬性名使用data中的數據
        // 5. 可以通過vm.$data.屬性 訪問數據
        // 6. 可以通過vm.屬性 訪問數據(更簡單)
        data: {
            msgA: '第一個Vue實例對象'
        },
        // methods作用:指定當前Vue實例中的方法
        // 1. 可以直接通過vm實例訪問這些方法,
        // 2. 方法中的 this 自動綁定爲 Vue 實例。
        // 3. 不推薦使用箭頭函數
        methods: {
            fn1: function() {
                console.log(this.msgA);
                console.log('vm實例中的methods裏的fn1方法被調用');
            },
            fn2: function() {
                this.fn1();
                console.log('fn2方法被調用--');
            },
            fn3: () => {
                console.log(this);
            }
        }
    });
    // 調用fn2方法
    vm.fn2();
    // 調用fn3方法
    vm.fn3();
</script>

3. 術語解釋

插值表達式

作用:會將綁定的數據實時的顯示出來:

通過任何方式修改所綁定的數據,所顯示的數據都會被實時替換

{{js表達式、三目運算符、方法調用等}}

不能寫 var a = 10; 分支語句 循環語句

    <div id="app">
        <!-- 在插值表達式中可以訪問vm實例中data裏面的屬性 -->
        {{message}}
        <p>{{message}}</p>
        <p>{{message+'啦啦啦'}}</p>
        <p>{{age>18?'成年':'未成年'}}</p>
        <p>{{message.split("")}}</p>
        <!-- 在插值表達式中不能寫js語句 -->
        <p>{{var a = 10}}</p>
    </div>
    <!-- 引入vue.js -->
    <script src="./vue.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                message: '我是data中的message屬性的值',
                age: 20
            }
        });
    </script>

插值表達式中不能寫js語句, 如var a = 10;

指令

指令 (Directives) 是帶有 v- 前綴的特殊特性。

指令特性的值預期是單個 JavaScript 表達式(v-for 是例外情況,稍後我們再討論)。

指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM。

Vue框架提供的語法

擴展了HTML的能力

減少DOM操作

  <div id="app">
        <p> {{message}}</p>
        <!-- v-on就是vue給標籤元素提供的擴展-指令
            v-on指令就是給標籤綁定事件,這裏是click,
            當事件處於點擊狀態時,出發methods中的changeMsg方法
        -->
        <button v-on:click="changeMsg">按鈕</button>
    </div>
    <!-- 引入vue.js -->
    <script src="./vue.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                message: '我是data中的message屬性的值',
                age: 20
            },
            methods: {
                changeMsg: function() {
                    this.message += "啦";
                }
            }
        });
    </script>

Vue常用指令

擴展了html標籤的功能、大部分的指令的值是js的表達式

取代DOM操作

v-text 和 v-html

很像innerText和innerHTML

  • v-text:更新標籤中的內容
    • v-text和插值表達式的區別
      • v-text 更新整個標籤中的內容
      • 插值表達式: 更新標籤中局部的內容
  • v-html:更新標籤中的內容/標籤
    • 可以渲染內容中的HTML標籤
    • 注意:儘量避免使用,容易造成危險 (XSS跨站腳本攻擊)
 <div id="app">
        <!-- v-text指令的值會替換標籤內容 -->
        <p>{{str}}</p>
        <p v-text="str"></p>
        <p v-text="str">我是p標籤中的內容</p>
        <p v-text="strhtml">我是p標籤中的內容</p>
        <p v-html="str"></p>
        <!-- v-html指令的值(包括標籤字符串)會替換掉標籤的內容 -->
        <p v-html="strhtml">我是p標籤中的內容</p>
    </div>
    <script src="./vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                str: 'abc',
                strhtml: '<span>content</span>'
            }
        });
    </script>

v-if 和 v-show

  • 作用:根據表達式的bool值進行判斷是否渲染該元素

在這裏插入圖片描述

 <div id="app">
        <!-- 如果isShow的值是true ,就顯示p標籤 -->
        <p v-if="isShow">我是p標籤中的內容</p>
        <p v-show="isShow">我是p標籤中的內容</p>
        <!-- 如果標籤顯示與隱藏切換頻繁, 就使用v-show 
            v-show本質是通過修改標籤的display值
        -->
    </div>
    <script src="./vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                isShow: false
            }
        });
    </script>

效果

在這裏插入圖片描述

  • v-if 有更高的切換開銷,而 v-show 有更高的初始渲染開銷。
  • 如果需要非常頻繁地切換,則使用 v-show 較好;
  • 如果在運行時條件很少改變,則使用 v-if 較好。

v-on

  • 作用:使用 v-on 指令綁定 DOM 事件,並在事件被觸發時執行一些 JavaScript 代碼。

  • 語法: @事件名.修飾符 = “methods中的方法名”

  • 注意: $event 可以傳形參

     <div id="app">
            <!-- v-on.xx事件名='當觸發xx事件時執行的語句' -->
            <!-- 執行一段js語句:可以使用data中的屬性 -->
            <button v-on:click="count += 1">增加 1</button>
            <!-- v-on的簡寫方法 -->
            <button @click="count += 1">增加 1</button>
            <!-- 執行一個方法 -->
            <button @click="add">增加 1</button>
            <!-- 執行一個方法、這種寫法可以傳形參 -->
            <button @click="fn1(count)">執行fn1方法</button>
            <!-- 執行一個方法、這種寫法可以傳形參,特殊的形參$event -->
            <button @click="fn2($event)">執行fn2方法</button>
            <hr>
            <!-- 和v-for結合使用 -->
            <button @click="fn3(index)" v-for="(item, index) in items">執行fn3方法</button>
            <!-- v-on修飾符 如 once: 只執行一次 -->
            <button @click.once="fn4">只執行一次</button>
    
            <p>上面的按鈕被點擊了 {{ count }} 次。</p>
        </div>
        <script src="./vue.js"></script>
        <script>
            new Vue({
                el: '#app',
                data: {
                    count: 0,
                    items: ['a', 'b', 'c']
                },
                methods: {
                    add: function() {
                        this.count += 1;
                    },
                    fn1: function(count) {
                        console.log(count);
                        console.log('fn1方法被執行');
                    },
                    fn2: function(e) {
                        console.log(e);
                        console.log('fn2方法被執行');
                    },
                    fn3: function(index) {
                        console.log(index);
                        console.log('fn3方法被執行');
                    },
                    fn4: function() {
                        console.log('fn4方法被執行了');
                    }
                }
            });
        </script>
    
    
  • 修飾符

    • .once - 只觸發一次回調。
    • .prevent - 調用 event.preventDefault()

簡寫: @事件名.修飾符 = ‘methods中的方法名’

v-for

在這裏插入圖片描述

根據一組數組或對象的選項列表進行渲染。

v-for 指令需要使用 item in items 形式的特殊語法,

items 是源數據數組 /對象

當要渲染相似的標籤結構時用v-for

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>

    <body>
        <div id="app">
            <!-- v-for作用:列表渲染,當遇到相似的標籤結構時,就用v-for去渲染
				v-for="元素 in 容器(數組和對象)"
				v-for="數組中的元素 in data中的數組名"
				v-for="對象中的屬性值 in data中的對象名"
			-->
            <!-- 數組 -->
            <p v-for="item in list">{{item}}</p>
            <hr>
            <p v-for="(item,index) in list">{{item}}----{{index}}</p>
            <!-- (v,i) in 數組
				v:數組中的每個元素
				i:數組中元素的下標
			-->
            <hr>
            <!-- 對象 -->
            <!-- (v,k,i)in 對象
				v:值
				k:鍵
				i:對象中每對key-value的索引 從0開始
				注意: v,k,i是參數名,見名知意即可!
			-->
            <p v-for="value in per">{{value}}</p>
            <hr>
            <p v-for="(value,key) in per">{{value}}----{{key}}</p>
            <hr>
            <p v-for="(value,key,i) in per">{{value}}----{{key}}--{{i}}</p>

        </div>
        <script src="./vue.js"></script>
        <script>
            new Vue({
                el: '#app',
                data: {
                    list: ['a', 'b', 'c'],
                    per: {
                        name: '老王',
                        age: 38,
                        gender: '男'
                    }
                },
                methods: {

                }
            })
        </script>
    </body>

</html>

注意: 在使用v-for時,要把一個唯一值賦值給:key屬性(通常是數組的index或者數據的id)

 <div id="app">

        <!-- v-for 
            key屬性: 值通常是一個唯一的標識
            key是一個可選屬性
            養成好習慣:建議在寫v-for時 設置:key="唯一值"
        -->
        <ul>
            <li v-for="(item,index) in list" :key="index">{{item}}---{{index}}</li>
        </ul>
    </div>
    <script src="./vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                list: ['a', 'b', 'c']
            },
            methods: {

            }
        });
    </script>

v-bind

作用: 可以綁定標籤上的任何屬性。

綁定src和id屬性

  <div id="app">
        <!-- data中的屬性值會替換爲標籤的屬性值 -->
        <img v-bind:src="src" />
        <p v-bind:id="idValue">內容</p>
    </div>
    <script src="./vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                src: './logo.png',
                idValue: 'b'
            }
        });
    </script>

綁定class類名

對象語法和數組語法

對象語法

如果isActive爲true,則返回的結果爲 <div class="active"></div>

 .active {
        color: red;
 }

 <div id="app">
        <div v-bind:class="{active: isActive}">
            hei
        </div>
        <button @click="changeClassName">點擊切換類名</button>
    </div>

  <script src="./vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                isActive: true
            },
            methods: {
                changeClassName: function() {
                    this.isActive = !this.isActive;
                }
            }
        });
    </script>

數組語法

渲染的結果 <div class="active text-danger"></div>

<div v-bind:class="[activeClass, dangerClass]">
    hei
</div>
  <script src="./vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
        	activeClass: 'active',
            dangerClass: 'text-danger'
        }
    });
</script>

綁定style

對象語法和數組語法

對象語法

渲染的結果

 <div id="app">
        <div v-bind:style="{color: redColor, fontSize: font18 + 'px'}">
            文本內容
        </div>
    </div>
    <script src="./vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                redColor: 'red',
                font18: 18
            }
        });
    </script>

數組語法
<div v-bind:style="[color, fontSize]">abc</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            color: {
                color: 'red'
            },
            fontSize: {
                'font-size': '18px'
            }
        }
    });
</script>

簡化語法

<div v-bind:class="{active: isActive}">
</div>
<!-- 可以簡化爲 :,簡化語法更常用 -->
<div :class="{active: isActive}">
</div>

v-model

作用: 表單元素的綁定

特點: 雙向數據綁定

  • 數據發生變化可以更新到界面
  • 通過界面可以更改數據
  • v-model 會忽略所有表單元素的 valuecheckedselected 特性的初始值而總是將 Vue 實例的數據作爲數據來源。應該在 data選項中聲明初始值。

綁定文本框

**效果:**當文本框的值發生變化後,div中的內容也會發生變化

 <div id="app">
        <p>{{message}}</p>
        <input type='text' v-model='message'>
        <hr>
        <!-- v-model其實是語法糖,它是下面這種寫法的簡寫 -->
        <input v-bind:value='message' v-on:input='message = $event.target.value' />

    </div>
    <script src="./vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                message: 'message默認值'
            }
        });
    </script>

綁定多行文本框

 <div id="app">
        <textarea v-model="message">
           我是textarea內的插值表達式 無效 {{str}}
        </textarea>
        <div>{{ message }}</div>
    </div>
    <script src="./vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                message: 'message默認值',
                str: 'str字符串'
            }
        });
    </script>

**注意:**多行文本框中使用插值表達式 無效

綁定複選框

  • 綁定一個複選框

checked是布爾類型的數據

<input type="checkbox" v-model="checked">
<div>{{ checked }}</div>

  • 綁定多個複選框

    此種方式需要input標籤提供value屬性

    v-model綁定的是數組-

 <!-- 多個複選框  : 需要設置value屬性值, v-model綁定的是數組-->
	<div id="app">
        <div>
            <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
            <label for="jack">Jack</label>
            <input type="checkbox" id="john" value="John" v-model="checkedNames">
            <label for="john">John</label>
            <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
            <label for="mike">Mike</label>
            <br>
            <span>Checked names: {{ checkedNames }}</span>
        </div>
    </div>
    <script src="./vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                checkedNames: []
            }
        });
    </script>

  • 綁定單選框

    需要input提供value屬性的值

    <input type="radio" name="sex" value="" v-model="sex"><input type="radio" name="sex" value="" v-model="sex">
    {{sex}}
    <script>
        var vm = new Vue({
           el: '#app',
            data: {
                sex: ''
            }
        });
    </script>
    
    
  • 綁定下拉框
    <div id="app">  
    <!-- 下拉框 -->
            <select v-model="selected">
                <option disabled value="">請選擇</option>
                <option>北京</option>
                <option>上海</option>
                <option>深圳</option>
            </select> <span> 您選擇的是: {{selected}}</span>
    </div>
        <script src="./vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    selected: ''
                }
            });
        </script>
    
    

v-cloak

問題:在使用vue綁定數據的時候,渲染頁面有時會出現變量閃爍,例如

<div id="app" v-cloak>
       <p>{{message}}</p>
   </div>
   <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
   <script>
       var vm = new Vue({
           el: '#app',
           data: {
               message: '我是data中message的數據'
           }
       });
   </script>

效果: 在頁面加載時,有時會在頁面中看到這個:

{{message}}

解決方案: 使用v-cloak

<div id="app" v-cloak>
    <p>{{message}}</p>
</div>

**注意:**要在css代碼部分寫如下代碼

[v-cloak] {
    display: none;
}

這樣:就可以防止也頁面閃爍

v-once

**解決的問題:**只渲染元素和組件一次,隨後的渲染,使用了此指令的元素/組件及其所有的子節點,都會當作靜態內容並跳過,這可以用於優化更新性能。

 <div id="app">
        <p v-once>{{message}}</p>
        <input type="text" v-model="message">
    </div>
    <script src="./vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                message: '我是data中message的屬性的值'
            }
        });
    </script>

當添加v-once的指令所對應的元素, 其數據發生改變時,並不會再一次進行渲染

v-cloak和v-once 不需要表達式, 直接將指令寫在開始標籤中即可

案例-表格展示

  • 效果演示
  • 功能分析
    • 渲染表格
    • 刪除商品
    • 添加商品

渲染表格

目的:動態渲染表格 數據爲Vue實例中data裏面的屬性items:[]

  1. 在data中添加商品信息的數組
  2. v-for渲染列表
  3. 插值表達式渲染數據
<tr v-for="item in items">
                    <td>{{item.id}}</td>
                    <td>{{item.name}}</td>
                    <td>{{item.date}}</td>
                    <td><a href="#">刪除</a></td>
</tr>

 <script src="./vue.js"></script>
    <script>
        // 1. 實例化Vue對象
        // 2. 設置Vue對象的選項
        new Vue({
            el: '#app',
            data: {
                items: [{
                        name: 'LV',
                        date: '2018-8-1'
                    }, {
                        name: 'Lenovo',
                        date: '2018-8-1'
                    }, {
                        name: 'TCL',
                        date: '2018-8-1'
                    }

                ]
            },
            methods: {

            }
        })
    </script>

處理無數據時的渲染

效果: 如果表格中沒有數據,展示頁面中的"沒有品牌數據"

<tr v-if="items.length === 0">
    <td colspan="4">沒有品牌數據</td>
</tr>

刪除商品

效果:點擊每個表格中的刪除按鈕, 當前數據從頁面中移除

  1. 綁定click事件
  2. 取消默認點擊事件
  3. 執行刪除deleItem方法
  4. 將點擊的a所在的tr的位置進行傳遞(目的是找到當前點擊的tr)
  5. 點擊後, 刪除當前tr
<td>
    <!-- 點擊刪除按鈕
1. 取消默認點擊事件
2. 執行刪除deleItem方法
3. 將所點擊的a所在的tr的位置進行傳遞(目的是找到當前點擊的tr)
4. 點擊後, 刪除當前tr
-->
    <a href="#" @click.	prevent="deleItem(index)">刪除</a>
</td>

methods: {
    deleItem: function(index) {
        console.log(index);
        this.items.splice(index, 1);
        console.log(this.items);
    }
}

添加商品

效果:點擊添加按鈕,向商品列表中添加商品信息

  1. 綁定click事件
  2. 在data中添加要綁定的屬性name
  3. v-model綁定name屬性
  4. 點擊按鈕後,將商品信息添加到items數組中
<div class="add">
    品牌名稱:
    <input type="text" v-model="name">
    <input type="button" value="添加" @click="addItem">
</div>

data: {
    name: ''
},
    methods: {
        addItem: function() {
            console.log('添加按鈕被點擊');
            const item = {
                name: this.name,
                date: new Date()
            };
            this.items.unshift(item)
        }
    }

細節處理

  1. 刪除提示框
deleItem: function(index) {
    // console.log(index);
    if (confirm('是否刪除')) {
        this.items.splice(index, 1);
    }
    // console.log(this.items);
}

  1. 添加的數據爲空時的處理

如果文本框爲空, 提示輸入內容

如果文本框不爲空,直接添加

if (this.name.length === 0) {
    alert('請輸入商品信息');
    return;
}
this.items.unshift(item);

當商品信息爲空時,禁用添加按鈕

<div class="add">
    品牌名稱:
    <input type="text" v-model="name">
    <input :disabled="name.length === 0" type="button" value="添加" @click="addItem">
</div>

添加數據成功後,清空文本輸入框

addItem: function() {
    console.log('添加按鈕被點擊');
    const item = {
        name: this.name,
        date: new Date()
    };
    if (this
        .name.length === 0) {
        alert('請輸入商品信息');
        return;
    }
    this.items.unshift(item);
    // 添加完畢 清空文本框
    this.name = '';
}

Vue其他知識點

在這裏插入圖片描述

過濾器

  • 作用:處理數據格式
  • 使用位置:雙花括號插值和 v-bind 表達式 (後者從 2.1.0+ 開始支持)。
  • 分類:局部註冊和全局註冊

1. 局部註冊

  1. 在vm對象的選項中配置過濾器filters:{}
  2. 過濾器的名字: (要過濾的數據)=>{return 過濾的結果}
  3. 在視圖中使用過濾器: {{被過濾的數據 | 過濾器的名字}}
<div id="app">
    <!-- 3. 調用過濾器 -->
    <p>{{ msg | upper | abc }}</p>
</div>
<script src="./vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'kfc'
        },
        // 1. 設置vm的過濾器filters選項
        filters: {
            upper: function(v) {
                // 2. 在過濾器的方法中操作數據並返回結果
                return v.toUpperCase();
            }
        }
    });
</script>

注意: 局部註冊的過濾器只適用於當前vm對象

2. 全局註冊

  1. 在創建 Vue 實例之前定義全局過濾器Vue.filter()
  2. Vue.filter(‘該過濾器的名字’,(要過濾的數據)=>{return 對數據的處理結果});
  3. 在視圖中通過{{數據 | 過濾器的名字}}或者v-bind使用過濾器
<div id="app">
    <!-- 3. 調用過濾器: (msg會自動傳入到toUpper中)-->
    <p>{{msg | toUpper}}</p>
</div>
<script src="./vue.js"></script>
<script>
    // 1. 定義全局過濾器
    Vue.filter('toUpper', (value) => {
        console.log(value);
        // 2. 操作數據並返回
        value = value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
        console.log(value);
        return value;
    });

    new Vue({
        el: '#app',
        data: {
            msg: 'hello'
        },
        methods: {

        }
    });
</script>

注意: 全局註冊的過濾器, 不同的vm對象都可以使用

  1. 過濾器是可以串聯使用的, 比如 {{msg | upper1 | upper2}}
  2. 過濾器是可以傳參數的,比如{{msg | upper1(自己傳的參數)}}

ref操作DOM

  • 解決的問題: 在vue中操作DOM元素
  • 使用步驟:
    1. 給DOM元素設置ref屬性的值
    2. 在Vue中的mounted選項下通過this.$refs.屬性 獲取到要操作的DOM
<div id="app">
    <!-- 1. 給要操作的DOM元素設置ref屬性 -->
    <input type="text" ref="txt">
</div>
<script src="./vue.js"></script>
<script>
    new Vue({
        el: '#app',
        // mounted當頁面加載完畢執行
        mounted() {
            console.log(this.$refs.txt);
            // 2. 用this.$refs.屬性 去操作DOM
            this.$refs.txt.focus();
        },
    });
</script>

自定義指令

  • 使用場景:需要對普通 DOM 元素進行操作,這時候就會用到自定義指令
  • 分類:全局註冊和局部註冊

1. 局部註冊

  1. 在vm對象的選項中設置自定義指令 directives:{}
  2. directives:{‘指令的核心名稱’:{ inserted: (使用指令時的DOM對象) => { 具體的DOM操作 } }}
  3. 在視圖中通過標籤去使用指令
<div id="app">
    <!-- 3. 在視圖中通過標籤去使用指令 -->
    <input v-focus type="text">
</div>

<script src="./vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        // 1. 在vm對象的選項中設置自定義指令 directives:{}

        directives: {
            // 2. directives:{'指令的核心名稱':{ inserted: (使用指令時的DOM對象) => { 具體的DOM操作 } }}
            focus: {
                // 指令的定義
                inserted: function(el) {
                    el.focus();
                }
            }
        }
    });
</script>

2. 全局註冊

1. 在創建 Vue 實例之前定義全局自定義指令Vue.directive()
2. Vue.directive('指令的名稱',{ inserted: (使用指令的DOM對象) => { 具體的DOM操作 } } );
3. 在視圖中通過"v-自定義指令名"去使用指令

<div id="app">
    <!-- 3. 在視圖中通過標籤去使用指令 -->
    <input v-focus type="text">

</div>
<script src="./vue.js"></script>
<script>
    // 全局自定義指令
    // 1.在創建 Vue 實例之前定義全局自定義指令Vue.directive()
    // 2. Vue.directive('指令的核心名稱',{ inserted: (使用指令時的DOM對象) => { 具體的DOM操作 } } );
    Vue.directive('focus', {
        // 當被綁定的元素插入到 DOM 中時,inserted會被調用
        inserted: (el) => {
            // el 就是指令所在的DOM對象
            el.focus();
        }
    });

    var vm = new Vue({
        el: '#app'
    });
</script>

Vue.directive(自定義指令名) 不需要加v- 使用自定義指令時需要加v-

inserted: 當被綁定的元素插入到 DOM 中時,會被調用

計算屬性

  • 計算屬性:是Vue實例的一個選項 computed:{}
  • 作用:在計算屬性中去處理data裏的數據
  • 使用場景:任何複雜邏輯,都應當使用計算屬性
  • 本質: 計算屬性的其實就是一個屬性,用法和data中的屬性一樣,但計算屬性的值是一個帶有返回值的方法
<div id="app">
    <p>{{a}}</p>
    <p>{{b}}</p>
    <!-- <p>{{c=a+b}}</p> -->

    <!-- 現象: data中的屬性c的值依賴於data中的另外兩個屬性a和b
問題:如果邏輯代碼很簡單,可以把表達式直接寫在{{}}中
如果邏輯代碼很複雜, 直接把表達式寫在{{}}中不合適
此時, 就用到了計算屬性
-->
    <!-- 計算屬性的用法和data中的屬性用法一樣 -->
    <p>{{comC}}</p>
    <p>{{comC}}</p>
    <p>{{comC}}</p>

</div>
<script src="./vue.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            a: 0,
            b: 0,
            c: 0
        },
        // 計算屬性
        /*
             * 計算屬性是Vue實例的一個選項
             * 計算屬性的值是一個對象
             * 計算屬性也是屬性,只不過值是帶有返回值的函數
             * 當data中的屬性一發生變化, 會自動調用計算屬性的方法
             */
        computed: {
            comC: function() {
                return this.a + this.b
            }
        }
    });
</script>

computed和methods

  • computed:
  • 一旦data中的數據發生變化,就會觸發計算屬性的方法
  • 會將data中屬性的結果進行緩存,對比緩存中的結果是否發生變化
  • methods: 一調用就會觸發, 和數據的變化與否無關
<div id="app">
    <p>{{fn()}}</p>
    <p>{{fn()}}</p>
    <p>{{fn()}}</p>
    <hr>
    <p>{{comFn}}</p>
    <p>{{comFn}}</p>
    <p>{{comFn}}</p>

</div>
<script src="./vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'abc'
        },
        methods: {
            fn() {
                // 返回一個值
                console.log('fn');
                return new Date();
            }
        },
        computed: {
            comFn() {
                // 計算屬性,如果data中的數據變化,會重新執行,
                console.log('計算屬性');
                return new Date();
            }
        }
    });
</script>

相關工具

JSON-server

說明: 可以快速把一個json文件託管成一個 web 服務器(提供接口)

**特點:**基於Express,支持CORS和JSONP跨域請求,支持GET, POST, PUT和 DELETE 方法

使用:

// 1 安裝json-server工具(只安裝一次即可)
npm i -g json-server
// 2 啓動
// 創建一個目錄server,在該目錄下創建一個json文件,db.json
// 在server目錄下執行
json-server --watch db.json

驗證:

在這裏插入圖片描述

在瀏覽器地址欄中輸入 http://localhost:3000 發起請求、觀察cmd中的變化、觀察瀏覽器中返回的json數據

注意: 直接使用課程包中的db.json文件

也可以改變端口 --port

RESTful:接口規則

1. 說明

  • RESTful是一套接口設計規範
  • 用不同的請求類型發送同樣一個請求標識 所對應的處理是不同的
  • 通過Http請求的不同類型(POST/DELETE/PUT/GET)來判斷是什麼業務操作(CRUD )
  • json-server應用了RESTful規範

2. HTTP方法規則舉例

HTTP方法 數據處理 說明
POST Create 新增一個沒有id的資源
GET Read 取得一個資源
PUT Update 更新一個資源。或新增一個含 id 資源(如果 id 不存在)
DELETE Delete 刪除一個資源

通過標準HTTP方法對資源CRUD:

POST:創建單個資源 (資源數據在請求體中)

POST /brands  

GET:查詢

GET /brands // 獲取所有商品信息
GET /brands/1 // 獲取id爲1的商品信息

PUT:更新單個資源,客戶端提供完整的更新後的資源

PUT /brands/1 // 更新id爲1的商品信息

DELETE:刪除

DELETE /brands/1  //刪除id爲1的商品

Postman:接口測試工具

  • 說明:Postman是一款功能強大的網頁調試與發送網頁HTTP請求的測試工具

在這裏插入圖片描述

Vue中的網絡請求

在Vue.js中發送網絡請求本質還是ajax,我們可以使用插件方便操作。

  1. vue-resource: Vue.js的插件,已經不維護,不推薦使用
  2. axios :不是vue的插件,可以在任何地方使用,推薦

說明: 既可以在瀏覽器端又可以在node.js中使用的發送http請求的庫,支持Promise,不支持jsonp

如果遇到jsonp請求, 可以使用插件 jsonp 實現

  • 發送get請求

    axios.get('http://localhost:3000/brands')
        .then(res => {
        console.log(res.data);
    })
        .catch(err => {
        console.dir(err)
    });
    
    
  • 發送delete請求

    axios.delete('http://localhost:3000/brands/109')
        .then(res => {
        console.log(res.data);
    })
        .catch(err => {
        console.dir(err)
    });
    
    
  • 發送post請求

    axios.post('http://localhost:3000/brands', {name: '小米', date: new Date()})
        .then(res => {
        console.log(res);
    })
        .catch(err => {
        console.dir(err)
    });
    
    
  • jsonp (如果是jsonp請求, 可以使用jsonp 包)

    • 安裝jsonp 包 npm i jsonp
    jsonp('http://localhost:3000/brands', (err, data) => {
        if (err) {
            console.dir(err.msg);
        } else {
            console.dir(data);
        }
    });
    
    

案例-表格展示

  • 效果演示
  • 功能分析
    • 日期格式處理
    • 搜索商品功能
    • 輸入框自動聚焦

日期格式處理

說明:表格中的日期格式需要處理, 這裏使用moment包

分析:把日期數據進行格式處理,將處理後的日期渲染到頁面中->過濾器

  1. 安裝/引入moment包
  2. 全局註冊過濾器
  3. 在過濾器的方法中,使用moment包對data中的日期進行處理
  4. 在視圖中渲染日期的位置使用過濾器
<div id="app">
    <!-- 省略 -->
    <!--在視圖中渲染日期的位置使用過濾器-->
    <td>{{ item.date | fmtDate('YYYY-MM-DD HH:mm:ss') }}</td>

    <!-- 省略 -->
</div>

<!-- 1 導入moment包-->
<script src="./moment.js"></script>
<script>
    // 2 定義全局過濾器
    Vue.filter('fmtDate', (v, fmtString) => {
        // 3 在過濾器的方法中,使用moment包對data中的日期進行處理
        return moment(v).format(fmtString);
    });

    var vm = new Vue({
        // ...
    });
</script>

搜索商品功能

說明: 在搜索輸入框中輸入商品名稱時, 在商品列表中顯示對應的商品

分析: 要渲染的視圖會根據搜索內容的變化而變化-> 計算屬性

  1. 在data中定義屬性 searchValue
  2. 在搜索輸入框中 v-model綁定searchValue
  3. 添加計算屬性:根據搜索的內容 返回搜索的結果數組
  4. 將頁面中遍歷items數組替換爲計算屬性返回的數組
<div id="app">
    <!-- 省略-->
    <div class="add">
        <!--2. 在搜索輸入框中 v-model綁定searchValue-->
        品牌名稱:
        <input type="text" v-model="searchValue" placeholder="請輸入搜索條件">
    </div>
    <!-- 省略-->
    <!-- 4 替換爲計算屬性-->
    <tr v-for="(item,index) in newItems">
        <!-- 省略-->
    <tr v-if="newItems.length===0">
        <td colspan="4">沒有品牌數據</td>
    </tr>
</div>
<script>
    // 省略
    new Vue({
        el: '#app',
        data: {
            // 省略
            // 1. 在data中定義屬性 searchValue
            searchValue: ''
        },
        // 計算屬性
        computed: {
            newItems() {
                // 3. 根據搜索的內容 返回搜索的結果數組
                // filter返回滿足條件的數組
                return this.items.filter((item) => {
                    // item表是數組中的每個元素
                    // 篩選item (判斷item中的name的值是否以searchValue開頭)
                    return item.name.startsWith(this.searchValue);
                });
            }
        },
        // 省略
    });
</script>

輸入框自動聚焦

說明:進入頁面時,添加商品的輸入框自動獲取焦點,等待用戶輸入

  1. 全局自定義指令
  2. 獲取要操作的input,進行DOM操作
  3. 在頁面中使用自定義指令
<div class="add">
    品牌名稱:
    <!-- 3 在頁面中使用自定義指令-->
    <input v-focus type="text" v-model="name">
    <input :disabled="name.length===0" @click="addItem(name)" type="button" value="添加">
</div>

<!--省略-->
<script>

    // 1 定義全局自定義指令-自動聚焦
    Vue.directive('focus', {
        // 2 當被綁定的元素插入到 DOM 中時,inserted會被調用
        inserted: (el) => {
            // el 就是指令所在的DOM對象
            el.focus();
        }
    });
</script>

在案例中使用axios

說明: 使用axios請求server/db.json中的數據

渲染列表

  1. 啓動json-server
  2. 安裝並導入axios
  3. 將items數組清空
  4. 在mounted方法中發送網絡請求
  5. 使用返回的數據
<!-- 引入axios -->
<script src="./axios.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            items: [],
            name: '',
            searchValue: ''
        },
        // 當頁面加載完畢之後執行
        mounted() {
            // 加載列表數據
            this.loadData();
        },
        methods: {
            // 加載列表數據
            loadData() {
                // 加載數據
                axios
                    .get('http://localhost:3000/brands')
                    .then((res) => {
                    this.items = res.data;
                })
                    .catch((err) => {
                    console.log(err);
                });
            },
            // 省略代碼
</script>

添加數據

說明:點擊添加按鈕時,發送post請求向db.json中增加商品數據

將addItem中的代碼進行改寫

addItem: function(name) {
    axios
        .post('http://localhost:3000/brands', {
        name: this.name,
        date: new Date()
    })
        .then((res) => {
        // 判斷響應碼  201  created
        if (res.status === 201) {
            // 添加成功 重新加載列表
            this.loadData();
        } else {
            alert('添加失敗');
        }
    })
        .catch((err) => {
        console.log(err);
    })
}

刪除數據

說明:點擊刪除按鈕時,發送DELETE請求從db.json中刪除商品數據

將deleItem中的代碼進行改寫

deleItem: function(id) {
    // 刪除提示
    if (!confirm('是否確認刪除?')) {
        return;
    }
    axios
        .delete('http://127.0.0.1:3000/brands/' + id)
        .then((res) => {
        if (res.status === 200) {
            // 刪除成功
            this.loadData();
        } else {
            alert('刪除失敗');
        }
    })
        .catch((err) => {
        console.log(err);
    })
},

搜索商品

說明: 根據搜索框中的文本信息 動態發送請求獲取數據

用到了watch選項: 當屬性值發生變化 就執行響應的代碼

// 偵聽器
watch: {
    // 監聽的是data中的屬性searchValue
    searchValue(nValue, oValue) {
        // console.log(newValue, oldValue);
        // 發送異步請求
        axios
            .get('http://127.0.0.1:3000/brands?name=' + nValue)
            .then((res) => {
            this.items = res.data;
        });
    }
}

組件基礎

什麼是組件

**需求:**如果頁面中有多個一樣結構的控件,比如

<div id="app">
    <!-- 頁面中有多個一樣結構的標籤: span+button -->
        <span>{{count1}}</span> <button @click="changeCount1">按鈕</button> <br>
        <span>{{count2}}</span> <button @click="changeCount2">按鈕</button> <br>
        <span>{{count3}}</span> <button @click="changeCount3">按鈕</button> <br>
        <span>{{count4}}</span> <button @click="changeCount4">按鈕</button> <br>
        <span>{{count5}}</span> <button @click="changeCount5">按鈕</button> <br>
</div>
<script src="./vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            count1: 0,
            count2: 0,
            count3: 0,
            count4: 0,
            count5: 0
        },
        methods: {
            changeCount1() {
                this.count1++;
            },
            changeCount2() {
                this.count2++;
            },
            changeCount3() {
                this.count3++;
            },
            changeCount4() {
                this.count4++;
            },
            changeCount5() {
                this.count5++;
            }
        }
    });
</script>

問題:

  1. 代碼重複 冗餘
  2. 不利於維護

解決方案: 使用Vue中一個十分重要的特性-組件

體驗組件的使用

<div id="app">
    <!-- 2. 使用組件 -->
    <span-btn></span-btn>
    <span-btn></span-btn>
    <span-btn></span-btn>
    <span-btn></span-btn>
</div>
<script src="./vue.js"></script>
<script>
    // 註冊全局組件
    Vue.component('span-btn', {
        template: `
<div>
<span>{{count}}</span> 
<button @click="changeCount">按鈕</button>
    </div>
`,
        data() {
            return {
                count: 0
            }
        },
        methods: {
            changeCount() {
                this.count++;
            }
        }
    });

    new Vue({
        el: '#app'
    });
</script>

什麼是組件:

組件系統是 Vue 的另一個重要概念,允許我們使用小型、獨立和通常可複用的組件構建大型應用。

仔細想想,幾乎任意類型的應用界面都可以抽象爲一個組件樹:

例如,你可能會有頁頭、側邊欄、內容區等組件,每個組件又包含了其它的像導航鏈接、博文之類的組件。
在這裏插入圖片描述

  • 組件是可複用的 Vue 實例,且帶有一個名字
  • 組件的選項:
  • 組件與 new Vue 接收相同的選項:例如 datacomputedwatchmethods 以及生命週期鉤子等。
  • 僅有的例外是像 el 這樣根實例特有的選項
  • 另外, 組件也有自己的選項 template components等

組件的特點

  • 組件是一種封裝
  • 組件能夠讓我們複用已有的html、css、js
  • 可複用
  • 是一個特殊的Vue實例
  • 可以任意次數的複用
  • 每用一次組件,就會有一個它的新實例被創建
  • 組件中的data要求必須是一個函數,且需要返回一個對象
  • 組件有自己的作用域
  • template 每個組件模板有且只有一個根元素

建議: 在實際開發中,儘可能使用各種第三方組件

組件的分類和使用

  • **分類:**全局註冊和局部註冊
  • **使用(步驟)😗*1. 註冊組件 2. 通過組件名字使用組件

全局註冊

  1. 使用Vue.component(組件名,組件選項) 進行註冊

    組件名:推薦小寫加減號的命名方式

  2. 用在其被註冊之後的任何 (通過 new Vue) 新創建的 (一個或者多個)Vue 實例

      Vue.component('組件名', {
            // 組件選項: data methods template等(沒有el)
            // data 的值是一個函數, 需要返回一個對象
      });

<div id="app">
    <!-- 2. 使用組件 -->
    <span-btn></span-btn>
    <span-btn></span-btn>
    <span-btn></span-btn>
    <span-btn></span-btn>
</div>
<hr>
<div id="app1">
    <span-btn></span-btn>
    <My-Component></My-Component>
</div>
<hr>
<div id="app2">
    <span-btn></span-btn>

</div>
<hr>
<div id="app3">
    <span-btn></span-btn>
</div>
<script src="./vue.js"></script>
<script>
    // 1. 註冊組件
    // Vue.component('組件名', {
    //     // 組件選項: data methods template等
    // });
    Vue.component('span-btn', {
        // template: 頁面字符串,有且僅有一個根元素
        template: `
<div>
<span>{{count}}</span> 
<button @click="changeCount">按鈕</button>
    </div>
`,
        data() {
            return {
                count: 0
            }
        },
        methods: {
            changeCount() {
                this.count++;
            }
        }
    });

    Vue.component('myComponent', {
        template: `
<div>
<h1>{{num}}</h1> 
<button @click="changeTitle">按鈕</button>
    </div>
`,
        style: './style.css',
        data() {
            return {
                num: 0
            }
        },
        methods: {
            changeTitle() {
                this.num++;
            }
        }
    });

    new Vue({
        el: '#app'
    });

    new Vue({
        el: '#app1'
    });
    new Vue({
        el: '#app2'
    });
    new Vue({
        el: '#app3'
    });
</script>

注意:

  1. 全局組件必須寫在Vue實例創建之前,纔在該根元素下面生效
  2. 在不同的Vue實例中可以使用多個不同的全局組件
  3. 每個組件有自己的作用域

局部註冊

  • 直接在Vue實例裏面通過 components選項進行註冊
  • 對於 components 對象中的每個屬性來說,
  • 其屬性名就是自定義元素的名字,其屬性值就是這個組件的選項對象。
<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>

    <body>
        <div id="app">
            <!-- 2 使用組件 -->
            <com-A></com-A>
            <com-B></com-B>
            <com-C></com-C>
        </div>
        <script src="./vue.js"></script>
        <script>
            // 局部組件的選項
            const comA = {
                template: `<div>{{titleA}}</div>`,
                data() {
                    return {
                        titleA: 'comA中的data裏的titleA'
                    }
                }
            };
            const comB = {
                template: `<div>{{titleB}}</div>`,
                data() {
                    return {
                        titleB: 'comB中的data裏的titleB'
                    }
                }
            };

            const comC = {
                template: `<div>{{titleC}}</div>`,
                data() {
                    return {
                        titleC: 'comC中的data裏的titleC'
                    }
                }
            };

            new Vue({
                el: '#app',
                // 1. 在Vue實例中設置components選項{組件名:組件選項}
                components: {
                    // 在頁面中的組件名:組件選項
                    'comA': comA,
                    'comB': comB,
                    'comC': comC
                }
            });
        </script>
    </body>

</html>

組件嵌套

我們可以在new Vue()實例中使用自定義組件,

也可以在註冊自定義組件時,嵌套另一個自定義組件,也就是父子組件的關係

父子組件-寫法一

<div id="app">
    <!-- 2. 通過組件名使用組件 -->
    <parent-Com></parent-Com>
</div>
<script src="./vue.js"></script>
<script>
    // 1. 註冊全局組件
    Vue.component('childCom', {
        template: `
<div>
<h1>childCom全局組件</h1>
    </div>
`
    });

    Vue.component('parentCom', {
        // 在parentCom中嵌入childCom組件
        // parentCom和childCom屬於父子組件
        // 父組件是parentCom
        // 子組件是childCom
        template: `
<div>
<h1>parentCom全局組件</h1>
<child-Com></child-Com>
    </div>
`
    });

    new Vue({
        el: '#app'
    });
</script>

父子組件-寫法二

<div id="app">
    <!-- 2. 通過組件名使用組件 -->
    <parent-Com></parent-Com>
</div>
<script src="./vue.js"></script>
<script>
    // 1. 局部組件的選項
    const childCom = {
        template: `
<div>
<h1>childCom局部組件</h1>
    </div>
`
    };

    // 在parentCom組件選項中 使用components選項設置其子組件
    // 在template中使用該子組件
    const parentCom = {
        template: `
<div>
<h1>parentCom局部組件</h1>
<child-Com></child-Com>
    </div>
`,
        components: {
            'childCom': childCom
        }
    };

    new Vue({
        el: '#app',
        components: {
            'parentCom': parentCom
        }
    });
</script>

組件通信

父->子(在子組件中使用父組件數據) props : 不可修改 單向數據傳遞

子->父(在父組件中使用子組件數據) 自定義事件!

兄弟組件

組件讓我們提高了代碼的複用性,接下來考慮如何在不同的組件中進行傳值

比如: 父組件有items數組 在子組件中使用父組件中的items數組去渲染列表

父子組件通信

目的: 要在子組件中使用父組件中data中的屬性值

關鍵點:通過Props給子組件傳值

步驟:

  1. 在子組件中通過props聲明自定義屬性title
  2. 註冊局部組件
  3. 使用子組件時,設置props選項, 通過自定義屬性獲取父組件的值
<div id="app">
    <!-- 3. 使用子組件時,通過動態綁定自定義屬性獲取父組件的值 -->
    <component-a :title="msg" :lists="items"></component-a>
</div>

<script src="./vue.js"></script>
<script>
    var ComponentA = {
        // 1. 在子組件中通過props聲明自定義屬性title
        template: `<div>
<h1>{{ title }}</h1>
<ul>
<li  v-for="item in lists">
{{item.name}}
    </li>
    </ul> 
    </div>`,
        // 用來接收外部傳過來的數據
        // 值的傳遞是單向的,內部不要修改props裏變量的值
        props: ['title', 'lists']
    };

    new Vue({
        el: '#app',
        // 目的: 要在子組件中使用父組件的msg的值
        data: {
            msg: 'hello heima',
            items: [{
                'id': 1,
                'name': '小狗'
            }, {
                'id': 2,
                'name': '小貓'
            }, {
                'id': 3,
                'name': '小羊'
            }

                   ]
        },
        // 2. 註冊局部組件
        components: {
            'component-a': ComponentA
        }
    });
</script>

父子組件的傳值有多種方法, 兄弟組件的通信也有自己的寫法

避免混淆,這裏我們先只講父子組件通信的一種寫法

會在後續的案例中會進行講解

組件和模塊

  • 模塊:側重於功能或者數據的封裝
  • 組件:包含了 template、style 和 script,而它的 script 可以由各種模塊組成

鉤子函數

生命週期是指Vue實例或者組件從誕生到消亡經歷的每一個階段,在這些階段的前後可以設置一些函數當做事件來調用。

在這裏插入圖片描述

<body>
  <div id="app">
    <h1>{{message}}</h1>
  </div>
</body>

<script>
  var vm = new Vue({
    el: '#app',
    data: {
      message: 'Vue的生命週期'
    },
    beforeCreate: function() {
      console.group('------beforeCreate創建前狀態------');
      console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //undefined 
      console.log("%c%s", "color:red","message: " + this.message) 
    },
    created: function() {
      console.group('------created創建完畢狀態------');
      console.log("%c%s", "color:red","el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化 
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化
    },
    beforeMount: function() {
      console.group('------beforeMount掛載前狀態------');
      console.log("%c%s", "color:red","el     : " + (this.$el)); //已被初始化
      console.log(this.$el);
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化  
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化  
    },
    mounted: function() {
      console.group('------mounted 掛載結束狀態------');
      console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
    },
    beforeUpdate: function () {
      console.group('beforeUpdate 更新前狀態===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);   
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    updated: function () {
      console.group('updated 更新完成狀態===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el); 
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    beforeDestroy: function () {
      console.group('beforeDestroy 銷燬前狀態===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    destroyed: function () {
      console.group('destroyed 銷燬完成狀態===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);  
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message)
    }
  })
</script>
</html>

前端路由

什麼是單頁應用

單頁應用(single page web application,SPA),是在一個頁面完成所有的業務功能,瀏覽器一開始會加載必需的HTML、CSS和JavaScript,之後所有的操作都在這張頁面完成,這一切都由JavaScript來控制。

單頁應用優缺點

  • 優點
    • 操作體驗流暢
    • 完全的前端組件化
  • 缺點
    • 首次加載大量資源(可以只加載所需部分)
    • 對搜索引擎SEO不友好 -> 服務端渲染
    • 開發難度相對較高

單頁應用的實現原理

前後端分離(後端專注於數據、前端專注於交互和可視化)+前端路由

  • Hash路由

  • 利用URL上的hash,當hash改變不會引起頁面刷新,所以可以利用 hash 值來做單頁面應用的路由,

  • 並且當 url 的 hash 發生變化的時候,可以觸發相應 hashchange 回調函數。

  • 模擬實現:

<a href="#/">首頁</a>
<a href="#/users">用戶管理</a>
<a href="#/rights">權限管理</a>
<a href="#/goods">商品管理</a>
<div id="box">
    </div>
<script>
    var box = document.getElementById('box');
window.onhashchange = function() {
    // #/users
    var hash = location.hash;
    hash = hash.replace('#', '');
    switch (hash) {
        case '/':
            box.innerHTML = '這是首頁';
            break;
        case '/users':
            box.innerHTML = '這是用戶管理';
            break;
        case '/rights':
            box.innerHTML = '這是權限管理';
            break;
    }
};
</script>

  • History路由

  • History 路由是基於 HTML5 規範,在 HTML5 規範中提供了 history.pushState || history.replaceState 來進行路由控制

vue-router

Vue-Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,讓構建單頁面應用變得易如反掌

實現根據不同的請求地址 而顯示不同的組件

快速體驗

  1. 導入vue和vue-router

  2. 設置HTML中的內容

    <!-- router-link 最終會被渲染成a標籤,to指定路由的跳轉地址 -->
    <router-link to="/users">用戶管理</router-link>
    
    <!-- 路由匹配到的組件將渲染在這裏 -->
    <router-view></router-view>
    
    
  3. 創建組件

    // 創建組件
    // 組件也可以放到單獨的js文件中
    var Home = {
        template: '<div>這是Home內容</div>'
    };
    var Users = {
        template: '<div>這是用戶管理內容</div>'
    };
    
    
  4. 配置路由規則

    // 配置路由規則
    var router = new VueRouter({
        routes: [
            { name: 'home', path: '/', component: Home },
            { name: 'users', path: '/users', component: Users }
        ]
    });
    
    
  5. 設置vue的路由選項

    var vm = new Vue({
        el: '#app',
        router
    });
    
    

動態路由

場景: 不同的path對應同一個組件

注意: 變化的路由 改成 :參數

此時可以通過路由傳參來實現,具體步驟如下:

  1. 路由規則中增加參數,在path最後增加 :id

    { name: 'users', path: '/users/:id', component: Users },
    
    
  2. 通過 傳參,在路徑上傳入具體的值

    <router-link to="/users/120">用戶管理</router-link>
    
    
  3. 在組件內部可以使用,this.$route 獲取當前路由對象

    var Users = {
        template: '<div>這是用戶管理內容 {{ $route.params.id }}</div>',
        mounted() {
            console.log(this.$route.params.id);
        }
    };
    
    

路由嵌套

在這裏插入圖片描述

如果存在組件嵌套,就需要提供多個視圖容器

同時,router-link和router-view 都可以添加類名、設定樣式

<div id="app">
    <!--router-link運行後會自動變成a標籤-->
    <nav>
        <router-link to="/top">熱點</router-link>
        <router-link to="/tech">教育</router-link>
        <router-link to="/soc">社會</router-link>
        <router-link to="/mus">音樂</router-link>
        <router-link to="/te">體育</router-link>
    </nav>

    <!--容器-->
    <router-view class="box">
    </router-view>
</div>

<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
    // 組件:

    // 熱點
    var Top = {
        template: '<h1>Top</h1>'
    };

    // 體育:帶參數的二級路由
    var Te = {
        template: `
<div>
<ul>
<li><router-link to='/te/basb/10'>籃球</router-link></li>
<li><router-link to='/te/fotb/10'>足球</router-link></li>
<li><router-link to='/te/mbal/10'>好多球</router-link></li>
    </ul>
<router-view class="box"></router-view>
    </div>
`
    };

    // 教育:使用了data
    var Tech = {
        data: function() {
            return {
                name: "luck",
                age: 10,
                fn: function() {
                    alert(1);
                }
            }
        },
        template: `
<div>
<p @click="fn">{{name}}</p>
<p>{{age}}</p>
    </div>
`
    }

    // 社會
    var Soc = {
        template: '<h1>soc</h1>'
    };


    // 音樂:不帶參數的二級路由
    var Mus = {
        // template: '<h1>mus</h1>'
        template: `
<div>
<ul>
<li><router-link to='/mus/pop'>流行</router-link></li>
<li><router-link to='/mus/tra'>古典</router-link></li>
<li><router-link to='/mus/roc'>搖滾</router-link></li>
    </ul>
<router-view class="box"></router-view>
    </div>
`
    };

    // 音樂:二級路由的視圖
    var Pop = {
        template: '<h3>mus下的pop模塊</h3>'
    };

    // 體育:二級路由的視圖
    var Ball = {
        //路由參數 $route.params
        template: "<h3>{{$route.params}}</h3>"
    };

    // 配置路由
    var routes = [
        // 熱點
        {
            path: '/top',
            component: Top
        },
        // 教育
        {
            path: '/tech',
            component: Tech
        },
        // 社會
        {
            path: '/soc',
            component: Soc
        }, {
            path: '/mus',
            component: Mus,
            //子路由配置
            children: [{
                path: 'pop',
                component: Pop,
            }]
        },
        // 體育
        {
            path: '/te',
            component: Te,
            children: [{ // /te/形參/10
                path: ':cate/10',
                component: Ball
            }]
        },

        //重定向:默認或者404界面 
        {
            path: '*',
            redirect: '/top'
        }
    ];

    // 實例化路由
    var router = new VueRouter({
        // routes : routes
        routes
    });

    // 實例化vue
    var vue = new Vue({
        el: '#app',
        // router : router
        router
    });
</script>

過渡和動畫

基本用法就是給我們需要動畫的標籤外面嵌套transition標籤 ,並且設置name屬性

Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應用過渡效果。

  • 在 CSS 過渡和動畫中自動應用 class
  • 可以配合使用第三方 CSS 動畫庫,如 Animate.css

在 CSS 過渡和動畫中自動應用 class

Vue 提供了 transition 的封裝組件,在下列情形中,可以給任何元素和組件添加進入/離開過渡

// v要替換成transition組件的name屬性值
v-enter:定義進入過渡的開始狀態。
v-enter-active:定義進入過渡生效時的狀態。
v-enter-to: 2.1.8版及以上 定義進入過渡的結束狀態。
v-leave: 定義離開過渡的開始狀態。
v-leave-active:定義離開過渡生效時的狀態。
v-leave-to: 2.1.8版及以上 定義離開過渡的結束狀態。

示例:

<style>
    .box {
        position: absolute;
        left: 0;
        top: 50px;
        width: 100px;
        height: 100px;
        background-color: red;
    }
    .slide-enter, .slide-leave-to {
        left: 200px;
        opacity: 0;
    }
    .slide-enter-active, .slide-leave-active {
        transition: all 2s;
    }
    .slide-enter-to, .slide-leave {
        left: 0px;
        opacity: 1;
    }
</style>
<button @click="isShow = !isShow">顯示/隱藏</button>

<transition name="slide"> 
    <div v-show="isShow" class="box"></div>
</transition>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            isShow: true
        }
    });
</script>

自定義過渡動畫的類名

可以通過transition組件自定義過渡動畫的類名,可以方便結合第三方的動畫庫使用,比如:animate.css

// transition組件的屬性 
enter-class
    enter-active-class
        enter-to-class (2.1.8+)
leave-class
    leave-active-class
        leave-to-class (2.1.8+)

示例:

<button @click="isShow = !isShow">toggle</button>
<transition 
            enter-active-class="animated fadeIn"
            leave-active-class="animated fadeOut">
    <div v-show="isShow">hello</div>
</transition>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            isShow: true
        }
    });
</script>

vue-cli(腳手架)

爲什麼要用vue-cli

可以快速創建vue項目結構,而不需要我們一點點的去創建/管理項目所需要的各種文件夾/文件

什麼是vue-cli

vue-cli是npm包

vue-cli 提供一個官方命令行工具,可用於快速搭建大型單頁應用。

使用vue-cli

# 安裝 Vue CLI 腳手架
# 如果已經安裝過則不需要
# 這裏安裝的是最新版本 3版本
npm install -g @vue/cli

# 執行vue --verson查看是否安裝成功,
# 顯示vue的版本,就是安裝成功了
vue -V

# 如果仍然要使用vue-cli 2版本的指令 需要安裝一個橋接工具
npm install -g @vue/cli-init

# 使用腳手架工具初始化你的項目
# webpack-simple是一種工程模板
vue init webpack-simple 項目名稱

# 進入你初始化好的項目
cd 項目路徑

# 安裝項目模板所需要的依賴
npm i

# 啓動開發模式
# 或者 npm start
npm run dev

運行npm run dev後,會在瀏覽器中看到如下效果:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WfpC6Jgg-1578997873077)(./assets/1534009067048.png)]

項目目錄說明

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vow3ngGA-1578997873077)(./assets/1534009729744.png)]

  • node_modules 項目依賴包
  • src 項目核心文件(項目核心代碼都放在這個文件夾下)!!!
    • assets 靜態資源(樣式類文件,如css、less、sass以及外部的js文件)
    • App.vue 根組件,所有頁面都是在App.vue下進行切換的
      • 也可以理解爲所有的路由也是App.vue的子組件
    • main.js 入口文件:主要作用是初始化vue實例並使用需要的插件。
  • .babelrc babel配置參數
  • .editorconfig 代碼格式
  • .gitignore git忽略文件
  • index.html 項目的首頁
  • package-lock.json
  • package.json
  • README.md 項目說明
  • webpack.config.js webpack配置文件

注意:

一個vue頁面通常由三部分組成:模板(template)、js(script)、樣式(style)

我們關心的重點是src中的文件夾

單文件組件

說明:

  1. *.vue 文件,是一個自定義的文件類型,用類似HTML的語法描述一個Vue組件。
  2. 每個.vue文件包含三種類型的頂級語言塊 ,

template 部分

  • 代表它的 html 結構
  • 必須在裏面放置一個 html 標籤來包裹所有的代碼
  • 我們在其他地方寫好了一個組件,然後就可以在當前template中引入

script 部分

export default {
    // 這裏寫你的代碼,如
    el:,
    data:,
    props:
    // 省略
};

style 部分

就是針對我們的 template 裏內容出現的 html 元素寫一些樣式

注意: vue-cli的作用就是讓我們把精力放在業務編碼上,一切準備的工作交給vue-cli去做

之後我們可以直接使用vue-cli去做案例或者項目

Vue案例

講完了Vue基礎知識和vue-cli工具

我們利用所講知識完成一個簡單的案例–英雄列表

目的:

  1. 熟悉vue-router的使用
  2. 熟悉單文件組件的使用
  3. 熟悉vue-cli的使用

案例演示

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-N0gcotgS-1578997873078)(./assets/1536664536268.png)]

功能拆分

  1. vue-cli創建項目hero
  2. 路由配置
  3. 英雄列表
    • 列表展示
    • 添加英雄
    • 編輯英雄
    • 刪除英雄

項目起步

利用腳手架vue-cli生成項目結構

# 安裝 Vue CLI 腳手架
# 如果已經安裝過則不需要!
npm i -g @vue/cli

# 使用腳手架工具初始化你的項目
vue init webpack-simple 項目名稱

# 進入你初始化好的項目
cd 項目路徑

#安裝項目所需依賴
npm i

# 啓動開發模式
# 或者 npm start
npm run dev

調整模板

將vue-cli生成的文件中無用的代碼進行刪除

首頁展示

步驟分析:

  1. 導入素材: 將課程包中index.html的標籤結構放在App.vue的template中
  2. 安裝[email protected]: index.html使用了bootstrap和index.css,在vue項目中安裝和導入
  3. 在main.js中引入bootstrap和index.css
  4. 修改webpack配置: 程序報錯、無法識別字體文件, 需要在webpack.config.js中進行配置

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eAHakbGK-1578997873078)(./assets/1534220243520.png)]

代碼演示

1. 導入素材

2. 安裝bootstrap,導入index.css

  1. npm i [email protected]
  2. 將課程包中的css文件夾放在assets中

3. 引入bootstrap和index.css

main.js

import Vue from 'vue'
import App from './App.vue'

import "../node_modules/bootstrap/dist/css/bootstrap.css";
import "./assets/css/index.css";

new Vue({
    el: '#app',
    render: h => h(App)
})

4. 修改webpack.config.js配置

{
    test: /.(ttf|woff2|woff|eot)$/,
        loader: 'file-loader',
            options: {
                name: '[name].[ext]?[hash]'
            }
}

接下來我們用單文件組件的方式將頁面文件提取爲不同的組件

提取公共頭部組件

步驟分析:

1. 新建AppHeader.vue

2. 修改App.vue的template

3. 使用AppHeader.vue

代碼演示:

  1. 在src下新建components/AppHeader.vue
  2. 找到頭部的標籤結構,將其放置於AppHeader.vue的template中

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XFiv0Kxk-1578997873078)(./assets/1534222080131.png)]

  1. 在App.vue中引入並使用AppHeader.vue組件
    1. 引入AppHeader.vue組件
    2. 註冊AppHeader.vue組件
    3. 使用AppHeader.vue組件

AppHeader.vue

<template>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">CRUD</a>
</div>
</div>
</nav>
</template>

<script>
    export default {

}
</script>
<style>

</style>

App.vue

<template>
    <div>
    <!-- 3 使用AppHeader.vue組件 -->
<AppHeader></AppHeader>
<!--後面的標籤結構 省略..-->
</div>
</template>

<script>

    // 1. 導入AppHeader.vue組件
    import AppHeader from './components/AppHeader';


export default {
    name: 'app',
    data () {
        return {

        }
    },
    // 2. 註冊AppHeader組件
    components:{
        // 注意命名
        AppHeader:AppHeader
    }
}
</script>

<style lang="scss">

    </style>

提取側邊欄組件

步驟分析

1. 新建AppSilder.vue

2. 修改App.vue的template

3. 使用AppSilder.vue

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0CsCZQtp-1578997873079)(./assets/1534223067628.png)]

提取英雄列表組件

新建AppList.vue,並將App.vue中的英雄列表的頁面標籤提取到AppList.vue中

步驟分析

1. 新建AppList.vue

2. 修改App.vue的template

3. 使用AppList.vue

Vue-Router使用

使用 Vue-Router 實現頁面導航管理

步驟分析及代碼演示

  1. 安裝路由模塊
npm i vue-router

  1. main.js 中加載
...
import VueRouter from 'vue-router' // 加載路由模塊

// 註冊到 Vue 中纔可以使用
Vue.use(VueRouter)

// ...

  1. main.jsnewVueRouter 實例,並掛載到根實例的 router 選項中
// ...

// 配置路由表
const appRouter = new VueRouter({
    routes: [
    ]
})

// ...

new Vue({
    el: '#app',
    render: h => h(App),
    // 配置實例選項 router 爲你在上面 new 出來的 VueRouter 實例對象
    router: appRouter
});

  1. 配置路由表
// ...
// 配置路由表
const appRouter = new VueRouter({
    // routes 選項用來配置路由表
    // 當請求 /xxx 的時候,渲染 xxx 組件
    // routes 是一個數組,數組中存儲一些固定格式的對象
    // 對象 path 表示請求的路徑
    // 對象的 component 用來指定當你請求 path 路徑的時候,渲染該組件
    // 現在的問題是?匹配到 path 的時候,組件往哪裏渲染?
    // 在你的根組件預留一個路由的出口,用來告訴路由到匹配到某個 path 的時候,把該組件渲染到哪裏
    routes: [
        {
            path: '/foo',
            component: {
                template: `<div>foo 組件啊</div>`
            }
        },
        {
            path: '/bar',
            component: {
                template: `<div>bar 組件啊</div>`
            }
        }
    ]
});
// ...

  1. src/App.vue 組件中設置路由出口(告訴路由往哪裏渲染 path 匹配到的組件)
<template>
    <div id="app">
        <AppHeader></AppHeader>
        <div class="container-fluid">
            <div class="row">
                <AppSidebar></AppSidebar>
                <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                    <!-- <AppList></AppList> -->
                    <!--
<router-view></router-view> 組件標籤是給路由看的,默認啥都沒有
它不是固定的,它標識路由出口標記
當路由匹配到 path xxx 的時候,會將 router-view 替換到我們在路由表中配置好的組件
-->
                    <router-view></router-view>
                </div>
            </div>
        </div>
    </div>
</template>
...

  1. 在側邊欄 src/components/AppSidebar.vue 組件中 增加兩個導航鏈接用來導航 foobar
<template>
    <div class="col-sm-3 col-md-2 sidebar">
        <ul class="nav nav-sidebar">
            <li class="active"><a href="#">英雄管理 <span class="sr-only">(current)</span></a></li>
            <li><a href="#">用戶管理</a></li>
            <li><a href="#">商品管理</a></li>
            <li><a href="#">訂單管理</a></li>
            <!--
導航鏈接要以 # 開頭,後面跟你在路由表中配好的 path 路徑
-->
            <li><a href="#/foo">Go Foo</a></li>
            <li><a href="#/bar">Go Bar</a></li>
        </ul>
    </div>
</template>

<script></script>

<style></style>

將路由導航到 .vue 組件

src/components/Foo.vue:

<template>
    <div>
        Foo 組件
    </div>
</template>

<script></script>
<style></style>

src/components/Bar.vue:

<template>
    <div>
        Bar 組件
    </div>
</template>

<script></script>
<style></style>

src/main.js:

// ...
// ...
import Foo from './components/Foo'
import Bar from './components/Bar'
import HeroList from './components/HeroList'

// ...
// ...

// 配置路由表
const appRouter = new VueRouter({
    routes: [
        {
            path: '/foo',
            component: Foo
            // component: {
            //   template: `<div>foo 組件啊</div>`
            // }
        },
        {
            path: '/bar',
            component: Bar
        },
        {
            path: '/heroes',
            component: HeroList
        }
    ]
});

// ...

提取路由模塊router.js

將main.js中路由相關的代碼提取到router.js中

新建router.js

import Vue from 'vue';

// 1. 導入路由
import VueRouter from 'vue-router';

// 導入組件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';


// 註冊插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);

// 2. 創建路由對象,配置路由規則
const router = new VueRouter({
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        { name: 'home', path: '/', redirect: { name: 'heroes' } },
        // 路由規則
        { name: 'heroes', path: '/heroes', component: AppList },
        { name: 'bar', path: '/bar', component: Bar },
        { name: 'foo', path: '/foo', component: Foo }
    ]
});

// 3 導出模塊
export default router;

main.js

import Vue from 'vue'
import App from './App.vue'

// import Foo from './components/Foo'
// import Bar from './components/Bar'
// import AppList from './components/AppList'

// import VueRouter from 'vue-router' // 加載路由模塊
// // 註冊到 Vue 中纔可以使用
// Vue.use(VueRouter);

// 1 導入路由對象
import router from './router';

import "../node_modules/bootstrap/dist/css/bootstrap.css";
import "./assets/css/index.css";


new Vue({
    el: '#app',
    render: h => h(App),
    // 配置實例選項 router 爲你在上面 new 出來的 VueRouter 實例對象
    // router: appRouter
    router
});

配置導航菜單

將AppSilder.vue中的a標籤改成router-link

AppSilder.vue

<template>
    <div class="col-sm-3 col-md-2 sidebar">
        <ul class="nav nav-sidebar">
            <!-- <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
<li><a href="#/heroes">Reports</a></li>
    <li><a href="#">Analytics</a></li>
        <li><a href="#">Export</a></li>
            <li><a href="#/foo">Go Foo</a></li>
                <li><a href="#/bar">Go Bar</a></li> -->
                    <router-link tag="li" to="/heroes">
                        <a>英雄列表</a>
</router-link>
<router-link tag="li" to="/bar">
    <a>武器列表</a>
</router-link>
<router-link tag="li" to="/foo">
    <a>裝備列表</a>
</router-link>
</ul>
</div>
</template>

<script>
    export default {

}
</script>
<style>

</style>

API-Server

接下來要實現具體的功能, 首先是英雄列表展示,其中的數據要來源於服務器

我們使用json-server快速啓動api服務器 監聽課程包中的db.json

可以使用postman測試接口

英雄列表數據渲染

利用axios發送請求獲取英雄列表的數據渲染到AppList.vue的template中

步驟分析:

  1. 啓動json-server
  2. 在安裝並在AppList.vue中導入axios
  3. 在data選項中添加屬性list:[]
  4. 將發送請求的方法寫在methods中 loadData
  5. 在created鉤子函數中調用loadData方法
  6. 將list中的數據渲染到template中的相應位置

代碼演示:

AppList.vue

<template>
    <div>
        <h2 class="sub-header">Hero List</h2>
        <a class="btn btn-success" href="add.html">Add</a>
        <div class="table-responsive">
            <table class="table table-striped">
                <!-- <thead>
<tr>
<th>#</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>1,001</td>
<td>Lorem</td>
<td>ipsum</td>
<td>dolor</td>
<td>sit</td>
<td>
<a href="edit.html">edit</a>
&nbsp;&nbsp;
<a href="javascript:window.confirm('Are you sure?')">delete</a>
</td>
</tr>
</tbody> -->
                <thead>
                    <tr>
                        <th>#</th>
                        <th>名稱</th>
                        <th>性別</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr :key="item.id" v-for="(item, index) in list">
                        <td>{{ index + 1 }}</td>
                        <td>{{ item.name }}</td>
                        <td>{{ item.gender }}</td>
                        <td>

                            <a href="edit.html">edit</a>
                            &nbsp;&nbsp;
                            <a href="javascript:window.confirm('Are you sure?')">delete</a>            </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</template>

<script>
    import axios from 'axios';

    export default {
        data(){
            return {
                list:[]
            }
        },
        created(){
            this.loadData();
        },
        methods:{
            loadData(){
                axios.get('http://localhost:3000/users')
                    .then((res)=>{
                    console.log(res);
                    const {status,data} = res;
                    if (status == 200) {
                        this.list = data;
                    }

                })
            }
        }
    }
</script>
<style>

</style>


實現效果:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Nml70Xk1-1578997873080)(./assets/1534228452013.png)]

刪除功能

點擊英雄列表中每個英雄信息後面的刪除按鈕,可以刪除當前英雄數據

步驟分析

  1. 找到刪除按鈕, 綁定click事件
  2. 將要刪除的英雄的id傳給刪除方法
  3. 在methods中實現刪除方法
    1. 獲取當前英雄的id
    2. 提示用戶是否刪除
    3. 如果是, 則調用axios.delete方法刪除數據
      1. 刪除成功, 重新渲染列表

代碼演示

AppList.vue

<template>
    <div>
        <h2 class="sub-header">Hero List</h2>
        <a class="btn btn-success" href="add.html">Add</a>
        <div class="table-responsive">
            <table class="table table-striped">

                <thead>
                    <tr>
                        <th>#</th>
                        <th>名稱</th>
                        <th>性別</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr :key="item.id" v-for="(item, index) in list">
                        <td>{{ index + 1 }}</td>
                        <td>{{ item.name }}</td>
                        <td>{{ item.gender }}</td>
                        <td>
                            <a href="edit.html">edit</a>
                            &nbsp;&nbsp;
                            <!-- <a href="javascript:window.confirm('Are you sure?')">delete</a>             -->
                            <a href="#" @click.prevent="handleDelete(item.id)">delete</a>

                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</template>

<script>
    import axios from 'axios';

    export default {
        data(){
            return {
                list:[]
            }
        },
        created(){
            this.loadData();
        },
        methods:{
            loadData(){
                axios.get('http://localhost:3000/users')
                    .then((res)=>{
                    console.log(res);
                    const {status,data} = res;
                    if (status == 200) {
                        this.list = data;
                    }

                })
            },

            handleDelete(id) {
                // 刪除提示
                if (!confirm('是否確認刪除?')) {
                    return;
                }
                axios
                    .delete(`http://localhost:3000/users/${id}`)
                    .then((res) => {
                    if (res.status === 200) {
                        // 刪除成功,重新渲染列表
                        this.loadData();
                    } else {
                        alert('刪除失敗');
                    }
                })
                    .catch((err) => {
                    console.log(err);
                });
            }
        }
    }
</script>
<style>

</style>


添加功能-頁面

點擊添加按鈕 進入到添加的組件,輸入新英雄信息,點擊確定, 回到列表頁渲染新數據

我們先讓添加的頁面顯示出來

步驟分析

  1. 新建add.vue組件
  2. 將課程包中的add.html中添加的頁面標籤放置在add.vue中
  3. 修改路由router.js
    1. 導入add.vue
    2. 註冊add.vue
    3. 使用add.vue
  4. 根據效果調整add.vue中的標籤

代碼演示

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Ja8XgaAO-1578997873081)(./assets/1534229426837.png)]

add.vue

<template>
    <div>
        <h2 class="sub-header">Add Hero</h2>
        <form>
            <div class="form-group">
                <label for="exampleInputEmail1">Email address</label>
                <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
            </div>
            <div class="form-group">
                <label for="exampleInputPassword1">Password</label>
                <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
            </div>
            <div class="form-group">
                <label for="exampleInputFile">File input</label>
                <input type="file" id="exampleInputFile">
                <p class="help-block">Example block-level help text here.</p>
            </div>
            <div class="checkbox">
                <label>
                    <input type="checkbox"> Check me out
                </label>
            </div>
            <button type="submit" class="btn btn-success">Submit</button>
        </form>
    </div>
</template>

<script>
    export default {

    }
</script>

<style>

</style>


router.js

import Vue from 'vue';

// 1. 導入路由
import VueRouter from 'vue-router';

// 導入組件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';
import Add from './components/add.vue';


// 註冊插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);

// 2. 創建路由對象,配置路由規則
const router = new VueRouter({
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        { name: 'home', path: '/', redirect: { name: 'heroes' } },
        // 路由規則
        { name: 'heroes', path: '/heroes', component: AppList },
        { name: 'bar', path: '/bar', component: Bar },
        { name: 'foo', path: '/foo', component: Foo },
        { name: 'add', path: '/add', component: Add }

    ]
});

// 3 導出模塊
export default router;

AppList

<template>
    <div>
        <h2 class="sub-header">Hero List</h2>
        <!-- <a class="btn btn-success" href="add.html">Add</a> -->
        <!-- 注意動態綁定屬性 : -->
        <router-link :to="{name:'add'}">添加</router-link>
        <div class="table-responsive">
            <!--省略-->
        </div>
    </div>
</template>

// 省略


add.vue

<template>
    <div>
        <div>
            <h2 class="sub-header">Add Hero</h2>
            <form>
                <div class="form-group">
                    <label for="name">英雄名稱</label>
                    <input type="text" class="form-control" id="name" placeholder="Name">
                </div>
                <div class="form-group">
                    <label for="sex">英雄性別</label>
                    <input type="text" class="form-control" id="sex" placeholder="Sex">
                </div>
                <button type="submit" class="btn btn-success">Submit</button>
            </form>
        </div>
    </div>
</template>
<!-- 省略-->

添加功能-功能實現

有了頁面,接下來我們實現添加的功能

步驟分析:

  1. 綁定文本框
  2. 添加按鈕註冊事件
  3. 發送請求

代碼演示:

add.vue

<template>
    <div>  
        <h2 class="sub-header">Add Hero</h2>
        <form>
            <div class="form-group">
                <label for="name">英雄名稱</label>
                <input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
            </div>
            <div class="form-group">
                <label for="sex">英雄性別</label>
                <input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
            </div>
            <button @click.prevent="handleAdd" type="submit" class="btn btn-success">Submit</button>
        </form>
    </div>
</template>

<script>

    import axios from 'axios'
    export default {
        data() {
            return {
                // 綁定到表單元素
                formData: {
                    name: '',
                    gender: ''
                }
            }
        },
        methods:{
            handleAdd() {
                axios
                    .post('http://localhost:3000/users', this.formData)
                    .then((res) => {
                    const { status, data } = res;
                    if (status === 201) {
                        // 判斷添加是否成功
                        // 添加成功,跳轉到英雄列表
                        this.$router.push({ name: 'heroes' });
                    } else {
                        alert('添加失敗');
                    }
                })
            }
        }
    }
</script>

<style>

</style>


編輯功能-頁面

編輯的頁面和添加的頁面很像

步驟分析

  1. 新建edit.vue組件
  2. 將add.vue中的代碼copy到edit.vue中進行修改
  3. 修改路由router.js
    1. 導入edit.vue
    2. 註冊edit.vue
    3. 使用edit.vue
  4. 在AppList中設置router-link 動態參數

代碼演示

edit.vue

<template>
    <div>

        <h2 class="sub-header">Edit Hero</h2>
        <form>
            <div class="form-group">
                <label for="name">英雄名稱</label>
                <input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
            </div>
            <div class="form-group">
                <label for="sex">英雄性別</label>
                <input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
            </div>
            <button  type="submit" class="btn btn-success">Submit</button>
        </form>
    </div>
</template>

<script>

    import axios from 'axios'
    export default {
        data() {
            return {
                // 綁定到表單元素
                formData: {
                    name: '',
                    gender: ''
                }
            }
        },
        methods:{

        }
    }
</script>

<style>

</style>


router.js

import Vue from 'vue';

// 1. 導入路由
import VueRouter from 'vue-router';

// 導入組件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';
import Add from './components/add.vue';
import Edit from './components/edit.vue';

// 註冊插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);

// 2. 創建路由對象,配置路由規則
const router = new VueRouter({
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        { name: 'home', path: '/', redirect: { name: 'heroes' } },
        // 路由規則
        { name: 'heroes', path: '/heroes', component: AppList },
        { name: 'bar', path: '/bar', component: Bar },
        { name: 'foo', path: '/foo', component: Foo },
        { name: 'add', path: '/add', component: Add },
        { name: 'edit', path: '/edit/:id', component: Edit }
    ]
});

// 3 導出模塊
export default router;

AppList

<!-- <a href="edit.html">edit</a> -->
<router-link :to="{name:'edit',params:{id:item.id}}">編輯</router-link>

編輯功能-功能實現

步驟分析:

  1. 進入編輯頁面,顯示當前要編輯的英雄
    1. 獲取url上的id,created()
    2. 發送請求獲取數據
    3. 綁定文本框
  2. 點擊Submit按鈕,實現更新功能

代碼演示

edit.vue

<template>
    <div>
        <h2 class="sub-header">Edit Hero</h2>
        <form>
            <div class="form-group">
                <label for="name">英雄名稱</label>
                <input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
            </div>
            <div class="form-group">
                <label for="sex">英雄性別</label>
                <input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
            </div>
            <button @click.prevent="handleEdit" type="submit" class="btn btn-success">Submit</button>
        </form>
    </div>
</template>

<script>

    import axios from 'axios';

    // 1. 進入編輯頁面,顯示當前要編輯的英雄
    // 1.1 獲取url上的id,created()
    // 1.2 發送請求獲取數據
    // 1.3 綁定文本框

    // 2. 點擊Submit按鈕,實現更新功能

    export default {
        data() {
            return {
                formData: {
                    name: '',
                    gender: ''
                },
                // 獲取url上的id,默認-1
                heroId: -1
            }
        },
        // 組件創建完畢
        created() {
            // 獲取路由參數
            this.heroId = this.$route.params.id;
            console.log(this.heroId);

            // 調用 獲取英雄對象的方法
            this.loadData();
        },
        methods: {
            // 根據id,獲取英雄對象
            loadData() {
                axios
                    .get(`http://localhost:3000/users/${this.heroId}`)
                    .then((res) => {
                    if (res.status === 200) {
                        this.formData = res.data;
                    }
                });
            },
            handleEdit() {
                axios
                    .put(`http://localhost:3000/users/${this.heroId}`, this.formData)
                    .then((res) => {
                    if (res.status === 200) {
                        this.$router.push({ name: 'heroes' });
                    } else {
                        alert('修改失敗');
                    }
                });
            }
        }
    };
</script>

<style>

</style>


當前選中導航的樣式

選中某個導航時,其樣式和其他的不同, 爲active的樣式

參考文檔

router.js

添加 linkActiveClass: ‘active’,全局配置

// 省略
const router = new VueRouter({
    linkActiveClass: 'active',
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        { name: 'home', path: '/', redirect: { name: 'heroes' } },
        // 路由規則
        { name: 'heroes', path: '/heroes', component: AppList },
        { name: 'bar', path: '/bar', component: Bar },
        { name: 'foo', path: '/foo', component: Foo },
        { name: 'add', path: '/add', component: Add },
        { name: 'edit', path: '/edit/:id', component: Edit }
    ]
});
// 省略

全局配置axios

axios請求在多個組件中都要使用,

所以, 可以考慮給Vue實例添加axios選項,

這樣 所有的組件都可以使用

main.js

// 省略--

// 導入axios
import axios from 'axios';
// 配置所有Vue的實例都具有$http這個成員
Vue.prototype.$http = axios;

new Vue({
    el: '#app',
    render: h => h(App),
    // 配置實例選項 router 爲你在上面 new 出來的 VueRouter 實例對象
    // router: appRouter
    router
});

將之前在組件中使用axios的位置改成

  1. 去掉import axios from ‘axios’
  2. 將axios. 改成this.$http.

add.vue

<script>

    // import axios from 'axios'
    export default {
data() {
return {
// 綁定到表單元素
formData: {
    name: '',
        gender: ''
}
}
},
    methods:{
        handleAdd() {
            this.$http
                .post('http://localhost:3000/users', this.formData)
                .then((res) => {
                const { status, data } = res;
                if (status === 201) {
                    // 判斷添加是否成功
                    // 添加成功,跳轉到英雄列表
                    this.$router.push({ name: 'heroes' });
                } else {
                    alert('添加失敗');
                }
            })
        }
    }
}
    </script>

配置baseUrl

請求的url中有一部分是一樣的, 每次寫很麻煩,

所以, 可以使用axios的API 配置baseURl

main.js

// 省略--

// 導入axios
import axios from 'axios';
// 設置baseURL
axios.defaults.baseURL = 'http://localhost:3000/';

// 省略--

在發起this.$http請求的位置, 簡化原來的url

add.vue

<script>

    // import axios from 'axios'
    export default {
data() {
return {
// 綁定到表單元素
formData: {
    name: '',
        gender: ''
}
}
},
    methods:{
        handleAdd() {
            this.$http
                .post('users', this.formData)
                .then((res) => {
                const { status, data } = res;
                if (status === 201) {
                    // 判斷添加是否成功
                    // 添加成功,跳轉到英雄列表
                    this.$router.push({ name: 'heroes' });
                } else {
                    alert('添加失敗');
                }
            })
        }
    }
}
    </script>

發佈了61 篇原創文章 · 獲贊 40 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章