Vue 的快速入門

學(xué)習(xí)目標

  • 會創(chuàng)建Vue實例,知道Vue的常見屬性
  • 會使用Vue的生命周期的鉤子函數(shù)
  • 會使用vue常見指令
  • 會使用vue計算屬性和watch監(jiān)控
  • 會編寫Vue組件
  • 掌握組件間通信

0.前言

前幾天我們已經(jīng)對后端的技術(shù)棧有了初步的了解、并且已經(jīng)搭建了整個后端微服務(wù)的平臺。接下來要做的事情就是功能開發(fā)了。但是沒有前端頁面,我們肯定無從下手,因此今天我們就要來了解一下前端的一些技術(shù),完成前端頁面搭建。

先聊一下前端開發(fā)模式的發(fā)展。

靜態(tài)頁面

  • 最初的網(wǎng)頁以HTML為主,是純靜態(tài)的網(wǎng)頁。網(wǎng)頁是只讀的,信息流只能從服務(wù)的到客戶端單向流通。開發(fā)人員也只關(guān)心頁面的樣式和內(nèi)容即可。

異步刷新,操作DOM

  • 1995年,網(wǎng)景工程師Brendan Eich 花了10天時間設(shè)計了JavaScript語言.

    隨著JavaScript的誕生,我們可以操作頁面的DOM元素及樣式,頁面有了一些動態(tài)的效果,但是依然是以靜態(tài)為主。

  • ajax盛行:

    • 2005年開始,ajax逐漸被前端開發(fā)人員所重視,因為不用刷新頁面就可以更新頁面的數(shù)據(jù)和渲染效果。
    • 此時的開發(fā)人員不僅僅要編寫HTML樣式,還要懂a(chǎn)jax與后端交互,然后通過JS操作Dom元素來實現(xiàn)頁面動態(tài)效果。比較流行的框架如Jquery就是典型代表。

MVVM,關(guān)注模型和視圖

  • 2008年,google的Chrome發(fā)布,隨后就以極快的速度占領(lǐng)市場,超過IE成為瀏覽器市場的主導(dǎo)者。

  • 2009年,Ryan Dahl在谷歌的Chrome V8引擎基礎(chǔ)上,打造了基于事件循環(huán)的異步IO框架:Node.js。

    • 基于時間循環(huán)的異步IO
    • 單線程運行,避免多線程的變量同步問題
    • JS可以編寫后臺diamante,前后臺統(tǒng)一編程語言
  • node.js的偉大之處不在于讓JS邁向了后端開發(fā),而是構(gòu)建了一個龐大的生態(tài)系統(tǒng)。

  • 2010年,NPM作為node.js的包管理系統(tǒng)首次發(fā)布,開發(fā)人員可以遵循Common.js規(guī)范來編寫Node.js模塊,然后發(fā)布到NPM上供其他開發(fā)人員使用。目前已經(jīng)是世界最大的包模塊管理系統(tǒng)。

  • 隨后,在node的基礎(chǔ)上,涌現(xiàn)出了一大批的前端框架:

1525825983230.png

MVVM模式

  • M:即Model,模型,包括數(shù)據(jù)和一些基本操作
  • V:即View,視圖,頁面渲染結(jié)果
  • VM:即View-Model,模型與視圖間的雙向操作(無需開發(fā)人員干涉)

在MVVM之前,開發(fā)人員從后端獲取需要的數(shù)據(jù)模型,然后要通過DOM操作Model渲染到View中。而后當(dāng)用戶操作視圖,我們還需要通過DOM獲取View中的數(shù)據(jù),然后同步到Model中。

而MVVM中的VM要做的事情就是把DOM操作完全封裝起來,開發(fā)人員不用再關(guān)心Model和View之間是如何互相影響的:

  • 只要我們Model發(fā)生了改變,View上自然就會表現(xiàn)出來。
  • 當(dāng)用戶修改了View,Model中的數(shù)據(jù)也會跟著改變。

把開發(fā)人員從繁瑣的DOM操作中解放出來,把關(guān)注點放在如何操作Model上。

1525828854056.png

而我們今天要學(xué)習(xí)的,就是一款MVVM模式的框架:Vue

1.認識Vue

Vue (讀音 /vju?/,類似于 view) 是一套用于構(gòu)建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設(shè)計為可以自底向上逐層應(yīng)用。Vue 的核心庫只關(guān)注視圖層,不僅易于上手,還便于與第三方庫或既有項目整合。另一方面,當(dāng)與現(xiàn)代化的工具鏈以及各種支持類庫結(jié)合使用時,Vue 也完全能夠為復(fù)雜的單頁應(yīng)用提供驅(qū)動。

? 前端框架三巨頭:Vue.js、React.js、AngularJS,vue.js以期輕量易用著稱,vue.js和React.js發(fā)展速度最快,AngularJS還是老大。

官網(wǎng):https://cn.vuejs.org/

參考:https://cn.vuejs.org/v2/guide/

1525829249048.png

Git地址:https://github.com/vuejs

1525829030730.png

尤雨溪,Vue.js 創(chuàng)作者,Vue Technology創(chuàng)始人,致力于Vue的研究開發(fā)。

2.Node和NPM

前面說過,NPM是Node提供的模塊管理工具,可以非常方便的下載安裝很多前端框架,包括Jquery、AngularJS、VueJs都有。為了后面學(xué)習(xí)方便,我們先安裝node及NPM工具。

2.1.下載Node.js

下載地址:https://nodejs.org/en/download/

1525830686367.png

推薦下載LTS版本。

課程中采用的是8.9.0版本。目前最新的是8.11.1。大家自行下載。然后下一步安裝即可。

完成以后,在控制臺輸入:

node -v

看到版本信息:

1525831616514.png

2.2.NPM

安裝完成Node應(yīng)該自帶了NPM了,在控制臺輸入npm -v查看:

1525831670850.png

npm默認的倉庫地址是在國外網(wǎng)站,速度較慢,建議大家設(shè)置到淘寶鏡像。但是切換鏡像是比較麻煩的。推薦一款切換鏡像的工具:nrm

我們首先安裝nrm,這里-g代表全局安裝

npm install nrm -g

然后通過nrm ls命令查看npm的倉庫列表,帶*的就是當(dāng)前選中的鏡像倉庫:

1525831918982.png

通過nrm use taobao來指定要使用的鏡像源:

1525831983603.png

然后通過nrm test npm來測試速度:

1525832070968.png

注意:

  • 有教程推薦大家使用cnpm命令,但是使用發(fā)現(xiàn)cnpm有時會有bug,不推薦。
  • 安裝完成請一定要重啟下電腦!?。?/li>
  • 安裝完成請一定要重啟下電腦?。?!
  • 安裝完成請一定要重啟下電腦?。?!

3.快速入門

接下來,我們快速領(lǐng)略下vue的魅力

3.1.創(chuàng)建工程

創(chuàng)建一個新的工程:

1525830180378.png

選中一個空的:

1525832233385.png

然后新建一個module:

1525832250071.png

選中static web,靜態(tài)web項目:

1525832275532.png

位置信息:

1525832294322.png

3.2.安裝vue

3.2.1.下載安裝

下載地址:https://github.com/vuejs/vue

可以下載2.5.16版本https://github.com/vuejs/vue/archive/v2.5.16.zip

下載解壓,得到vue.js文件。

3.2.2.使用CDN

或者也可以直接使用公共的CDN服務(wù):

<!-- 開發(fā)環(huán)境版本,包含了用幫助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

或者:

<!-- 生產(chǎn)環(huán)境版本,優(yōu)化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

3.2.3.推薦npm安裝

在idea的左下角,有個Terminal按鈕,點擊打開控制臺:

1525832726161.png

進入hello-vue目錄:

1525833019284.png

先輸入:npm init -y 進行初始化

1525833057884.png

安裝Vue,輸入命令:npm install vue --save

1525833109155.png

然后就會在hello-vue目錄發(fā)現(xiàn)一個node_modules目錄,并且在下面有一個vue目錄。

1525833163686.png

node_modules是通過npm安裝的所有模塊的默認位置。

3.3.vue入門案例

3.3.1.HTML模板

在hello-vue目錄新建一個HTML


1525833345526.png

在hello.html中,我們編寫一段簡單的代碼:

1525833809054.png

h2中要輸出一句話:xx 非常帥。前面的xx是要渲染的數(shù)據(jù)。

3.3.2.vue渲染

然后我們通過Vue進行渲染:

<div id="app">
    <h2>{{name}} 非常帥</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    // 生成一個Vue實例
    var app = new Vue({
        el:"#app", // el,即element。要渲染的的頁面元素
        data:{ // 數(shù)據(jù)
            name:"虎哥"
        }
    })
</script>
  • 首先通過 new Vue()來創(chuàng)建Vue實例
  • 然后構(gòu)造函數(shù)接收一個對象,對象中有一些屬性:
    • el:是element的縮寫,通過id選中要渲染的頁面元素,本例中是一個div
    • data:數(shù)據(jù),數(shù)據(jù)是一個對象,里面有很多屬性,都可以渲染到視圖中
      • name:這里我們指定了一個name屬性
  • 頁面中的h2元素中,我們通過{{name}}的方式,來渲染剛剛定義的name屬性。

打開頁面查看效果:

1525834212902.png

更神奇的在于,當(dāng)你修改name屬性時,頁面會跟著變化:

ScreenGif-1525834621341.gif

3.3.3.雙向綁定

我們對剛才的案例進行簡單修改:

<div id="app">
    <input type="text" v-model="num">
    <h2>
        {{name}} 非常帥,
        有{{num}}位女神為他著迷。
    </h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    // 生成一個Vue實例
    var app = new Vue({
        el:"#app", // el,即element。要渲染的的頁面元素
        data:{ // 數(shù)據(jù)
            name:"虎哥",
            num:1
        }
    })
</script>
  • 我們在data添加了新的屬性:num
  • 在頁面中有一個input元素,通過v-modelnum進行綁定。
  • 同時通過{{num}}在頁面輸出

效果:

2.gif

我們可以觀察到,輸入框的變化引起了data中的num的變化,同時頁面輸出也跟著變化。

  • input與num綁定,input的value值變化,影響到了data中的num值
  • 頁面{{num}}與數(shù)據(jù)num綁定,因此num值變化,引起了頁面效果變化。

沒有任何dom操作,這就是雙向綁定的魅力。

  • 傳統(tǒng)需要操作dom
<input type="text"  name="number" /><br/>
        <p></p>
        <button onclick="btn()" >按鈕</button>
        <script type="text/javascript">
            function btn() {
                        var input = document.getElementsByName('number')[0]
                        // 獲取輸入框中的數(shù)據(jù)
                        value  =input.value
                        value = parseInt(value)
                    document.getElementsByTagName('p')[0].innerText = value+'位同學(xué)';
                    }
        
        </script>

3.3.4.事件處理

我們在頁面添加一個按鈕:

<button v-on:click="num++">點我</button>
  • 這里用v-on指令綁定點擊事件,而不是普通的onclick,然后直接操作num
  • 普通click是無法直接操作num的。

效果:

3.gif

4.Vue實例

4.1.創(chuàng)建Vue實例

每個 Vue 應(yīng)用都是通過用 Vue 函數(shù)創(chuàng)建一個新的 Vue 實例開始的:

var vm = new Vue({
  // 選項
})

在構(gòu)造函數(shù)中傳入一個對象,并且在對象中聲明各種Vue需要的數(shù)據(jù)和方法,包括:

  • el
  • data
  • methods

等等

接下來我們一 一介紹。

4.2.模板或元素

每個Vue實例都需要關(guān)聯(lián)一段Html模板,Vue會基于此模板進行視圖渲染。

我們可以通過el屬性來指定。

例如一段html模板:

<div id="app">
    
</div>

然后創(chuàng)建Vue實例,關(guān)聯(lián)這個div

var vm = new Vue({
    el:"#app"
})

這樣,Vue就可以基于id為app的div元素作為模板進行渲染了。在這個div范圍以外的部分是無法使用vue特性的。

4.3.數(shù)據(jù)

當(dāng)Vue實例被創(chuàng)建時,它會嘗試獲取在data中定義的所有屬性,用于視圖的渲染,并且監(jiān)視data中的屬性變化,當(dāng)data發(fā)生改變,所有相關(guān)的視圖都將重新渲染,這就是“響應(yīng)式“系統(tǒng)。

html:

<div id="app">
    <input type="text" v-model="name"/>
</div>

js:

var vm = new Vue({
    el:"#app",
    data:{
        name:"劉德華"
    }
})
  • name的變化會影響到input的值
  • input中輸入的值,也會導(dǎo)致vm中的name發(fā)生改變

4.4.方法

Vue實例中除了可以定義data屬性,也可以定義方法,并且在Vue的作用范圍內(nèi)使用。

html:

<div id="app">
    {{num}}
    <button v-on:click="add">加</button>
</div>

js:

var vm = new Vue({
    el:"#app",
    data:{
        num: 0
    },
    methods:{
        add:function(){
            // this代表的當(dāng)前vue實例
            this.num++;
        }
    }
})

4.5.生命周期鉤子

4.5.1.生命周期

每個 Vue 實例在被創(chuàng)建時都要經(jīng)過一系列的初始化過程 :創(chuàng)建實例,裝載模板,渲染模板等等。Vue為生命周期中的每個狀態(tài)都設(shè)置了鉤子函數(shù)(監(jiān)聽函數(shù))。每當(dāng)Vue實例處于不同的生命周期時,對應(yīng)的函數(shù)就會被觸發(fā)調(diào)用。

生命周期:

lifecycle.png

4.5.2.鉤子函數(shù)

例如:created代表在vue實例創(chuàng)建后;

我們可以在Vue中定義一個created函數(shù),代表這個時期的構(gòu)造函數(shù):

html:

<div id="app">
    {{hello}}
</div>

js:

var vm = new Vue({
    el:"#app",
    data:{
        hello: '' // hello初始化為空
    },
    created(){
        this.hello = "hello, world! 我出生了!";
    }
})

結(jié)果:

1525843098485.png

4.5.3.this

我們可以看下在vue內(nèi)部的this變量是誰,我們在created的時候,打印this

var vm = new Vue({
    el:"#app",
    data:{
        hello: '' // hello初始化為空
    },
    created(){
        this.hello = "hello, world! 我出生了!";
        console.log(this);
    }
})

控制臺的輸出:

1525843381094.png

5.指令

什么是指令?

指令 (Directives) 是帶有 v- 前綴的特殊特性。指令特性的預(yù)期值是:單個 JavaScript 表達式。指令的職責(zé)是,當(dāng)表達式的值改變時,將其產(chǎn)生的連帶影響,響應(yīng)式地作用于 DOM。

例如我們在入門案例中的v-on,代表綁定事件。

5.1.插值表達式

5.1.1.花括號

格式:

{{表達式}}

說明:

  • 該表達式支持JS語法,可以調(diào)用js內(nèi)置函數(shù)(必須有返回值)
  • 表達式必須有返回結(jié)果。例如 1 + 1,沒有結(jié)果的表達式不允許使用,如:var a = 1 + 1;
  • 可以直接獲取Vue實例中定義的數(shù)據(jù)或函數(shù)

示例:

HTML:

<div id="app">{{name}}</div>

JS:

var app = new Vue({
    el:"#app",
    data:{
        name:"Jack"
    }
})

5.1.2.插值閃爍

使用{{}}方式在網(wǎng)速較慢時會出現(xiàn)問題。在數(shù)據(jù)未加載完成時,頁面會顯示出原始的{{}},加載完畢后才顯示正確數(shù)據(jù),我們稱為插值閃爍。

我們將網(wǎng)速調(diào)慢一些,然后試試看剛才的案例:

1525843894502.png

刷新頁面:

4.gif

5.1.3.v-text和v-html

使用v-text和v-html指令來替代{{}}

說明:

  • v-text:將數(shù)據(jù)輸出到元素內(nèi)部,如果輸出的數(shù)據(jù)有HTML代碼,會作為普通文本輸出
  • v-html:將數(shù)據(jù)輸出到元素內(nèi)部,如果輸出的數(shù)據(jù)有HTML代碼,會被渲染

示例:

HTML:

<div id="app">
    v-text:<span v-text="hello"></span> <br/>
    v-html:<span v-html="hello"></span>
</div>

JS:

var vm = new Vue({
    el:"#app",
    data:{
        hello: "<h1>大家好,我是虎哥</h1>"
    }
})

效果:


1525844448278.png

并且不會出現(xiàn)插值閃爍,當(dāng)沒有數(shù)據(jù)時,會顯示空白。

5.2.v-model

剛才的v-text和v-html可以看做是單向綁定,數(shù)據(jù)影響了視圖渲染,但是反過來就不行。接下來學(xué)習(xí)的v-model是雙向綁定,視圖(View)和模型(Model)之間會互相影響。

既然是雙向綁定,一定是在視圖中可以修改數(shù)據(jù),這樣就限定了視圖的元素類型。目前v-model的可使用元素有:

  • input
  • select
  • textarea
  • checkbox
  • radio
  • components(Vue中的自定義組件)

基本上除了最后一項,其它都是表單的輸入項。

舉例:

html:

<div id="app">
    <input type="checkbox" v-model="language" value="Java" />Java<br/>
    <input type="checkbox" v-model="language" value="PHP" />PHP<br/>
    <input type="checkbox" v-model="language" value="Swift" />Swift<br/>
    <h1>
        你選擇了:{{language.join(',')}}
    </h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            language: []
        }
    })
</script>
  • 多個CheckBox對應(yīng)一個model時,model的類型是一個數(shù)組,單個checkbox值是boolean類型
  • radio對應(yīng)的值是input的value值
  • inputtextarea 默認對應(yīng)的model是字符串
  • select單選對應(yīng)字符串,多選對應(yīng)也是數(shù)組

效果:

1525845481512.png

5.3.v-on

5.3.1.基本用法

v-on指令用于給頁面元素綁定事件。

語法:

v-on:事件名="js片段或函數(shù)名"

示例:

<div id="app">
    <!--事件中直接寫js片段-->
    <button v-on:click="num++">增加</button><br/>
    <!--事件指定一個回調(diào)函數(shù),必須是Vue實例中定義的函數(shù)-->
    <button v-on:click="decrement">減少</button><br/>
    <h1>num: {{num}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el:"#app",
        data:{
            num:1
        },
        methods:{
            decrement(){
                this.num--;
            }
        }
    })
</script>

效果:

5.gif

另外,事件綁定可以簡寫,例如v-on:click='add'可以簡寫為@click='add'

5.3.2.事件修飾符

在事件處理程序中調(diào)用 event.preventDefault()event.stopPropagation() 是非常常見的需求。盡管我們可以在方法中輕松實現(xiàn)這點,但更好的方式是:方法只有純粹的數(shù)據(jù)邏輯,而不是去處理 DOM 事件細節(jié)。

為了解決這個問題,Vue.js 為 v-on 提供了事件修飾符。之前提過,修飾符是由點開頭的指令后綴來表示的。

  • .stop :阻止事件冒泡
  • .prevent:阻止默認事件發(fā)生
  • .capture:使用事件捕獲模式
  • .self:只有元素自身觸發(fā)事件才執(zhí)行。(冒泡或捕獲的都不執(zhí)行)
  • .once:只執(zhí)行一次

5.3.3.按鍵修飾符

在監(jiān)聽鍵盤事件時,我們經(jīng)常需要檢查常見的鍵值。Vue 允許為 v-on 在監(jiān)聽鍵盤事件時添加按鍵修飾符:

<!-- 只有在 `keyCode` 是 13 時調(diào)用 `vm.submit()` -->
<input v-on:keyup.13="submit">

記住所有的 keyCode 比較困難,所以 Vue 為最常用的按鍵提供了別名:

<!-- 同上 -->
<input v-on:keyup.enter="submit">

<!-- 縮寫語法 -->
<input @keyup.enter="submit">

全部的按鍵別名:

  • .enter
  • .tab
  • .delete (捕獲“刪除”和“退格”鍵)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

5.3.4.組合按鈕

可以用如下修飾符來實現(xiàn)僅在按下相應(yīng)按鍵時才觸發(fā)鼠標或鍵盤事件的監(jiān)聽器。

  • .ctrl
  • .alt
  • .shift

例如:

<!-- Alt + C -->
<input @keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

5.4.v-for

遍歷數(shù)據(jù)渲染頁面是非常常用的需求,Vue中通過v-for指令來實現(xiàn)。

5.4.1.遍歷數(shù)組

語法:

v-for="item in items"
  • items:要遍歷的數(shù)組,需要在vue的data中定義好。
  • item:迭代得到的數(shù)組元素的別名

示例

<div id="app">
    <ul>
        <li v-for="user in users">
            {{user.name}} : {{user.gender}} : {{user.age}}
        </li>
    </ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            users:[
                {name:'柳巖', gender:'女', age: 21},
                {name:'虎哥', gender:'男', age: 30},
                {name:'范冰冰', gender:'女', age: 24},
                {name:'劉亦菲', gender:'女', age: 18},
                {name:'古力娜扎', gender:'女', age: 25}
            ]
        }
    })
</script>

效果:

1525848812000.png

5.4.2.數(shù)組角標

在遍歷的過程中,如果我們需要知道數(shù)組角標,可以指定第二個參數(shù):

語法

v-for="(item,index) in items"
  • items:要迭代的數(shù)組
  • item:迭代得到的數(shù)組元素別名
  • index:迭代到的當(dāng)前元素索引,從0開始。

示例

    <div id="app">
        <ul>
            <li v-for="(user,index) in users">
                {{index}} - {{user.name}} : {{user.gender}} : {{user.age}}
            </li>
        </ul>
    </div>

效果:

1525849039930.png

5.4.3.遍歷對象

v-for除了可以迭代數(shù)組,也可以迭代對象。語法基本類似

語法:

v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
  • 1個參數(shù)時,得到的是對象的值
  • 2個參數(shù)時,第一個是值,第二個是鍵
  • 3個參數(shù)時,第三個是索引,從0開始

示例:

<div id="app">
    <ul>
        <li v-for="(value,key,index) in user">
            {{index}} - {{key}} : {{value}}
        </li>
    </ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            user:{name:'柳巖', gender:'女', age: 21}
        }
    })
</script>

效果:

1525849552865.png

5.4.4.key

當(dāng) Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認用“就地復(fù)用”策略。如果數(shù)據(jù)項的順序被改變,Vue 將不會移動 DOM 元素來匹配數(shù)據(jù)項的順序, 而是簡單復(fù)用此處每個元素,并且確保它在特定索引下顯示已被渲染過的每個元素。

這個功能可以有效的提高渲染的效率。

但是要實現(xiàn)這個功能,你需要給Vue一些提示,以便它能跟蹤每個節(jié)點的身份,從而重用和重新排序現(xiàn)有元素,你需要為每項提供一個唯一 key 屬性。理想的 key 值是每項都有的且唯一的 id。

示例:

<ul>
    <li v-for="(item,index) in items" :key=index></li>
</ul>
  • 這里使用了一個特殊語法::key="" 我們后面會講到,它可以讓你讀取vue中的屬性,并賦值給key屬性
  • 這里我們綁定的key是數(shù)組的索引,應(yīng)該是唯一的

5.5.v-if和v-show

5.5.1.基本使用

v-if,顧名思義,條件判斷。當(dāng)?shù)玫浇Y(jié)果為true時,所在的元素才會被渲染。

語法:

v-if="布爾表達式"

示例:

    <div id="app">
        <!--事件中直接寫js片段-->
        <button v-on:click="show = !show">點擊切換</button><br/>
        <h1 v-if="show">
            你好
        </h1>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
        var app = new Vue({
            el:"#app",
            data:{
                show:true
            }
        })
    </script>

效果:

ScreenGif-1525850553649.gif

5.5.2.與v-for結(jié)合

當(dāng)v-if和v-for出現(xiàn)在一起時,v-for優(yōu)先級更高。也就是說,會先遍歷,再判斷條件。

示例:

    <div id="app">
        <ul>
            <li v-for="(user,index) in users" v-if="user.gender === '女'">
                {{index}} - {{user.name}} : {{user.gender}} : {{user.age}}
            </li>
        </ul>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                users:[
                    {name:'柳巖', gender:'女', age: 21},
                    {name:'虎哥', gender:'男', age: 30},
                    {name:'范冰冰', gender:'女', age: 24},
                    {name:'劉亦菲', gender:'女', age: 18},
                    {name:'古力娜扎', gender:'女', age: 25}
                ]
            }
        })
    </script>

效果:

1525850816434.png

5.5.3.v-else

你可以使用 v-else 指令來表示 v-if 的“else 塊”:

<div v-if="Math.random() > 0.5">
  Now you see me
</div>
<div v-else>
  Now you don't
</div>

v-else 元素必須緊跟在帶 v-if 或者 v-else-if 的元素的后面,否則它將不會被識別。

v-else-if,顧名思義,充當(dāng) v-if 的“else-if 塊”,可以連續(xù)使用:

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

類似于 v-else,v-else-if 也必須緊跟在帶 v-if 或者 v-else-if 的元素之后。

5.5.4.v-show

另一個用于根據(jù)條件展示元素的選項是 v-show 指令。用法大致一樣:

<h1 v-show="ok">Hello!</h1>

不同的是帶有 v-show 的元素始終會被渲染并保留在 DOM 中。v-show 只是簡單地切換元素的 CSS 屬性 display。

示例:

    <div id="app">
        <!--事件中直接寫js片段-->
        <button v-on:click="show = !show">點擊切換</button><br/>
        <h1 v-if="show">
            你好
        </h1>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
        var app = new Vue({
            el:"#app",
            data:{
                show:true
            }
        })
    </script>

代碼:

1.gif

5.6.v-bind

5.6.1.綁定class樣式

假如我們想動態(tài)的修改頁面元素的屬性,比如class屬性,這樣寫是錯誤的:

<div class="{{isAcctive}}"></div>

因為插值表達式不能用在屬性的值中。

Vue對class屬性進行了特殊處理,可以接收數(shù)組或?qū)ο蟾袷剑?/p>

數(shù)組語法

我們可以借助于v-bind指令來實現(xiàn):

HTML:

<div v-bind:class="isActive"></div>

你的data屬性:

data:{
    isActive:['active','hasError']
}

渲染后的效果:

<div class="active hasError"></div>

對象語法

我們可以傳給 v-bind:class 一個對象,以動態(tài)地切換 class:

<div v-bind:class="{ active: isActive }"></div>

上面的語法表示 active 這個 class 存在與否將取決于數(shù)據(jù)屬性 isActivetruthiness。

你可以在對象中傳入更多屬性來動態(tài)切換多個 class。此外,v-bind:class 指令也可以與普通的 class 屬性共存。當(dāng)有如下模板:

<div class="static"
     v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>

和如下 data:

data: {
  isActive: true,
  hasError: false
}

結(jié)果渲染為:

<div class="static active"></div>

當(dāng) isActive 或者 hasError 變化時,class 列表將相應(yīng)地更新。例如,如果 hasError的值為 true,class 列表將變?yōu)?"static active text-danger"。

5.6.2.簡寫

v-bind:class可以簡寫為:class

5.7.計算屬性

在插值表達式中使用js表達式是非常方便的,而且也經(jīng)常被用到。

但是如果表達式的內(nèi)容很長,就會顯得不夠優(yōu)雅,而且后期維護起來也不方便,例如下面的場景,我們有一個日期的數(shù)據(jù),但是是毫秒值:

data:{
    birthday:1529032123201 // 毫秒值
}

我們在頁面渲染,希望得到y(tǒng)yyy-MM-dd的樣式:

<h1>您的生日是:{{
    new Date(birthday).getFullYear() + '-'+ new Date(birthday).getMonth()+ '-' + new Date(birthday).getDay()
    }}
</h1>

雖然能得到結(jié)果,但是非常麻煩。

Vue中提供了計算屬性,來替代復(fù)雜的表達式:

var vm = new Vue({
    el:"#app",
    data:{
        birthday:1429032123201 // 毫秒值
    },
    computed:{
        birth(){// 計算屬性本質(zhì)是一個方法,但是必須返回結(jié)果
            const d = new Date(this.birthday);
            return d.getFullYear() + "-" + d.getMonth() + "-" + d.getDay();
        }
    }
})
  • 計算屬性本質(zhì)就是方法,但是一定要返回數(shù)據(jù)。然后頁面渲染時,可以把這個方法當(dāng)成一個變量來使用。

頁面使用:

    <div id="app">
       <h1>您的生日是:{{birth}} </h1>
    </div>

效果:

1525861635758.png

5.8.watch

watch可以讓我們監(jiān)控一個值的變化。從而做出相應(yīng)的反應(yīng)。

示例:

<div id="app">
    <input type="text" v-model="message">
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el:"#app",
        data:{
            message:""
        },
        watch:{
            message(newVal, oldVal){
                console.log(newVal, oldVal);
            }
        }
    })
</script>

效果:

1525865657611.png

6.組件化

在大型應(yīng)用開發(fā)的時候,頁面可以劃分成很多部分。往往不同的頁面,也會有相同的部分。例如可能會有相同的頭部導(dǎo)航。

但是如果每個頁面都獨自開發(fā),這無疑增加了我們開發(fā)的成本。所以我們會把頁面的不同部分拆分成獨立的組件,然后在不同頁面就可以共享這些組件,避免重復(fù)開發(fā)。

6.1.定義全局組件

我們通過Vue的component方法來定義一個全局組件。

<div id="app">
    <!--使用定義好的全局組件-->
    <counter></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    // 定義全局組件,兩個參數(shù):1,組件名稱。2,組件參數(shù)
    Vue.component("counter",{
        template:'<button v-on:click="count++">你點了我 {{ count }} 次,我記住了.</button>',
        data(){
            return {
                count:0
            }
        }
    })
    var app = new Vue({
        el:"#app"
    })
</script>
  • 組件其實也是一個Vue實例,因此它在定義時也會接收:data、methods、生命周期函數(shù)等
  • 不同的是組件不會與頁面的元素綁定,否則就無法復(fù)用了,因此沒有el屬性。
  • 但是組件渲染需要html模板,所以增加了template屬性,值就是HTML模板
  • 全局組件定義完畢,任何vue實例都可以直接在HTML中通過組件名稱來使用組件了。
  • data的定義方式比較特殊,必須是一個函數(shù)。

效果:

6.gif

6.2.組件的復(fù)用

定義好的組件,可以任意復(fù)用多次:

<div id="app">
    <!--使用定義好的全局組件-->
    <counter></counter>
    <counter></counter>
    <counter></counter>
</div>

效果:

1525854127169.png

你會發(fā)現(xiàn)每個組件互不干擾,都有自己的count值。怎么實現(xiàn)的?

組件的data屬性必須是函數(shù)

當(dāng)我們定義這個 <counter> 組件時,它的data 并不是像這樣直接提供一個對象:

data: {
  count: 0
}

取而代之的是,一個組件的 data 選項必須是一個函數(shù),因此每個實例可以維護一份被返回對象的獨立的拷貝:

data: function () {
  return {
    count: 0
  }
}

如果 Vue 沒有這條規(guī)則,點擊一個按鈕就會影響到其它所有實例!

6.2.局部注冊

一旦全局注冊,就意味著即便以后你不再使用這個組件,它依然會隨著Vue的加載而加載。

因此,對于一些并不頻繁使用的組件,我們會采用局部注冊。

我們先在外部定義一個對象,結(jié)構(gòu)與創(chuàng)建組件時傳遞的第二個參數(shù)一致:

const counter = {
    template:'<button v-on:click="count++">你點了我 {{ count }} 次,我記住了.</button>',
    data(){
        return {
            count:0
        }
    }
};

然后在Vue中使用它:

var app = new Vue({
    el:"#app",
    components:{
        counter:counter // 將定義的對象注冊為組件
    }
})
  • components就是當(dāng)前vue對象子組件集合。
    • 其key就是子組件名稱
    • 其值就是組件對象的屬性
  • 效果與剛才的全局注冊是類似的,不同的是,這個counter組件只能在當(dāng)前的Vue實例中使用

6.3.組件通信

通常一個單頁應(yīng)用會以一棵嵌套的組件樹的形式來組織:

1525855149491.png
  • 頁面首先分成了頂部導(dǎo)航、左側(cè)內(nèi)容區(qū)、右側(cè)邊欄三部分
  • 左側(cè)內(nèi)容區(qū)又分為上下兩個組件
  • 右側(cè)邊欄中又包含了3個子組件

各個組件之間以嵌套的關(guān)系組合在一起,那么這個時候不可避免的會有組件間通信的需求。

6.3.1.父向子傳遞props

比如我們有一個子組件:

Vue.component("introduce",{
    // 直接使用props接收到的屬性來渲染頁面
    template:'<h3>{{title}}</h3>',
    props:[title] // 通過props來接收一個父組件傳遞的屬性
})
  • 這個子組件中要使用title屬性渲染頁面,但是自己并沒有title屬性
  • 通過props來接收父組件屬性,名為title

父組件使用子組件,同時傳遞title屬性:

<div id="app">
    <h1>打個招呼:</h1>
    <!--使用子組件,同時傳遞title屬性-->
    <introduce title="大家好,我是虎哥"/>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    Vue.component("introduce",{
        // 直接使用props接收到的屬性來渲染頁面
        template:'<h1>{{title}}</h1>',
        props:['title'] // 通過props來接收一個父組件傳遞的屬性
    })
    var app = new Vue({
        el:"#app"
    })
</script>

效果:

1525857338270.png

6.3.2.傳遞復(fù)雜數(shù)據(jù)

我們定義一個子組件:

const myList = {
    template:'\
        <ul>\
            <li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
        </ul>\
        ',
    props:{ // 通過props來接收父組件傳遞來的屬性
        items:{// 這里定義items屬性
            type:Array,// 要求必須是Array類型
            default:[] // 如果父組件沒有傳,那么給定默認值是[]
        }
    }
}
  • 這個子組件可以對 items 進行迭代,并輸出到頁面。
  • 但是組件中并未定義items屬性。
  • 通過props來定義需要從父組件中接收的屬性
    • items:是要接收的屬性名稱
      • type:限定父組件傳遞來的必須是數(shù)組,否則報錯
      • default:默認值

我們在父組件中使用它:

<div id="app">
    <h2>傳智播客已開設(shè)如下課程:</h2>
    <!-- 使用子組件的同時,傳遞屬性,這里使用了v-bind,指向了父組件自己的屬性lessons -->
    <my-list :items="lessons"/>
</div>
var app = new Vue({
    el:"#app",
    components:{
        myList // 當(dāng)key和value一樣時,可以只寫一個
    },
    data:{
        lessons:[
            {id:1, name: 'java'},
            {id:2, name: 'php'},
            {id:3, name: 'ios'},
        ]
    }
})

效果:

1525857477274.png

6.3.3.子向父的通信

來看這樣的一個案例:

<div id="app">
    <h2>num: {{num}}</h2>
    <!--使用子組件的時候,傳遞num到子組件中-->
    <counter :num="num"></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    Vue.component("counter", {// 子組件,定義了兩個按鈕,點擊數(shù)字num會加或減
        template:'\
            <div>\
                <button @click="num++">加</button>  \
                <button @click="num--">減</button>  \
            </div>',
        props:['num']// count是從父組件獲取的。
    })
    var app = new Vue({
        el:"#app",
        data:{
            num:0
        }
    })
</script>
  • 子組件接收父組件的num屬性
  • 子組件定義點擊按鈕,點擊后對num進行加或減操作

我們嘗試運行:

1525859093172.png

好像沒問題,點擊按鈕試試:

1525859138607.png

子組件接收到父組件屬性后,默認是不允許修改的。怎么辦?

既然只有父組件能修改,那么加和減的操作一定是放在父組件:

var app = new Vue({
    el:"#app",
    data:{
        num:0
    },
    methods:{ // 父組件中定義操作num的方法
        increment(){
            this.num++;
        },
        decrement(){
            this.num--;
        }
    }
})

但是,點擊按鈕是在子組件中,那就是說需要子組件來調(diào)用父組件的函數(shù),怎么做?

我們可以通過v-on指令將父組件的函數(shù)綁定到子組件上:

<div id="app">
    <h2>num: {{num}}</h2>
    <counter :count="num" @inc="increment" @dec="decrement"></counter>
</div>

然后,當(dāng)子組件中按鈕被點擊時,調(diào)用綁定的函數(shù):

        Vue.component("counter", {
            template:'\
                <div>\
                    <button @click="plus">加</button>  \
                    <button @click="reduce">減</button>  \
                </div>',
            props:['count'],
            methods:{
                plus(){
                    this.$emit("inc");
                },
                reduce(){
                    this.$emit("dec");
                }
            }
        })
  • vue提供了一個內(nèi)置的this.$emit函數(shù),用來調(diào)用父組件綁定的函數(shù)

效果:

7.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 寫在前面 上面文章我給大家介紹了Dapper這個ORM框架的簡單使用,大伙會用了嘛!本來今天這篇文章是要講Vue的...
    依樂祝閱讀 982評論 0 1
  • Vue是現(xiàn)在最流行的前端框架之一,而且相對于其他兩個框架React和Angular來說也更加易學(xué),而且它的作者是國...
    dinel閱讀 5,031評論 0 9
  • Vue是現(xiàn)在最流行的前端框架之一,而且相對于其他兩個框架React和Angular來說也更加易學(xué),而且它的作者是國...
    樂百川閱讀 3,540評論 0 9
  • 主要還是自己看的,所有內(nèi)容來自官方文檔。 介紹 Vue.js 是什么 Vue (讀音 /vju?/,類似于 vie...
    Leonzai閱讀 3,537評論 0 25
  • 1. 組件的data為什么必須是函數(shù)? 組件中的 data 寫成一個函數(shù),數(shù)據(jù)以函數(shù)返回值形式定義,這樣每復(fù)用一次...
    郭先生_515閱讀 1,047評論 0 12

友情鏈接更多精彩內(nèi)容