Vue_Vue權威指南

Vue特性

Vue只是聚焦視圖層,是一個構建數據驅動的Web界面的庫。
Vue經過簡單 API提供高效的數據綁定和靈活的組件系統javascript

  1. 輕量css

  2. 數據綁定html

  3. 指令前端

  4. 插件化vue

架構從傳統後臺MVC 向REST API + 前端MV*遷移
DOM是數據的一種天然映射java

Vue核心:
組件化數據驅動node

組件化: 擴展HTML元素,封裝可重用的代碼
每一個組件對應一個工程目錄,組件所須要的各類資源在這個目錄下就近維護。react

Vue與其它框架的區別

對比標準:
文件大小(性能)入門曲線(易用),社區繁榮,吸收優勢linux

與AngularJs區別webpack

相同點:

  • 支持指令 -- 內置指令和自定義指令

  • 支持過濾器 -- 內置過濾器和自定義過濾器

  • 支持雙向綁定

  • 都不支持低端瀏覽器(IE6/7/8)

不一樣點:
在性能上,ANgualrJS依賴對數據作髒檢查,因此Watcher越多越慢,Vue使用依賴追中的觀察而且使用異步隊列更新,全部的數據都是獨立觸發的。

與React的區別

相同點:

  • React採用特殊的JSX語法,Vue在組建開中也推崇編寫.vue特殊文件格式,對文件內容都有一些約定,二者都須要編譯後使用。

  • 中心思想相同:一切都是組件,組件實例之間能夠嵌套。

  • 都提供合理的鉤子函數,能夠去定製化的去處理需求。

  • 都不內置相似AJAX,Router等功能到核心包,而是以其它方式(插件)加載。

  • 在組建開發中,都支持mixins的特性。

不一樣點:

  • React依賴 Virtual DOM,而Vue使用的DOM模板。React採用的Virtual DOM會對渲染出來的結果作髒檢查

  • Vue在模板中提供了指令,過濾器等。能夠方便快捷的操做DOM。

髒檢查:在angular中,沒有辦法對數據是否作了更改,因此設置觸發條件,當觸發這些條件,就執行一個檢查來遍歷全部的數據,對比更改的地方,而後執行變化,保留沒有更改的地方。
效率不高,不少多餘,稱之爲 髒檢查。(過程:數據修改了,結果:保留就數據)

Vue穩定版本:1.0.24

數據綁定

數據綁定是將數據和視圖想關聯,當數據發生變化時,能夠自動更新視圖。

插值

mustache標籤
文本插值:{{}}
有時候只需渲染一次數據,後續數據變化再也不關心,使用:{{*}}
HTML片斷:{{{}}}

注意:Vue指令和自身特性內是不能夠插值。

表達式

mustache標籤能夠由JavaScript表達式和過濾器(本質上是一個JavaScript函數)構成。

表達式:各類數值,變量,運算符的綜合體。

{{var a = 100;}} // 錯誤。 是語句,並非表達式
{{if (true) return 'a'}} // 條件控制語句是不支持,可使用 三目運算符

指令

做用:當表達式的值發生變化時,將這個變化也反映到DOM上。

分隔符

  1. delimiters

    Vue.config.delimiters = ['<%', '%>'];

修改了默認的文本插值的分隔符,則文本插值的語法由{{example}} 變爲<%example%>

  1. unsafeDelimiters

    Vue.config.unsafeDelimiters = ['<$', '$>'];

    若是修改了默認的HTML插值的分隔符,則HTML插值的語法由{{example}}變爲 <$emample&dollar;>

指令

指令的值限定爲綁定表達式。
做用:當其表達式的值改變時把某些特殊的行爲應用到DOM上。

內部指令

v-if

根據表達式的值在DOM中生成或移除一個元素。

v-show

根據表達式的值來顯示或隱藏HTML元素。

在切換v-if模塊時,Vue有一個局部編譯/卸載過程,由於v-if中的模板可能包括數據綁定或子組件,v-if是真實的條件渲染,由於它會包缺條件塊在切換時合適地銷燬與重建條件塊內的時間監聽器和子組件

v-if是惰性的---若是初始渲染時條件爲假,則什麼也不作,在條件第一次變爲真時纔開始局部編譯(編譯會被緩存起來)
相比v-show -- 元素始終被編譯並保留,只是簡單的基於CSS切換。

v-if有更高的切換消耗,而v-show有更高的初始渲染消耗。所以,若是須要頻繁的切換,則使用v-show較好,若是在運行時條件不大可能變化,則使用v-if較好

v-else

必須跟着v-ifv-show後面,充當else功能

v-model

用來在 input, select, text, checkbox, radio 等表單控件元素上建立雙向數據綁定。根據控件類型,v-model自動選取正確的方法更新元素。

v-model指令能夠添加參數number,lazy,debounce

<input type="text" v-model="msg" number />
<!-- 輸入的自動轉換爲Number類型(若是原始的轉換結果爲NaN,則返回原始值) -->

<input type="text" v-model="msg" lazy />
<!-- 默認狀況下,v-model 在 input 時間中同步輸入框的值與數據, 能夠添加一個lazy特性,從而將數據改到 change事件中發生 -->

v-for

基於源數據重複渲染元素,可使用$index來呈現相對應的數組索引

<ul id="demo">
    <li v-for="item in items" class="item-{{$index}}">
        {{item.childMsg}}
    </li>
</ul>

Vue 1.0.17及之後支持 of分隔符.

<div v-for="item of items"></div>

使用v-for,將獲得一個特殊的做用域,須要明確指定props屬性傳遞數據,不然在組建內江獲取不到數據。(隔離做用域)

<my-item v-for="item in items" :item="item" :index="$index">
    <p>{{item.text}}</p>
</my-item>

Vue包裝了被觀察數據的變異方法,它們能觸發視圖更新。
push(),pop(),shilt(),unshift(),splice(),sort(),reverse()

Vue重寫了這些方法以後,觸發了notify

Vue增長了兩個方法來觀測變化:$set$remove

$set : 經過索引設置數組元素並觸發視圖更新。

vm.animals.$set(0, {name: 'Aardvark'});

$set,$remove 底層都是調用splice()方法。

應該儘可能避免直接設置數據綁定的數組元素,由於這些變化不會被Vue檢測到,由於也不會更新視圖渲染,可使用$set().

Vue不能檢測到數組的變化

  • 直接用索引設置元素. 例如:vm.items[0] = {};

  • 修改數據的長度, 例如:vm.items.length = 0;

解決方法:

vm.items.$set(0, {});

第二個問題,用一個空數據替換items便可。

v-for遍歷一個對象,每個重複的實例都將有一個特殊的屬性$key,或者給對象的簡直提供一個別名。

<li v-for="itme in item">{{$key}} : {{item}}</li>

<li v-for="(key, value) in item">{{key}} : {{item.msg}}</li>

v-for 支持整數

<li v-for="itme in 10"></li>

ECMAScript沒法檢測到新屬性添加到一個對象上或者在對象中刪除。要處理這樣的情況Vue增長三種方法:$add(key,value),$set(key, value),$delete(key)這些方法能夠用來添加和刪除屬性,同時能夠觸發視圖的更新。

v-text

v-text指令能夠更新元素的textContent。在內部,{{ Mustache }}插值也被編譯爲textNode的一個v-text指令。

<span v-text="msg"></span>

<span>{{msg}}</span>

v-html
能夠更新元素的InnerHTML。內容按普通 HTML插入 -- 數據綁定被忽略。

{{{Mustache}}} 插值也會被編譯爲錨節點上的一個v-html指令

不建議直接動態渲染任意的HTML片斷,很容易致使XSS攻擊.

<div v-html="html"></div>
<div>{{{html}}}</div>

v-bind

響應更新HTML特性,將一個或多個attribute,或一個組件prop動態綁定到表達式。

<img v-bind:src="imgSrc" />
<img :src="imgSrc" />

在綁定prop時,prop必須在子組件中聲明。能夠用修飾符指定不一樣的綁定類型。

修飾符爲:

  • .sync --- 雙向綁定,只能用於prop綁定。

  • .noce --- 單次綁定,只能用於prop綁定

  • .camel --- 將綁定的特性名字轉換駝峯命名(一般用於綁定用駝峯命名的SVG特性)

<my-component :prop="smoeThing"></my-component>
<my-component :prop.sync="smoeThing"></my-component>

v-on
用於綁定事件監聽器,事件類型由參數指定。

在監聽原生DOM事件時,若是隻定義一個參數。 DOM event 爲事件的惟一參數;若是在內聯語句處理器中訪問原生DOM事件,則能夠用特殊變量$event把它傳入方法中。

<!-- 方法 -->
<button v-on:click="methods"></button>
<!-- 內聯語句 -->
<button v-on:click="methods(123, $event)"></button>
<!-- 縮寫 -->
<button @click="methods"></button>

<!-- 中止冒泡 -->
<button @click.stop="methods"></button>
<!-- 阻止默認行爲 -->
<button @click.prevent="methods"></button>
<!-- 阻止默認行爲,沒有表達式 -->
<button @submit.prevent></button>
<!-- 串聯修飾符 -->
<button @click.stop.prevent="methods"></button>
<!-- 修飾符,鍵別名 -->
<button @keyup.enter="onEnter"></button>

<!-- 鍵修飾符,鍵代碼 -->
<button @keyup.13="onEnter"></button>

v-ref

在父組件上註冊一個子組件的索引,便於直接訪問。不須要表達式,必須提供參數id。能夠經過父組件的$refs對象訪問子組件

v-el

爲DOM元素註冊一個索引,方便經過所屬實例的$els訪問這個元素。能夠用v-el:smoe-el設置this.$els.smoeEl

<div class="app">
    
    <span v-el:msg>hello</span>
    <span v-el:other-msg>Vue</span>
    
</div>

<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    new Vue({
        el: '.app',
        ready: function () {
            console.log( this.$els.msg.textContent ); // hello
            console.log( this.$els.otherMsg ); // <span>Vue<span>
        }
    });
    
</script>

v-pre

編譯時跳過當前元素和它的子元素。能夠用來顯示原始Mustache標籤。跳過大量沒有指令的節點會加快編譯。

v-cloak

v-cloak 這個指令保持在元素上知道關聯實例結果編譯。
解決閃爍問題

[v-cloak] {
    dispnay: none;
}
<div v-cloak>
    {{message}}
</div>

自定義指令

自定義指令提供一種機制將數據的變化映射爲DOM行爲。

鉤子函數

Vue中的鉤子函數都是可選的,相互之間沒有制約關係

  • bind, 只調用一次,在指令第一次綁定到元素上時調用。

  • update, 在bind以後當即以初始值爲參數第一次調用,以後每當綁定值變化時調用,參數爲新值與舊值。

  • unbind,只調用一次,在指令從元素上綁定時調用。

    Vue.directive('my-directive', {
        bind: function () {
            // 準備工做
            // 例如,添加時間處理器或只須要運行一次的高耗任務
        },
        update: function ( newValue, oldValue ) {
            // 值更新時的工做
            // 也會以初始值爲參數調用一次    
        },
        unbind: function () {
            // 清理工做
            // 例如,刪除bind() 添加的事件監聽器    
        }
    });

使用指令:

<div v-my-direactive="someValue"></div>

只須要update函數是,能夠傳入一個函數替代定義對象

Vue.direactive('my-directive', function () {
    // update();
});

指令實例屬性

全部的鉤子函數都將被複制都實際的指令對象中,在鉤子內this指向這個指令對象。

  • el -- 指令綁定的元素

  • vm -- 擁有該指令的上下文ViewModel

  • expression -- 指令的表達式,不包括參數和過濾器。

  • arg -- 指令的參數

  • name -- 指令的名字,不包含前綴

  • modifires -- 一個對象,包括指令的修飾符

  • descriptor -- 一個對象,包含指令的解析結果

將這些屬性視爲只讀,不要修改他們。

<div id="app" @click="up">
    <div v-my-directive:hello.a.b="msg"></div>
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    Vue.directive('my-directive', {
        bind: function() {
            console.log('bound!');
        },
        update: function( value ) {
            this.el.innerHTML = 
                'name -' + this.name + '<br />' +
                'expression - ' + this.expression + '<br />' +
                'argument - ' + this.arg + '<br />' +
                'modifiers - ' + JSON.stringify(this.mondifiers) + '<br />' +
                'value -' + value + '<br />' +
                'vm-msg' + this.vm.msg;
        }
    });
        //name -my-directive
        //expression - msg
        //argument - hello
        //modifiers - undefined
        //value -hello
        //vm-msghello
    
    new Vue({
        el: '#app',
        data: {
            msg: 'hello'
        },
        methods: {
            up: function() {
                console.log('click');
            }
        }
    });
    
</script>

指令高級選項

自定義指令提供一種機制將數據的變化映射爲DOM行爲

params
自定義指令能夠接收一個params數組,指定一個特性列表,Vue編譯器將自定提取綁定元素的這些特性。

<div id="app">
    <my-direactvie class="hello" name="hi" a="aaaa"></my-direactvie>
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    Vue.elementDirective('my-direactvie', {
        
        params: ['a'],
        
        bind: function() {
            
            console.log(this.params.a);
            
            console.log(this.el.getAttribute('name'));
            
        }
        
    });
    
    new Vue({
        el: '#app'
    });
    
</script>

支持動態(v-bind),this.params[key]會自動保持更新。能夠指定一個回調,在值變化時調用。

<div id="app">
    <my-direactvie class="hello" name="hi" v-bind:a="someValue"></my-direactvie>
    <input type="text" v-model="someValue" name="" id="" value="" />
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    Vue.elementDirective('my-direactvie', {
        
        params: ['a'],
        
        paramWatchers: {
            a: function() {
                console.log('a changed!');
            }
        }
        
    });
    
    new Vue({
        el: '#app',
        data: {
            someValue: ''
        }
    });
    
</script>

deep

若是自定義指令使用在一個對象上,當對象內部屬性變化時要觸發update,則在指令定義對象中指定 deep:true

<div id="app">
    <div v-my-directive="a"></div>
    <button @click="change">change</button>{{a.b.c}}
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">

    Vue.directive('my-directive', {
        deep: true,
        update: function( obj ) {
            console.log( obj.b.c );
        }
    });
    new Vue({
        el: '#app',
        data: {
            a: {
                b: {
                    c: 2
                }
            }
        },
        methods: {
            change: function() {
                this.a.b.c = 4;
            }
        }
    });

    
</script>

twoWay

若是指令想VUe實例寫回數據,則在指令定義對象中指定twoWay:true
做用:容許在指令中使用this.set(value)

<div id="app">
    自定義組件: <input v-exp="a.b.c" /> <br />
    父做用域:{{a.b.c}}
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    Vue.directive('exp', {
        twoWay: true,
        bind: function() {
            this.handler = function() {
                
                // 把數據寫回 vm
                // 若是指令這樣綁定 v-exp="a.b.c"
                // 這裏將會綁定 `vm.a.b.c` 賦值
                this.set(this.el.value);
            }.bind(this);
            this.el.addEventListener('input', this.handler)
        },
        update: function() {
            this.el.removeEventListener('input', this.handler);
        }
    });
    
    new Vue({
        el: '#app',
        data: {
            a: {
                b: {
                    c: 2
                }
            }
        }
    });
    
</script>

acceptStatement

傳入acceptStatement:true可讓自定義指令接受內聯語句,就像v-on那樣。

<div id="app">
    <div v-my-directive="a++"></div>
    {{a}}
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    Vue.directive('my-directive', {
        acceptStatement: true,
        update: function( fn ) {
            // 傳入一個是函數
            // 調用它是將在所屬實例做用域內計算"a++"語句
            console.log( fn.toString() );
            fn();
        }
    });
    
    new Vue({
        el: '#app',
        data: {
            a: 5
        }
    });
    
</script>

Terminal

Vue經過遞歸遍歷DOM樹來編譯模塊。可是遇到terminal指令時會中止遍歷這個元素的後代,這個指令將會接管編譯這個元素及其後代的任務。 v-ifv-for都是terminal指令

priority

能夠給指令指定一個優先級。若是沒有指定優先級,普通指令默認是1000,terminal指令默認是2000.同一個元素上優先級高的指令會比其它指令處理得早已一些,優先級同樣的指令按照它在元素特性列表中出現的順序依次處理,可是不能保證這個順序在不一樣瀏覽器中是一致的。

流程控制指令 v-ifv-for在編譯過程當中始終擁有最高的優先級。

指令可以使用的配置項:

Vue.directive(id, {
    params: [],
    deep: true, // 使用對象,對象內部屬性變化,觸發update
    twoWay: true, // 指令把數據寫回Vue實例
    acceptStatement: true, // 自定義指令接受內聯語句 (相似`v-on`)
    priority: 2222, // 優先級
    bind: function() {},
    update: function() {},
    unbind: function() {}
});

Vue.directive(id, function() {
    
});

問題:

v-on能夠綁定多個方法嗎?

v-on能夠綁定多種類型的方法,能夠是click,能夠是focus事件,也能夠是change事件
可是使用v-on綁定了兩個甚至多個click事件,那麼v-on只會綁定第一個click事件,其它會被自動忽略。

<input type="text" :value="name" @input="onInput" @focus="onFocus" @blur="onBlur" />

一個Vue實例能夠綁定多個element元素嗎?

el爲實例提供掛載元素,值能夠是CSS選擇符,或實際的HTML元素,或返回HTML元素的函數。這邊,元素只用做掛載點。若是提供了模板,則元素被替換,除非replace爲false.元素能夠用vm.$el訪問。

在Vue中如何讓v-for循環出來的列表裏面的click事件只對當前列表內元素有效?

  1. 從數據角度出發,定好數據結構,而後操做數據

  2. 經過$event對象,獲取當前事件源,而後操做下面的元素.

<div class="app">
    
    <ul>
        <li @click="toggle(item)" v-for="item in items">
            <span v-show="item.show">{{item.content}}</span>
        </li>
    </ul>
    
</div>

<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    new Vue({
        el: '.app',
        data: {
            items: [
                {
                    content: '1 item',
                    show: true
                }, {
                    content: '2 item',
                    show: true
                }, {
                    content: '3 item',
                    show: false
                }
            ]
        },
        methods: {
            toggle: function ( item ) {
                item.show = !item.show;
            }
        }
    });
    
</script>

計算屬性

一般會在模板中綁定表達式,模板是用來描述視圖結構的。若是模板中的表達式存在過多的邏輯,模板會變成臃腫不堪,維護變得很是困難,所以,爲了簡化邏輯,當某個屬性值依賴於其它屬性的值,可使用計算屬性。

什麼是計算屬性

計算屬性就是當其依賴屬性的值發生變化時,這個屬性的值會自動更新,與之相關的DOM部分也會同步自動更新。

<div class="app">
    
    <input type="text" v-model="didi" />
    <input type="text" v-model="family" />
    <br />
    
    didi = {{didi}}, family = {{family}}, didiFamily = {{didiFamily}}
    
</div>


<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    new Vue({
        el: '.app',
        data: {
            didi: 'didi',
            family: 'family'
        },
        computed: {
            didiFamily: {
                get: function () {
                    return this.didi + this.family;
                },
                set: function ( val ) {
                    var names = val.split(' ');
                    this.didi = names[0];
                    this.family = names[1];
                }
            }
        }
    });
    
</script>

計算屬性緩存

計算屬性方法中執行大量的耗時操做,則可能會帶來一些性能問題。
例如:在計算屬性getter中循環一個大的數組以執行不少操做,那麼當頻繁調用該計算屬性時,就會致使大量沒必要要的運算。
而在 Vue 0.12.8版本中,在這方面進行了優化,即只有計算屬性依賴的屬性值發生了改變時纔會從新執行getter
這樣存在一個問題:就是隻有Vue實例中被觀察的數據發生了改變時纔會從新執行getter。可是有時候計算屬性依賴實時的非觀察數據屬性。

<div class="app">
    <input type="text" v-model="welcome" name="" id="" />
    {{welcome}}
    <p>{{example}}</p>
</div>


<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    new Vue({
        el: '.app',
        data: {
            welcome: 'welcome to join didi'
        },
        computed: {
            example: function () {
                return Date.now() + this.welcome;
            }
        }
    });
    
</script>

在每次訪問example時都取得最新的事件而不是緩存的事件。從Vue 0.12.11版本開始,默認提供了緩存開關。 在計算屬性對象中指定cache字段來控制是否開啓緩存。

new Vue({
    el: '.app',
    data: {
        welcome: 'welcome to join didi'
    },
    computed: {
        example: {
            cache: false, // 關閉緩存,默認爲true
            get: function () {
                return Date.now() + this.welcome;
            }
        }
    }
});

設置cache爲false關閉緩存以後,每次直接訪問vm.example 時都會從新執行getter方法。

問題:

計算屬性getter不執行的場景

當計算屬性依賴的數據屬性發生改變時,計算屬性的getter方法就會執行。在有些狀況下,雖然依賴數據屬性發生了改變,但計算屬性的getter方法並不會執行。

當包含計算屬性的節點被移出模板中其它地方沒有再引用該屬性時,那麼對應的計算屬性的getter不會執行。

<div class="app">
    
    <button @click="toggleShow">Toggle Show Total Price</button>
    <p v-if="showTotal">Total Price = {{totalPrices}}</p>
    {{totalPrices}}
</div>

<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    new Vue({
        el: '.app',
        data: {
            showTotal: true,
            basePrice: 100
        },
        computed: {
            totalPrices: function () {
                return this.basePrice + 1;
            }
        },
        methods: {
            toggleShow: function () {
                this.showTotal = !this.showTotal; 
            }
        }
    });
    
</script>

表單控件

基本使用

text

設置文本框v-modelname

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

checkbox

通常的,使用多個複選框,被選中的值將會放入一個數組中。

<div id="app">
    
    <input type="checkbox" id="flash" value="flash" v-model="bizLines" />
    <label for="flash">快</label>

    <input type="checkbox" id="premium" value="premium" v-model="bizLines" />
    <label for="premium">專</label>

    <p>Checked lines: {{bizLines | json}}</p>

</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    new Vue({
        el: '#app',
        data: {
            bizLines: []
        },
        ready: function() {
            console.log( this.bizLines );
        }
    });
    
</script>

radio

單選按鈕被選擇時,v-dmoel中的變量值會被賦值爲對應的value值。

select

經過v-for指令來冬天生成option

<div id="app">
    
    <select v-model="bizLine">
        <option v-for="option in options" :value="option.value">
            {{option.value}} {{option.premium}}
        </option>
    </select>
    <p>bizLine: {{bizLine}}</p>
    
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    new Vue({
        el: '#app',
        data: {
            bizLine: 'falsh',
            options: [
                { text: '快', value: 'falsh' },
                { text: '專', value: 'premium' }
            ]
        }
    });
    
</script>

值綁定

checkbox

使用 :value 進行綁定

<input type="checkbox" id="falsh" :value="flash" v-model="bizLines" />
<label for="falsh"></label>

vm.bizLines === vm.flash

v-model

視圖與Model之間同步數據

lazy
通常的,v-model在input時間中同步輸入框的值與數據,能夠添加一個lazy特性。從而改到change事件中去同步。

<input v-model="msg" lazy /> <br />
{{msg}}

debounce
設置一個最小延遲,通常的在 AJAX 請求時,有效。

number
能夠在v-model所在的控件上使用number指令,該指令會在用戶輸入被同步到Model中時將其轉化爲數值類型,若是裝換結果爲NaN,則對應的Model值該是用戶輸入的原始值。

過濾器

過濾器,本質上都是函數,其做用在於用戶輸入數據後,它可以進行處理,並返回一個數據結果。

Vue支持在任何出現表達式的地方添加過濾器,除了{{}}mustache風格的表達式以外,還能夠在綁定指令的表達式後調用。

<span v-text="message | uppercase"></span>

過濾器能夠接收參數,參數跟在過濾器後面,參數之間以空格分隔。

<p>{{msg | filterFunction 'arg1' arg2}}</p>

過濾器函數始終以表達式的值做爲第一個參數,帶引號的參數會被看成字符串處理,而不帶引號的參數會被看成數據屬性名來處理。

Linux shell 的管道符號,上一個命令的輸出能夠做爲下一個命令的輸入。
Vue過濾器支持鏈式調用,上一個過濾器的輸出的結果能夠做爲下一個過濾器的輸入。

<span>{{'ddfe' | capitalize | reverse}}</span>
<!-- 
    -> 'ddfe' => 'Defe' => 'efeD'
    capitalize 過濾器: 將輸入字符串中的單詞的首字母大寫
    reverse過濾器: 反轉字符串順序 
-->

內置過濾器

字母操做

capitalize,uppercase,lowercase 三個過濾器用於處理英文字符。

capitalize 過濾器: 將表達式中的首字母轉大寫形式。
uppercase 過濾器:全部字母轉換爲大寫形式。
lowercase 過濾器:全部字母轉爲小寫形式。

json

json過濾器本質上時JSON.stringify(); 的精簡縮略版。
做用:將表達式的值轉換爲JSON字符串。

限制
limitBy,filterBy,orderBy 用於處理並返回過濾後的數組。 例如與v-for搭配使用。

limitBy

limitBy過濾器的做用時限制數組爲開始的前N個元素,其中N由傳入的第一個參數指定。第二個參數可選用於指定開始的偏移量。默認偏移量爲 0. 若是第二個參數爲3,則表示從數組下標第3個的地方開始計數。

<div v-for="item in tiems | limitBy 10"></div>

filterBy

第一個參數能夠是字符串或者函數。

<div v-for="item in times | fitlerBy 'hello'"></div>
<!-- 過濾出含有hello 字符串的元素 -->

orderBy

返回排序後的數組

<ul>
    <li v-for="user in users | orderBy 'lastName' 'firsetname' 'age'">{{user.lasetName}}--{{user.firsetName}}--{{user.age}}</li>
</ul>

自定義過濾器

fitler語法

Vue.filter(ID, function() {});

單參數

<div id="app">
    <p v-text="message | reverse"></p>
</div>

<script type="text/javascript">
    
    Vue.filter('reverse', function( val ) {
        return val.split('').reverse().join('');
    });
    
    new Vue({
        el: '#app',
        data: {
            message: 'abcdeq'
        }
    });
    
</script>

多參數

<div id="app">
    <p v-text="message | reverse 'before' 'after'"></p>
</div>

<script type="text/javascript">
    
    Vue.filter('reverse', function( val, begine, end ) {
        return begine + '---' + val + '---' + end;
    });
    
    new Vue({
        el: '#app',
        data: {
            message: 'abcdeq'
        }
    });
    
</script>

雙向過濾器

Vue支持把視圖(input元素)的值在寫回模型前進行轉化。

Vue.filter('MSG', {
    // model -> view
    // read 函數可選
    read: function() {
        console.log( 123 );
    },
    
    // view -> model
    // write函數將在數據被寫入Model以前調用
    // 兩個參數分別爲表達式的新值和舊值
    write: function( newVal, oldVal ) {
        console.log( newVal, oldVal );
    }
});

動態參數

若是過濾器參數沒有用引號包起來,則它會在當前vm做用域內動態計算。過濾器函數的this始終指向調用它的vm

<div id="app">
    <input type="text" v-model="userInp" />
    <p>{{msg | concats userInp}}</p>
</div>

<script type="text/javascript">
    
    Vue.filter('concats', function( val, inp ) {
        if (inp) {
            return val + inp;
        }
        return val;
    });
    
    new Vue({
        el: '#app',
        data: {
            msg: 'a'
        }
    });
    
    
</script>

過濾器注意點:
須要給定過濾器一個惟一標識。若是用戶自定義的過濾器和Vue內置的過濾器衝突,那麼Vue內置的過濾器將會被覆蓋。若是後註冊的過濾器和以前的過濾器衝突,則以前註冊的過濾器層被覆蓋。

過濾器函數的做用時輸入表達式的值,通過處理後輸出。所以,定義的函數最好能夠返回有意義的值。函數沒有return語句不會報錯,但這樣的過濾器沒有意義。

問題

filterBy/orderBy 過濾後$index 的索引

在使用 filterBy 或者 orderBy 對錶達式進行過濾時,若是同時須要將$index 做爲參數,此時的$index將會根據表達式數組或對象過濾後的值進行索引。

<div id="app">
    
    <ul>
        <li v-for="item in items | orderBy 'age'">
            {{item.msg}} -- {{$index}}
        </li>
    </ul>
    
</div>

<script type="text/javascript">

    new Vue({
        el: '#app',
        data: {
            items: [
                { msg: '順', age: 1 },
                { msg: '出', age: 10  },
                { msg: '快', age: 6 }
            ]
        }
    });
    
</script>

自定義 filter 的書寫位置

<script>
    // 第一種寫法
    Vue.filter('reverse', function () {

    });

    // 第二種寫法
    new Vue({
        el: '',
        data: {},
        fitlers: {
            // 自定義 filter事件的位置
            reverse: function () {

            }
        },
        methods: {}
    });

</script>

Vue實例方法

Vue實例提供一些有用的屬性和方法,這些屬性和方法名都已前綴$開頭

實例屬性

clipboard.png

組件樹訪問

  1. $parent 訪問當前組件實例的父實例

  2. $root 訪問當前組件書的根實例,當前組件沒有父實例,$root 表示當前組件的實例自己。

  3. $children 訪問當前組件實例的直接子組件實例。

  4. $refs 訪問使用v-ref指令的子組件。

DOM訪問

  1. $el 訪問掛載當前組件實例的DOM元素。

  2. $els 訪問$el元素中使用了v-el指令的DOM元素。

數據訪問

  1. $data 訪問組件實例觀察的數據對象,該對象引用組件實例化時選項中的data屬性。

  2. $options 用來訪問組件實例化時的初始化選項對象。

當實例建立後本來不存在的屬性,是沒法綁定在視圖上的。
可使用Vue.set(),vm.$set() 來解決.

實例方法

clipboard.png

$appendTo
$appednTo();方法用來將el所指的DOM元素或片斷插入到目標元素中。

參數:
elementOrSelector(字符串或DOM元素),該參數能夠是一個選擇器字符串或者DOM元素。
callback -- (可選,該回調函數會在el元素被插入到目標元素後背觸發。(若是在el上應用了過渡效果,則回調會在過渡完成後被觸發)

$before
用來將el所指的DOM元素或片斷插入到目標元素以前

參數:
elementOrSelector
callback-- (可選)

$after
將el所指的DOM元素或片斷插入到目標元素以後。

參數:
elementOrSelector
callback-- (可選)

$remove
將el所指的DOM元素或片斷從DOM中刪除
參數:
callback -- (可選)

$nextITick
在下次DOM更新循環後執行的回調函數,使用該方法能夠保證DOM中的內容已經與最新數據保持同步。
參數:
callback -- (可選)該回調函數會在DOM更新循環後被執行。它和全局的Vue.nextTick(); 方法同樣,不一樣的是,callback中的this會自動綁定到調用它的Vue實例上。

實例Event方法的使用

$on
監聽實例上的自定義事件

$once
監聽實例上的自定義事件,當之觸發一次。

$emit
觸發事件
參數:
event(字符串),該參數能夠是一個事件名稱
args (可選),傳遞給監聽函數的參數

$dispatch()
派發事件,即先在當前實例觸發,再沿着父鏈一層一層向上,若是對應的監聽函數返回false就中止。
參數:
event(字符串),該參數能夠是一個事件名稱
args (可選),傳遞給監聽函數的參數

$boradcast()
廣播事件,即遍歷當前實例的$children,若是對應的監聽函數false就中止。
參數:
event(字符串),該參數能夠是一個事件名稱
args (可選),傳遞給監聽函數的參數

$off()
刪除事件監聽器

參數:
event(字符串),該參數能夠是一個事件名稱
args (可選),對應的回調函數

若是沒有參數,即刪除全部的事件監聽器,若是隻提供一個參數--事件名稱,即刪除它對應的全部監聽器。若是提供兩個參數--事件名稱和回調函數,即刪除對應的這個回調函數。

組件

組件核心目標是:可重用性高,減小重複性的開發。

Vue的組件能夠理解爲預先定義好行爲的ViewModel類。一個組件能夠預約義選項。

組件核心選項:

  • 模板(template) -- 聲明瞭數據和最終展示給用戶的DOM之間的映射關係

  • 初始化數據(data) -- 一個組件的初始數據狀態。對於可複用的組件來講,一般是私有的狀態。

  • 接收的外部參數(props) -- 組件之間經過參數來進行數據的傳遞和共享。參數默認是單向綁定(由上至下),但也能夠顯示聲明爲雙向綁定。

  • 方法(methods) -- 對數據的改動操做通常都在組件的方法內進行。能夠經過v-on指令將用戶輸入事件和組件方法進行綁定

  • 生命週期鉤子函數 -- 一個組件會觸發多個生命週期鉤子函數,好比:createdattacheddestoryed等。在這些鉤子函數中,能夠封裝一些自定義的邏輯,和傳統的MVC想必,着能夠理解爲Controller的邏輯被分散到了這些鉤子函數中。

基礎

註冊

全局註冊

Vue.component('wind-component', WindComponet);

參數:
function, 能夠是Vue.extend();建立的一個組件構造器,
Object ,Vue在背後自動調用Vue.extend();

組件的模板替換了自定義元素,自定義元素的做用只是做爲一個掛載點,能夠用實例replace決定是否替換自定義元素。

局部註冊

不須要每一個組件都全局註冊,可讓組件只能用在其它組件內。可使用 實例選項中componets註冊

<div class="app">
    <wind-component></wind-component>
</div>


<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    var Child = Vue.extend({
        template: '<div>I am Child</div>'
    });
    
    var Prent = Vue.extend({
        template: '<div>I am Parent</div> <Child></Child>',
        components: {
            child: Child
        }
    });
    
    new Vue({
        el: '.app',
        components: {
            'wind-component': Prent
        }
    });
        
</script>

爲了讓事件更簡單,能夠直接傳入選項對象而不是構造器給Vue.component(); 和 components選項

數據傳遞

Vue組件三種數據傳遞方式:

  • props

  • 組件通訊

  • slot

props

'props'是組建數據的一個字段,指望從父組件傳下來數據。由於組件的實例的做用域是孤立的,着意味着不能而且不該該在子組件的模板內直接引用父組件的數據,因此子組件須要顯示的用props選項來獲取父組件的數據。props選項能夠是字面量,也能夠是表達式,還能夠綁定修飾符。

字面量語法

<div class="app">
    
    <child msg="wind"></child>
    
</div>

<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    
    // 字面量
    var Child = Vue.component('child', {
        props: ['msg'],
        template: '<div>{{msg}}</div>'
    });
    
    new Vue({
        el: '.app',
        components: {
            child: Child
        }
    });
    
</script>

動態語法

能夠利用v-bind將動態props綁定到父組件的數據。每當父組件的數據變化時,該變化也會傳到給子組件。
動態語法:在父級組件連接 :wind="msg"。只能在Vue.extend({}).

<div class="app">
    
    <child msg="wind"></child>
    
</div>

<script src="vue1.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    // 動態語法  // v-bind
    var Child = Vue.extend({
        props: ['wind'],
        template: '<div>{{wind}}</div>',
//                replace: true
    });
    
    var Parent = Vue.extend({
        template: '<p>parent</p><br /><child :wind="msg"></child>',
        data: function () {
            return {
                'msg': 'msgConent'
            };
        },
        components: {
            'child': Child
        }
    });
    
    new Vue({
        el: '.app',
        components: {
            child: Parent
        }
    });
    
</script>

綁定修飾符

props默認是單向綁定 -- 當父組件的屬性變化時,將傳導給子組件,可是反過來不會。着是爲了防止子組件無心修改父組件的狀態。

  • .sync,雙向綁定

  • .once, 單次綁定

雙向綁定會把子組件的msg屬性同步會父組件的parentMsg屬性

<!-- 默認爲單項綁定 -->
<child :msg="parentMsg"></child>
<!-- 雙向綁定 -->
<child :msg.sync="parentMsg"></child>
<!-- 單詞綁定 -->
<child :msg.once="parentMsg"></child>

雙向綁定會把子組件的msg屬性同步到父組件的parentMsg屬性,單次綁定在創建以後不會同步以後的變化。若是props是一個對象或數組,那麼它是按引用傳遞的。在子組件內修改會影響父組件的狀態,而無論是用哪一種類型綁定。

組件通訊

子組件能夠用this.$parent訪問它的父組件,父組件有一個數組this.$children,暴行它全部的子元素,根實例的後代能夠用this.$root訪問根實例,不過子組件應當避免直接依賴父組件的數據,儘可能顯式的使用 props傳遞數據。

在子組件中修改父組件的狀態缺點:

  • 父組件與子組件緊密地耦合

  • 只看父組件,很難理解父組件的狀態,由於它可能被任意子組件修改。在理解狀況下,只有組件本身能修改其狀態。

由於做用域是有層次的,因此能夠在做用域鏈上傳遞時間。
通常的,選擇事件傳遞方式,判斷規則: 查看要觸發事件的做用域。若是要通知整個事件系統,就要向下廣播。

每個Vue實例都是一個事件觸發器:

  • $on() -- 監聽事件

  • $emit() -- 把事件沿着做用域向上派送

  • $dispatch() -- 派發事件,事件沿着父鏈冒泡。 調用

  • $broadcast() -- 廣播事件,事件向下傳導給全部的後代

<template id="child-template">
    <input v-model="msg" />
    <button @click="notify">Dispatch Event</button>
</template>

<div id="app">
    <p>Messages: {{messages | json}}</p>
    <child></child>
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    
    // 註冊子組件
    // 將當前消息派發出去
    Vue.component('child', {
        template: '#child-template',
        data: function() {
            return {
                msg: 'hello'
            }
        },
        methods: {
            notify: function () {
                if ( this.msg.trim() ) {
                    this.$dispatch('child-msg', this.msg);
                    this.msg = '';
                }
            }
        }
    });
    
    // 初始化父組件
    // 收到消息時將事件推入一個數組中
    var parent = new Vue({
        el: '#app',
        data: {
            messages: []
        },
        // 在建立實例時 `events` 選項簡單的調用`$on`
        events: {
            'child-msg': function ( msg ) {
                // 事件回到內的`this` 自動綁定到組冊它的實例上
                this.messages.push(msg);
            }
        }
    });
    
</script>

從父組件的代碼中不能直接觀看到child-msg 事件來自哪裏。若是在模板中子組件用到的地方聲明事件處理器。 可使用v-on來監聽。

<template id="child-template">
    <input v-model="msg" />
    <button @click="notify">Dispatch Event</button>
</template>

<div id="app">
        <p>Message {{messages | json}}</p>
        <child @child-msg="shandleIt"></child>
</div>


<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    // 組冊子組件
    Vue.component('child', {
        template: '#child-template',
        data: function () {
            return { msg: 'hello' }
        },
        methods: {
            notify: function () {
                if ( this.msg.trim() ) {
                    this.$dispatch('child-msg', this.msg)
                    this.msg = '';
                }
            }
        }
    });
    
    
    // 初始化父組件
    new Vue({
        el: '#app',
        data: {
            messages: []
        },
        methods: {
            'shandleIt': function () {
                alert(123);
            }
        },
        events: {
            'child-msg': function ( msg ) {
                if ( msg ) {
                    this.messages.push(msg);
                }
            }
        }
    });
    
</script>

當子組件觸發了child-msg 事件時,父組件的 hadleIt方法將被調用。全部影響父組件狀態的代碼都放到父組件的hadleIt方法中。 子組件只關注觸發事件。

儘管有propsevents,可是有時候仍須要在JavaScript中直接訪問子組件。所以,須要使用v-ref爲子組件指定一個索引ID。

v-ref 直接訪問子組件

<div id="app">
    <comp v-ref:aa></comp>
    <comp v-ref:bb></comp>
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script>

    Vue.component('comp', {
        template: '<div>嘻嘻哈哈</div>',
    });
    
    new Vue({
        el: '#app',
        data: {
            msg: []
        },
        ready: function () {
            console.log( this.$refs.aa );
            console.log( this.$refs.bb );
        }
    });

</script>

slot分發內容

場景:
使用組件時,經常須要組合使用:

<pink>
    <pink-header></pink-header>
    <pink-footer></pink-footer>
</pink>

注意:

  • <pink>組件不知道他的掛載點會有什麼內容,掛載點的內容是由<pink>的父組件決定的。

  • <pink>組件極可能有它本身的模板。

爲了讓組件能夠組合,須要一種方式來混合父組件的內容與子組件本身的模板。稱之爲:內容分發
Vue使用特殊的<slot>元素左右原始內容的插槽

定義在父組件中,父組件中嵌套的其它內容不會被替換。

編譯做用域

分發內容是在各自做用域中被編譯。
父組件模板的內容在父組件做用域內編譯,子組件模板的內容在子組件做用域內編譯。

單個 slot

父組件的內容被拋棄,除非子組件模板包含<slot>.若是子組件模板只有一個沒有特性的slot,父組件的整個內容將查到slot所在的地方並替換它。

<slot>標籤的內容視爲回退內容。回退內容在子組件的做用域內編譯,當宿主元素爲空而且沒有內容供插入時顯示這個回退內容。

<template id="pink">
    <div>
        <h1>This is my component!</h1>
        <slot>
            若是沒有分發內容則顯示我
        </slot>
    </div>
</template>

<div id="app">
    <pink-component>
        <p>This is some original conent</p>
        <p>This is some more original conent</p>
    </pink-component>
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    Vue.component('pink-component', {
        template: '#pink'
    });
    
    new Vue({
        el: '#app',
    });
    
</script>

具名slot

<slot>元素能夠用一個特殊特性name配置如何分發內容。多個slot能夠有不一樣的名字。具名slot將皮撇內容片斷中有對應slot特性的元素。

·具名slot·仍然能夠有一個匿名slot.做爲找不到匹配的內容片斷的回退插槽,它是默認slot。若是沒有默認slot,這些找不到匹配的內容片斷將被拋棄。

<template id="pink">
    
    <div>
        <slot name="a"></slot>
        <slot></slot>
        <slot name="b"></slot>
    </div>    
    
</template>

<div id="app">
    
    <pink-multi>
        <p slot="a">ONE</p>
        <p slot="b">TWO</p>
        <p>defalut A</p>
    </pink-multi>

</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
    
    Vue.component('pink-multi', {
        tempate: '#pink'
    });
    
    new Vue({
        el: '#app'
    });
    
</script>

混合

以一種靈活的方式爲組建提供分佈複用的功能。混合對象能夠包含任意的組件選項。
當組件使用了混合對象時,混合對象的全部選項將別「混入」組件本身的選項中。

<div id="app">
    <mixin-com></mixin-com>
</div>

<script type="text/javascript">
    
    Vue.config.debug = true;
    
    // mixin對象
    var myMixin = {
        created: function () {
            this.hello();
        },
        methods: {
            hello: function (){
                console.log( 'hello from mixin!' );
            }
        }
    }
    
    // 定義組件,使用 mixin對象
    var mixinCom = Vue.extend({
        mixins: [myMixin],
        template: '<h1>HELLO ~ </h1>'
    });
    
    // 建立根實例
    new Vue({
        el: '#app',
        components: {
            'mixin-com': mixinCom
        }
    });
    
</script>

HTML中是不區分大小寫,而JavaScript是區分大小寫。在給組件取屬性名時,要注意大小寫問題。儘可能使用小寫加中橫線


當混合對象和組件包含同名選項時,這些選項將以適當的策略合併。
例如:同名鉤子函數被併入一個數組中,於是都會被調用。另外,混合的鉤子函數將在組件本身的鉤子以前調用。

<div id="app">
    <my-componet></my-componet>
</div>

<script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">

    var myMixin = {
        created: function () {
            this.hello();
        },
        methods: {
            hello: function () {
                console.log('hello from mixin~');
            }
        }
    }
    
    // 定義組件,使用混合對象
    var com = Vue.extend({
        mixins: [myMixin],
        template: '<h1>HELLO ~</h1>',
        created: function () {
            console.log('component hook called');
        }
    });
    
    // 建立根實例
    new Vue({
        el: '#app',
        components: {
            'my-componet': com
        }
    });

</script>

混合全局註冊,一旦全局註冊混合,它就會影響全部以後建立的Vue實例。
慎用全局混合,由於它會影響到每一個所建立的Vue實例,包括第三方組件。大多數狀況下,它應當只用於自定義選項。

動態組件

多個組件可使用同一個掛載點,而後動態的在他們之間切換。使用保留的<component>元素,懂她id綁定到它的is特性上。

<component :is="show"></component>

<script>
new Vue({
    data: {
        show: true
    }
});
</script>

keep-alive

做用:切換組件時,保留組件狀態。減小內存開銷。

<component :is="currentView" keep-alive></component>

activate鉤子

做用: 控制切換組件的切換時間。切入組件添加activate 鉤子函數

Vue.component('actiate-exp', {
    activate: function ( done ) {
        var self = this;
        loadDataAsync(function ( data ) {
            self.smoeData = data;
            done();
        });
    }
});

activate 鉤子只做用於動態組件切換或靜態組件初始化渲染的過程當中,不做用於使用實例方法手工插入的過程當中。

transition-mode

transition-mode 特性用於指定連個動態組件之間如何過渡。

在默認狀況下,進入與離開平滑的過渡。

  • in-out --- 新組建先過分進去,等它的過去完成以後當前組件過渡出去。

  • out-in 當前組件先過渡出去,等它過渡完成後新組件過渡進入

<!-- 先淡出再淡入 -->

<component :is="view" transition="fade" transiion-mode="out-in"></component>

<style>
    .fade-transition {
        transtion: opacity .3s ease;
    }
    .fade-enter, .fade-leave {
        opacity: 0;
    }
</style>

擴展

組件和 v-for

自定義組件能夠像普通元素同樣直接使用v-for
由於組件的做用域是孤立的,沒法將數據傳遞那個到組件內部。

<pink v-for="item in items" :item="item" :index="$index"></pink>
<!-- 顯式聲明數據來自哪裏可讓組件複用再其它地方 -->
<div id="app">
    <pink v-for="item in msg" :wind="item" :item="item" :index="$index"></pink>
</div>        

<script type="text/javascript">
    
    Vue.component('pink', {
        props: ['wind'],
        template: '<div>pink -- {{wind}}</div>'
    });
    
    new Vue({
        el: '#app',
        data: {
            msg: ['pink', 'tan', 'red', 'yellow']
        }
    });
    
</script>

編寫可複用組件

在編寫組件時,時刻考慮組件是否可複用是否有好處的。
一次性組件跟其它組件緊密耦合不要緊,可是可複用組件必定要定義侵襲的公開接口。

Vue組件 API來自三部分 -- prop, Evnetslot

  • prop容許外部環境傳遞數據組給組件

  • 事件容許組件發出發佈環境的action

  • slot運行外部環境將內部插入到組件的視圖結構內。

使用v-bindv-on的簡寫語法,模板的縮進清楚並簡潔

異步組件須要將應用拆分爲小塊,每塊按實現按需加載。Vue容許將組建定義爲一個工廠函數,動態的解析組件的定義。Vue只在組件須要渲染時觸發工廠函數,並把結果緩存起來。

Vue.component('async-exp', function ( resoluve, reject ) {
    setTimeout(function () {
        reslove({
            tempate: '<div>ASYNC!</div>'
        });
    }, 1000);
});

工廠函數接受一個resolve回調,在收到從服務器下載的組件定義時調用。

片斷實例

在使用template選項時,模板的內容將替換實例的掛載元素,於是推薦模板的頂級元素始終是單個元素。

下面的狀況會讓實例變成一個片斷實例

  • 模板包含多個頂級元素

  • 模板只包含普通文本

  • 模板包含其餘組件(其它組件多是一個片斷實例)

  • 模板只包含一個元素指令,如<partial> 或 vue-router的<router-view>

  • 模板根節點有一個流程控制指令,如 v-if 或 v-for

讓實例有未知數據的頂級元素,它將把其DOM內容看成片斷。片斷實例仍然會正確的渲染內容。不過沒有一個根節點,它的$el指向一個錨節點,即一個空的文本節點(在開發模式下是一個註釋節點)

組件元素上的非流程控制指令,非prop特性和過分將被忽略。

<!-- 不能夠,由於沒有根元素 -->
<examplte v-show="ok" transition="fade"></examplte>
<!-- props 能夠 -->
<examplte :prop="someData"></examplte>
<!-- 流程控制能夠,可是不能有過渡 -->
<examplte v-if="ok"></examplte>

生命週期

在vue中,在實例化Vue以前,他們以HTML的文本形式保存在文本編輯器中。當實例化後將經歷建立,編譯,銷燬 主要三個階段

生命週期鉤子:

  1. init
    在實例化開始初始化時同步調用。此時數據觀測,事件和Watcher 都還沒有初始化

  2. created
    在實例建立後同步調用。此時實例已經結束解析選項,意味着已創建:數據綁定,計算屬性,方法,Watcher/事件回調。可是尚未開始DOM編譯,$el還不存在。

  3. beforeCompile
    在編譯開始前調用。

  4. compiled
    在編譯結束後調用。此時全部的指令已生效,於是數據的變化將觸發DOM更新。可是不是擔保$el已插入文檔。

  5. ready
    在編譯結束和$el第一次插入文檔以後調用,入在第一次attatced鉤子以後調用。注意必須是有Vue插入(如vm.$appendTo()等方法或更新)纔出發ready鉤子的。

    //  { 模板插入到文檔中了;至關於window.onload }
  6. attached
    vm.$el 操做如DOM時調用。必須是→指令實例方法(如$appednTo()) 插入,直接操做vm.$el不會觸發這個鉤子

  7. detached
    vm.$el從DOM中刪除時調用。必須是由指令實例方法刪除,直接操做vm.$el不會觸發這個鉤子

  8. beforeDestroy
    在開始銷燬實例時開始調用。此時實例仍然有功能。

  9. destroyed
    在實例被銷燬以後調用。此時全部的綁定和實例的指令已經解綁,全部的子實例也已經被效果。若是有離開過渡,dsetroyed鉤子在過渡完成以後調用。

開發組件

組件格式,把一個組件的模板,樣式,邏輯三要素整合在同一個文件中,即方便開發,也方便複用和維護。Vue自己支持對組件的異步加載,配合webpack的分塊打包功能,能夠實現組件的異步按需加載。

基於第三方組件開發

<scirpt>
    
import Chart from 'chart.js'

</scirpt>

問題

camelCase & kebab-case

HTML標籤中的屬性名不區分大小寫。設置prop名字爲camelCase形式的時候,須要裝歡爲keba-case形式在HTML中使用。

<!-- HTML中必須是短橫線分割 -->
<child my-message="hello"></child>

<script type="text/javascript">
    Vue.componet('child', {
        props: ['myMessage'],
        template: '<span>{{myMessage}</span>'
    });
</script>

字面量語法&動態語法

錯誤用法:
使用字面量語法傳遞數值。

<!-- 傳遞字符串 「1」 -->
<comp some-prop="1"></comp>

由於它是一個字面量prop,它的值是字符串「1」,而不是一實際的數字傳下去。若是須要傳遞真實的JavaScript類型的數字,則須要使用動態語法。從而讓它的值被看成JavaScript表達式計算。

<comp :some-prop="1"></comp>

組件選項問題

傳入Vue構造器的多數選項也能夠用Vue.extend();不過有兩個特列:datael.
場景:簡單的吧一個對象做爲data選項傳給Vue.extend();

var data = { a: 1 };
var MyComponent = Vue.extend({data: data});

存在的問題:MyComponent全部的實例哦給你共享同一個data對象。
解決方式:使用一個函數做爲data選項,讓這個函數返回一個新對象。

var MyComponent = Vue.extend({
    data: function () {
        return { a: 1 }
    }
});

模板解析

Vue的模板是DOM模板,使用瀏覽器元素的解析器而不是本身實現一個。
DOM模板缺點:必須是有效的HTML片斷。

一些HTML元素對什麼元素均可以放在它裏面有限制。

  • a 不能包含其餘交互元素(如,按鈕、鏈接)

  • ul和ol只能包含li

  • select 只能包含option和optgroup

  • table只能直接包含thead,tbody,tfoot,tr,caption,col,colgroup

  • tr只能直接包含th和td

自定義標籤(包括自定義元素和特殊標籤,如<component>.<template>,<partal>) 不能用在ul,select,table等對內部元素有限制的標籤內。放在這些元素內部的自定義標籤將被提到呀U尿素外面,於是渲染不正確。

自定義元素應當使用is特性。

<table>
    <tr :is="my-component"></tr>
</table>

如何解決數據層級結構太深的問題

使用vm.$set()手動定義一層數據

vm.$set('depAirprotZh', ticketInfo.flight.fromSegments[ticketInfo.flight.fromSegments.length - 1].depAirprotZh);

$set用法:
參數:
{String} keyPath
{*} value

設置Vue市裏的屬性值。在多數狀況下應當使用普通對象語法。如vm.a.b=123.
這個方法只能適用:

  • 使用keyPath動態的設置屬性

  • 設置不存在的屬性。

若是keyPath不存在,將遞歸的建立並創建追蹤。若是用它建立頂級屬性,實例將被強制進入"digset循環",在此過程當中從新計算全部Watcher。

var vm = new Vue({
    data: {
        a: {
            b: 1
        }
    }
});

// keypath 存在
vm.$set('a.b', 2);
vm.a.b // -> 2

// keypath 不存在
vm.$set('c', 3);
vm.c // -> 3

後端數據交互

配合vue-router

new Vue({
    el: '#app',
    data: {
        todos: []
    },
    created: function () {
        this.$http
            .get()
            .hten(function ( data ) {
                this.todos = data;
            })
    }
});

配合Jquery的AJAX

new Vue({
    el: '#app',
    data: {
        todos: []
    },
    created: function () {
        $.get('')
            .done(function ( data ) {
                    this.todo = data;
            });
    }
});

data中沒有計定義計算屬性,它是如何被使用的

沒有把計算數據放到$data裏面去,而是經過Object.definePrototype(this, key,def) 直接定義到了實例上。

ES6

ES6中的模塊,let 和 const

模塊

export

在ES6中,一個文件就是一個模塊,一個模塊內部的全部變量,對於外部來講是沒法獲取的,觸發是喲個關鍵詞exprot對外暴露接口,暴露的各個接口經過名字來進行區分。

const sqrt = Math.sqrt;

function square ( x ) {
    return x * x;
}
function diag ( x, y ) {
    return sqrt(square(x) + square(y));
}

// 經過export 暴露接口。使用大括號指定要暴露的接口
export {sqrt, square, diag}

import
經過import命令加載這個模塊(文件).

/**
 * 注意大括號中的接口名必須在lib.js模塊中暴露。
 */
import { square, diag } from './lib';

import 能夠經過as語法取別名

improt {myVar1 as myCustomVar1}  from './lib';

import 會指定加載模塊,所以有空的import語法

// 值加載執行模塊,不引用任何接口
import './lib'

import能夠總體加載模塊,達到命名空間的效果。

// lib.js
export var myVar1 = ...;
export let myVar2 = ...;
exprot const MY_COMST = ...;

export function myFunc () {
    ...
}

exprot function* myGeneratorFunc () {
    ...
}

export class MyClass {
    ...
}

// mian.js

import * as lib from './lib';

console.log(lib.myVar1);
console.log(lib.myVar2);

new lib.MyCalss();

export default

場景:即便用模塊接口的人必須知道該模塊export了哪些接口,有時候一個模塊實際上只對外暴露一個接口,這個時候沒有必要限定暴露的接口名字。
可使用export default語法讓模塊調用者自定義要導入的接口名字。

// myFunc.js
export defalut function () {
    
}

/**
 * 注意:myFunc 不能包含在`{}`裏。myFunc能夠替換任意變量名。
 */
// main.js
import MyFunc from 'myFunc';

MyFunc();

export/import在Vue.js中的使用

Vue採用export/import進行模塊化開發,文件經過exprot暴露接口,經過improt引用其它文件內容。

模塊和組件的區別

Module: 
An implementation unit of software that provides a coherent set of responsibilities.

Component:
A component is a reusable building block that can be combined with other components in the same or other computers in a distributed network to form an application.

vue-cli

基礎工具:目錄結構本地調試代碼部署熱加載單元測試

安裝: npm install vue-cli

vue-cli運行以後目錄結構

目錄或文件 說明
build webpack配置相關
config webpack配置相關
node_modules npm install 安裝依賴代碼庫
src 存放源碼
-- main.js 入口組件
static 第三方靜態資源
-- .gitkeep 文件目錄爲空也能夠提交到代碼倉庫
.babelrc babel 配置文件
.editorconfig 編輯器配置
.eslintignore 忽略語法檢查的目錄設置
.eslintrc.js eslint的配置文件
.gitignore git 忽略文件或目錄提交
index.html 入口文件
package.json 項目的配置文件

.babelrc

{
  "presets": ["es2015", "stage-2"], # 預設插件 (babel轉換預先須要安裝的插件)  // stage-2 四級 (1,2,3,4)包括了 es2015中沒有的插件
  "plugins": ["transform-runtime"], # 插件
  "comments": false # false 表示轉換成代碼不生成註釋
}

.editorconfig

root = true

[*]
charset = utf-8 # 編碼
indent_style = space # 縮進風格 (基於空格做爲縮進風格)
indent_size = 2 # 縮進大小
end_of_line = lf # 換行符風格, lf是linux換行符風格
insert_final_newline = true # 建立文件,會自動在末尾插入新行
trim_trailing_whitespace = true # true,自動行尾多餘風格

.eslintignore

build/*.js # build 文件夾底下的全部文件
config/*.js # config 文件夾底下的全部文件

.eslintrc.js

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style // 語法規則地址
  extends: 'standard', // standard 表示繼承一個標準的規則,在vue-cli建立過程當中會選擇.
  // required to lint *.vue files
  plugins: [
    'html'
  ],
  // add your custom rules here
  'rules': { // 配置部分自定義規則
    // allow paren-less arrow functions
    'arrow-parens': 0, // 箭頭函數前面容許不寫括號 (值設置爲0,表示忽略檢查)
    // allow async-await
    'generator-star-spacing': 0, // async-await 使用
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 // 不容許在代碼中有這些選項,生產環境不容許有 debugger
  }
}

package.js

"dependencies": { # 項目生產下的依賴

},
"devDependencies": { # 編譯過程當中的依賴
}

webpack打包

weback.base.conf.jswebapck基本配置

var path = require('path')
var config = require('../config') 
var utils = require('./utils')
var projectRoot = path.resolve(__dirname, '../') // 項目根目錄

module.exports = {
  entry: {
    app: './src/main.js' // 入口文件
  },
  output: {
    path: config.build.assetsRoot, // 打包的根目錄名字
    publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, // 根目錄
    filename: '[name].js' // 對應 entry 的key名字
  },
  resolve: { // 設置在 require() 或者import 模塊一些相關配置
    extensions: ['', '.js', '.vue'], // 自動補全文件後綴
    fallback: [path.join(__dirname, '../node_modules')], // require() 找不到模塊,會充 node_modules模塊中尋找 
    alias: { // 別名
      'src': path.resolve(__dirname, '../src'), // require 的時候 使用的別名
      'assets': path.resolve(__dirname, '../src/assets'),
      'components': path.resolve(__dirname, '../src/components')
    }
  },
  resolveLoader: {  // require() 找不到模塊,會充 node_modules模塊中尋找
    fallback: [path.join(__dirname, '../node_modules')] 
  },
  module: {
    preLoaders: [// preLoaders 會在loader以前對文件進行處理  // 對某種類型的文件 應用 某個loader進行處理
      {
        test: /\.vue$/,
        loader: 'eslint',
        include: projectRoot, // 檢查的文件。 只對該文件下的文件進行檢查
        exclude: /node_modules/ // 排除這些目錄,進行該loader處理
      },
      {
        test: /\.js$/,
        loader: 'eslint',
        include: projectRoot,
        exclude: /node_modules/
      }
    ],
    loaders: [ // 對某種類型的文件 應用 某個loader進行處理
      {
        test: /\.vue$/,
        loader: 'vue'
      },
      {
        test: /\.js$/,
        loader: 'babel',
        include: projectRoot,
        exclude: /node_modules/
      },
      {
        test: /\.json$/,
        loader: 'json'
      },
      {
        test: /\.html$/,
        loader: 'vue-html'
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url',
        query: { 
          limit: 10000, // 文件大小小於 10000kb 的時候生產 base64的文件
          name: utils.assetsPath('img/[name].[hash:7].[ext]') // 文件名的規則 生產
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  eslint: { 
    formatter: require('eslint-friendly-formatter') // 檢查錯誤友好的提示錯誤信息 並提供 es6語法的官網連接
  },
  vue: {
    loaders: utils.cssLoaders() // .vue文件中CSS處理的loader
  }
}

webpack.dev.conf.js dev環境下的webpack配置

var config = require('../config')
var webpack = require('webpack')
var merge = require('webpack-merge')
var utils = require('./utils')
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')

// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) { // hot relaod 相關代碼 // 改變源碼在瀏覽器不刷新的狀況下,可以看到更新後的視圖.
  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

module.exports = merge(baseWebpackConfig, {
  module: { 
    // 獨立對 CSS預處理文件進行編譯
    loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // eval-source-map is faster for development
  devtool: '#eval-source-map', 
  plugins: [
    new webpack.DefinePlugin({ // 把源碼中的 `process.env` 替換成 config.dev.env
      'process.env': config.dev.env
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.optimize.OccurenceOrderPlugin(), // webpack 優化插件. 對插件使用的頻率
    new webpack.HotModuleReplacementPlugin(), // hot realod
    new webpack.NoErrorsPlugin(), // 編譯錯誤,會跳過那段代碼
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({ // 經過
      filename: 'index.html', // 編譯生成的文件名
      template: 'index.html', // 處理的模板
      inject: true // 表示打包的時候,路徑自動添加到index.html中. css 的路徑會自動添加到 head頭部, js會默認添加到body中
    })
  ]
})

dev-server.js dev運行文件

var path = require('path')
var express = require('express')
var webpack = require('webpack')
var config = require('../config')
var proxyMiddleware = require('http-proxy-middleware')
var webpackConfig = process.env.NODE_ENV === 'testing'
  ? require('./webpack.prod.conf')
  : require('./webpack.dev.conf')

// default port where dev server listens for incoming traffic
var port = process.env.PORT || config.dev.port  // 端口號
// Define HTTP proxies to your custom API backend
// https://github.com/chimurai/http-proxy-middleware
var proxyTable = config.dev.proxyTable // 代理的接口

var app = express()
var compiler = webpack(webpackConfig) // 編譯webapck配置

var devMiddleware = require('webpack-dev-middleware')(compiler, {  // webpack專門爲express開發的中間件.
  publicPath: webpackConfig.output.publicPath, // 靜態資源訪問目錄
  stats: {
    colors: true,
    chunks: false
  }
})

var hotMiddleware = require('webpack-hot-middleware')(compiler) // 訪問的app文件,並無生產到項目目錄中,而是在內存中,該中間件作了處理,放入內存中.
// force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function (compilation) {
  compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
    hotMiddleware.publish({ action: 'reload' })
    cb()
  })
})

// proxy api requests
Object.keys(proxyTable).forEach(function (context) { // 處理代理接口
  var options = proxyTable[context]
  if (typeof options === 'string') {
    options = { target: options }
  }
  app.use(proxyMiddleware(context, options))
})

// handle fallback for HTML5 history API
app.use(require('connect-history-api-fallback')())

// serve webpack bundle output
app.use(devMiddleware) // 使用自定義中間件

// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware) // 使用自定義中間件

// serve pure static assets
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) // 處理靜態資源目錄
app.use(staticPath, express.static('./static')) //  靜態資源目錄

module.exports = app.listen(port, function (err) { // 監聽
  if (err) { 
    console.log(err)
    return
  }
  console.log('Listening at http://localhost:' + port + '\n')
})

項目目錄

`src`全部源碼目錄
-`main.js`入口文件 
-`App.vue` 整個頁面是實例文件

-`components` 組件目錄
--`header` 子組件目錄
---`header.vue` 具體的組件

--`common` 公共資源
---`js`  基礎庫
---`stylus` css預處理器
---`fonts` 字體庫

數據傳遞

props

1. 變量名 = data --> 自定義組件的自定義屬性
2. props 在child, 變量名在child



父級到子級:

父級:
$broadcast
子級:
evnets: {
    events: function () {
    }
}


子級到父級:

父級:
evnets: {
    events: function () {} 
}

子級:
$dispatch

配置選項

new Vue(options)

  • el

  • data

  • methods

  • components

  • computed

  • wtach

  • replace


  • init

  • created

  • beforeCompile

  • compiled

  • ready

  • attached

  • detached

  • beforeDestroy

  • destoryed


  • events

  • mixins: [mixin]

var vm = new Vue({

    el: '選擇器', // 掛載到頁面的那個元素裏,即肯定vue的做用範圍,外部能夠經過 vm.$el 訪問,獲得的是一個原生dom元素,可進行對應操做
    
    a: '', // 自定義屬性, 外部課經過vm.$options 訪問

    data: {}, // 實例屬性,外部經過實例名, 即vm.$data調用

    computed: {}, // 計算屬性, 也是實例屬性, 只是以方法的形式存在,並能夠有邏輯運算的屬性

    method: {}, // 實例方法

    wtach: {}, // 對data和computed的屬性進行監聽,當屬性有變化時,自動觸發,以方法的形式存在 外部經過$.watch調用

    // 以上屬性和方法,實例內部都經過 this調用,外部則經過對應的實例方法訪問.

    // 在vue的生命週期過程當中,提供了一系列的鉤子函數,進行自定義邏輯注入

    created: function () { // 實例已經建立 },

    beforeCompile: function () { // 模塊編譯以前 }, 

    compiled: function () { // 模塊編譯以後,即模板佔位符被是內容替換 },

    ready: function () { // 模板插入到文檔中, 至關於window.onload },

    // 上面4個方法,在對象被實例化後即按順序執行

    beforeDestroy: function () { // 對象銷燬以前 },

    destroyed: function () { // 對象銷燬以後 }

    // 上面2個方法需經過事件主動觸發, vm.$destory(); 才執行 
});

Vue.extend(options)

  • template

  • data

  • props

  • components

  • name

  • mixins: [mixin]

  • methods

Vue.component(id, options)

  • props (array | object)

  • templalte

  • methods

  • data

相關文章
相關標籤/搜索