一文速覽Vue全棧


一文速覽Vue全棧

Vue 是一套用於構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用,專注於聲明式渲染視圖層,結合豐富的生態系統和核心插件,致力於簡單靈活快速驅動SPA、MPA等大小型應用

本文依次介紹 雙向數據綁定計算屬性組件事件機制插件機制前端路由狀態管理服務端渲染等。

1. Vue實例與數據綁定

實例

Vue.js應用的創建很簡單,通過構造函數 Vue 就可以創建一個 Vue 的根實例,並啟動 Vue;

var app = new Vue({
    //選項
});

變量 app 就代表了這個 Vue 實例,事實上幾乎所有的代碼都是一個對象,用來寫入 Vue 實例的選項內的。

首先,必不可少的一個選項就是el,el用於指定一個頁面中己存在的DOM元素來掛載Vue 實例,它可以是 HTMLElement ,也可以是CSS選擇器,比如:

<div id='app'></div>
var app =new Vue({
    el: document.getElementByld('app')  // 或者是'#app'
});

一個 Vue 應用由一個通過 new Vue() 創建的根Vue實例,以及可選的嵌套的、可復用的組件樹組成。

數據綁定

當一個 Vue 實例被創建時,它將 data 對象中的所有的屬性加入到 Vue 的響應式系統中。當這些屬性的值發生改變時,視圖將會產生“響應”,即匹配更新為新的值。

建議所有會用到的數據都預先在data內聲明,這樣不至於將數據散落在業務邏輯中,難以維護。
Vue實例本身也代理了 data對象里的所有屬性,所以可以這樣訪問:

var app = new Vue({
    el: '#app',
    data: {
        a: 2
    }
});
console.log(app.a);  // 2

除了顯式地聲明數據外,也可以指向一個己有的變量,並且它們之間默認建立了雙向綁定,當修改其中任意一個時,另一個也會一起變化:

var myData = {
    a: 1
};
var app =new Vue({
    el: '#app',
    data: myData
});
console.log(app.a) ; // 1
//修改屬性,原數據也會隨之修改
app.a = 2;
console.log(myData.a); // 2
//反之,修改原數據, Vue屬性也會修改
myData.a = 3;
console.log(app.a); // 3

生命周期

每個 Vue 實例創建時,都會經歷一系列的初始化過程,同時也會調用相應的生命周期鈎子, 我們可以利用這些鈎子,在合適的時機執行我們的業務邏輯。

Vue的生命周期大致分為四個階段:

beforeCreate(此時date、method和el均沒有初始化,可以在此加載loading)
created(此時date和method初始化完成,但是DOM節點並沒有掛載,判斷是否有el節點,如果有則編譯template,如果沒有則使用vm.

beforeMount(編譯模板,並且將此時在el上掛載一個虛擬的DOM節點)
mounted(編譯模板,且將真實的DOM節點掛載在el上)

beforeUpdate(在數據有更新時,進入此鈎子函數,虛擬DOM被重新創建)
updated(數據更新完成時,進入此鈎子函數)

beforeDestory(組件銷毀前調用,此時將組件上的watchers、子組件和事件都移除掉)
destoryed(組件銷毀后調用)

在創建時,父子組件的生命周期是:
父組件beforeCreated -> 父組件created -> 父組件beforeMounted -> 子組件beforeCreated -> 子組件created -> 子組件beforeMounted -> 子組件mounted -> 父組件mounted。

在銷毀時,父子組件的生命周期是:
父組件beforeDestory -> 子組件beforeDestoryed -> 子組件destoryed -> 父組件destoryed

總之記住,父子組件的生命周期遵循:由外到內,再由內到外

不要在選項屬性或回調上使用箭頭函數,vue會自動綁定this的上下文環境。

模版語法

Vue.js 使用了基於 HTML 的模板語法,允許開發者聲明式地將 DOM 綁定至底層 Vue 實例的數據。所有 Vue.js 的模板都是合法的 HTML ,所以能被遵循規范的瀏覽器和 HTML 解析器解析。

在底層的實現上,Vue 將模板編譯成虛擬 DOM 渲染函數。結合響應系統,Vue 能夠智能地計算出最少需要重新渲染多少組件,並把 DOM 操作次數減到最少。

使用雙大括號(Mustache 語法)“{{}}”是最基本的文本插值方法,它會自動將我們雙向綁定的數據實時顯示出來,

<span>Message: {{ msg }}</span>

如果想顯示{{}}標簽,而不進行替換,使用v-pre即可跳過這個元素和它的子元素的編譯過程,例如 :

<span v-pre>{{這里的內容是不會被編譯的}}</span>

{{}}中,除了簡單的綁定屬性值外,還可以使用JavaScript表達式進行簡單的運算、三元運算等,例如 :

<div id='app'>
    {{ number / 10 ))
    {{ isOK ? ’確定’ : ’取消’ }}
    {{ text.split(’,’).reverse().join(’,’) }}
</div>

通過使用 v-once 指令,你也能執行一次性地插值,當數據改變時,插值處的內容不會更新。但請留心這會影響到該節點上的其它數據綁定:

<span v-once>這個將不會改變: {{ msg }}</span>

如果你熟悉虛擬 DOM 並且偏愛 JavaScript 的原始力量,你也可以不用模板,直接寫渲染 (render)函數,使用可選的 JSX 語法。

指令

指令(Directives) 是帶有 v- 前綴的特殊特性。指令特性的值預期是單個 JavaScript 表達式 (v-for是例外情況)。指令的職責是當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM。
常用的指令如下:

v-cloak

v-cloak不需要表達式,它會在 Vue 實例結束編譯時從綁定的 HTML 元素上移除 ,
經常和css的 display: none配合使用:

<div id='app' v-cloak> {{ message }}</div>
<style>
[v-cloak] {
    display: none;
}
</style>

當網速較慢 Vue.js 文件還沒加載完時,在頁面上會顯示{ { message }}的字樣,直到 Vue 創建實例、編譯模板時, DOM 才會被替換,所以這個過程屏幕是有閃動的,只要加上v-cloak就可以避免了。在一般情況下, v-cloak 是一個解決初始化慢導致頁面閃動的最佳實踐,對於簡單的項目很實用,但是在具有工程化的項目里,項目的HTML 結構只有一個空的 div元素,剩余的內容都是由路由去掛載不同組件完成的,所以不再需要 v-cloak

v-once
v-once 也是一個不需要表達式的指令,作用是定義它的元素或組件只渲染一次,包括元素或組件的所有子節點。首次渲染后,不再隨數據的變化重新渲染,將被視為靜態內容,例如:

<span v-once>{{ message }}</div>

v-once在業務中也很少使用,當你需要進一步優化性能時,可能會用到。

v-html

為了輸出真正的 HTML,需要使用 v-html 指令;

var contenthtml = `<span>哈哈大笑😄</span>`;
<span v-html="contenthtml"></span>

你的站點上動態渲染的任意 HTML 可能會非常危險,因為它很容易導致 XSS 攻擊。請只對可信內容使用 HTML 插值,絕不要對用戶提供的內容使用插值,必要時在服務端進行提前過濾轉義。

v-if

用於條件性地渲染一塊內容,該指令是惰性的,當初始值為false時dom節點不會進行渲染,是針對dom節點的移除和添加,例如 :

<div id='app'>
    <span v-if='false'>{{ message }}</span>
</div>
// 會被渲染為以下節點:
<div id='app'></div>

v-show

v-show的用法與v-if基本一致,只不過v-show是改變元素的css屬性display。當v-show 表達式的值為 false 時, 元素會隱藏,查看 DOM 結構會看到元素上加載了內聯樣式 display: none; 例如 :

<div id='app'>
    <span v-show='false'>{{ message }}</span>
</div>
// 會被渲染為以下節點
<div id='app'>
    <span style="display: none;”>哈哈大笑😄</span>
</div>
v-show不能在<template>上使用。相比之下, v-if更適合條件不經常改變的場景,因為它切換開銷相對較大,而 v-show 適用於頻繁切換條件。

v-else

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

<span v-if='show'>{{ message.a }}</span>
<span v-else>{{ message.b }}</span>

v-for

當需要將一個數組遍歷或枚舉一個對象循環顯示時,就會用到列表渲染指令 v-for。它的表達式需結合 in來使用,類似 item in items 的形式,看下面的示例 :

<ul>
    <li v-for=”book in books” :key="book.id">{{ book.name }}</li>
</ul>

當 Vue 正在更新使用 v-for 渲染的元素列表時,它默認使用“就地更新”的策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序,而是就地更新每個元素,並且確保它們在每個索引位置正確渲染,所以需要為每個元素設置唯一的key

v-bind

v-bind用於動態更新 HTML 元素上的屬性,比如 id、class等;

<div id=”app”>
    <v-bind:href=”url”〉鏈接</a>
    <img v-bind:src=”imgUrl”>
</div>

以上是 v-bind 最基本的用法,它在 Vue.js 組件中還有着極其重要的作用,可以簡寫為

v-on

v-on在事件綁定上,類似原生 JavaScript 的 onclick等寫法,也是在 HTML 上進行監昕的,例如:

<button v-on:click=”counter++”>+ 1</button>

v-on:click的表達式可以直接使用 JavaScript 語句,也可以是一個在 Vue實例中 methods選項內的函數名,例如:

<button v-on:click=”handleAdd(1)”>+ 1</button>

methods: {
    handleAdd: function(count) {
        this.counter += count;
    }
}

v-on:click調用的方法名后可以不跟括號“()” ;

 

<a href=”http://www.apple.com” @click="handleClick ('禁止打開',$event)">打開鏈接 </a>
methods: {
    handleClick: function(message, event) {
        event.preventDefault();
    }
}

v-on可以簡寫為@

  • v-model

v-model用於表單,進行雙向數據綁定。例如:

<input type=”text” id="name" v-model="fullname" />
<p>你好,{{fullname}} !</p>

過濾器

Vue.js 允許你自定義過濾器,可被用於一些常見的文本格式化。過濾器可以用在兩個地方:雙花括號插值和 v-bind 表達式。過濾器應該被添加在 JavaScript 表達式的尾部,由“管道”符號指示:

<!-- 在雙花括號中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>

你可以在一個組件的選項中定義本地的過濾器:

filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

// 或者在創建 Vue 實例之前全局定義過濾器:
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

過濾器可以串聯:

{{ message | filterA | filterB }}

過濾器是 JavaScript 函數,因此可以接收參數:

{{ message | filterA('arg1', arg2) }}

這里,filterA 被定義為接收三個參數的過濾器函數。其中message 的值作為第一個參數,普通字符串 'arg1' 作為第二個參數,表達式 arg2 的值作為第三個參數。

2. 計算屬性與響應式依賴

在一個計算屬性里可以完成各種復雜的邏輯,包括運算、函數調用等,只要最終返回 一個結果就可以。計算屬性還可以依賴多個Vue實例的數據,只要其中任一數據變化,計算屬性就會重新執行,視圖也會更新。

<span>{{fullName}}</span>
computed: {
    fullName: {
        get: function() {
            return this.firstName + ' ' + this.lastName;
        },
        set: function(newValue) {
            var names= newValue.split (' ') ;
            this.firstName = names[O);
            this.lastName = names[names.length - 1];
        }
    }
}

我們可以通過在表達式中調用方法來達到同樣的效果:

<span>{{getName()}}</span>
methods: {
    getName: function() {
        return this.firstName + ' ' + this.lastName;
    }
}

我們可以將同一函數定義為一個方法而不是一個計算屬性。兩種方式的最終結果確實是完全相同的。然而,不同的是計算屬性是基於它們的響應式依賴進行緩存的。只在相關響應式依賴發生改變時它們才會重新求值。

雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的偵聽器。這就是為什么 Vue 通過 watch選項提供了一個更通用的方法,來響應數據的變化。當需要在數據變化時執行異步或開銷較大的操作時,這個方式是最有用的。

watch: {
    message(newvalue, oldValue) {
        newvalue && this.getNewMessage();
    }
}

3. 組件

組件是可復用的 Vue 實例,通常一個應用會以一棵嵌套的組件樹的形式來組織:

組件 ( Component)是 Vue 最核心的功能,也是整個框架設計最精彩的地方,當然也是最難 掌握的。組件需要注冊后才可以使用,注冊有全局注冊和局部注冊兩種方式。全局注冊后, 任何 Vue 實例都可以使用。

全局注冊示例代碼如下 :

Vue.component(’my-component’, {
    //選項
})

在 Vue 實例中,使用 components選項可以局部注冊組件,注冊后的組件只有在該實例作用域下有效。組件中也可以使用components選項來注冊組件,使組件可以嵌套。示例代碼如下:

<div id=”app”>
    <my-component></my-component>
</div>
<script>
var Child = {
    template: '<div>局部注冊組件的內容</div>'
};
components: {
    ’my-component’: Child
}
</script>

Vue 組件的模板在某些情況下會受到HTML的限制,比如<table>內規定只允許是<tr><td><th>等這些表格元素,所以在<table>內直接使用組件是無效的。這種情況下可以使用特殊的is屬性來掛載組件,示例代碼如下 :

<div id=”app”>
    <table>
        <tbody is=”my-component”></tbody>
    </table>
</div>
<script>
var Child = {
    template: '<div>局部注冊組件的內容</div>'
};
components: {
    ’my-component’: Child
}
</script>
常見的限制元素還有<ul>、<ol>、<select>;如果使用字符串模板是不受限制的;

除了 template選項外,組件中還可以像 Vue實例那樣使用其他的選項,比如 data、 computed、 methods 等。但是在使用 data 時和實例稍有區別, data 必須是函數,然后將數據 return 出去, 例如:

Vue.component('my-component', {
    template: '<div>{{ message }}</div>',
    data: function() {
        return {
            message: 'aaa'
        }
    }
});

props傳遞數據、 events觸發事件和slot內容分發就構成了Vue組件的3個API來源,再復 雜的組件也是由這 3 部分構成的。

  • props

    組件不僅僅是要把模板的內容進行復用,更重要的是組件間要進行通信。通常父組件的模板 中包含子組件,父組件要正向地向子組件傳遞數據或參數,子組件接收到后根據參數的不同來渲染不同的內容或執行操作。這個正向傳遞數據的過程就是通過 props 來實現的。

在組件中,使用選項 props 來聲明需要從父級接收的數據, props 的值可以是兩種, 一種是字符串數組,一種是對象:

// 字符串數組
Vue.component ('my-component', {
    props: [ ’ message ’ ] ,
    template: ’<div>{{ message }}</div>’
});
// 對象形式
Vue.component ('my-component', {
    props: {
        //必須是數字類型
        propA : Number,
        //必須是字符串或數字類型
        propB : [String , Number],
        //布爾值,如果沒有定義,默認值就是 true
        propC: {
            type: Boolean,
            default: true
        },
        //數字,而且是必傳
        propD: {
            type: Number,
            required: true
        },
        //如果是數組或對象,默認值必須是一個函數來返回
        propE: {
            type: Array,
            default: function() {
                return [];
            }
        }
    } ,
    template: ’<div>{{ message }}</div>’
});
  • events

用集中式的事件中間件可以做到簡單的數據傳遞,這會讓組件之間的通信非常順利,即使是兄弟組件。因為 Vue 通過事件發射器接口執行實例,實際上你可以使用一個空的 Vue 實例,通過單獨的事件中心管理組件間的通信:

var eventHub = new Vue();

然后在組件中,可以使用 $emit$on$off 分別來分發、監聽、取消監聽事件:

eventHub.$emit('delete', id);
eventHub.$on('delete', this.delete);
eventHub.$off('delete', this.delete)
  • slot

Vue 實現了一套內容分發的 API,這套 API 的設計靈感源自 Web Components 規范草案,將

-普通插槽

// 父組件
<submit-button>save</submit-button>
// 子組件
<button type="submit">
  <slot>Submit</slot>
</button>

// 最終渲染
<button type="submit">
  Save
</button>

-具名插槽

// 父組件
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template v-slot:footer>
    <p>Heres some contact info</p>
  </template>
</base-layout>
// 子組件
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

// 最終渲染
<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Heres some contact info</p>
  </footer>
</div>

-作用域插槽

// 父組件
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

// 子組件
<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

插槽對於組件意義非凡,可以自定義拓展實現很多復雜的業務場景,且低耦合;

  • 通信方式

    -props/$emit

父子組件進行通信最常用這種方式:

// 父組件
<template>
    <child :updateTitle='updateTitle'></child>
</template>
<script>
export {
    data: {
        return {
            title: '我是父組件'
        }
    },
    methods: {
        updateTitle(value) {
            this.title = value;
        }
    }
}
</script>
// 子組件
<template>
  <header>
    <h1 @click="changeTitle">{{title}}</h1>
  </header>
</template>
<script>
export {
    props: {
        title: {
            type: String,
            default: '我是父組件'
        }
    },
    methods: {
        changeTitle() {
            this.$emit('updateTitle', '我是子組件');
        }
    }
}
</script>

-eventBus

父子、兄弟組件之間都可以使用這種方式:

var Event=new Vue();
Event.$emit(事件名,數據);
Event.$on(事件名,data => {});

$emit負責分發事件,

vuex

Vuex 實現了一個單向數據流,在全局擁有一個 State 存放數據,當組件要更改 State 中的數據時,必須通過 Mutation 進行,Mutation 同時提供了訂閱者模式供外部插件調用獲取 State 數據的更新。而當所有異步操作(常見於調用后端接口異步獲取更新數據)或批量的同步操作需要走 Action,但 Action 也是無法直接修改 State 的,還是需要通過 Mutation 來修改 State 的數據。最后,根據 State 的變化,渲染到視圖上。

一般用於比較復雜的大中型應用,一個應用只有一個store,通過插件的機制注入應用本身,下面的全部組件都可以訪問到store中的數據,便於數據的管理和追蹤變化;

$attrs/$listeners

$attrs包含了父作用域中不被 prop 所識別 (且獲取) 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這里會包含所有父作用域的綁定 (class 和 style 除外),並且可以通過 v-bind="onmountedcreatedvuex

VuexStateStateMutationMutation調State(調)ActionActionStateMutationStateStatestorestore便¨C26C¨C27Cprop()(classstyle)prop(classstyle)vbind="attrs" 傳入內部組件。通常配合 interitAttrs 選項一起使用。

$listeners包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它可以通過 v-on="

不能識別此Latex公式:
listeners" 傳入內部組件。

 

 
// 父組件
<template>
    <child :foo="foo" :boo="boo"  title="天道酬勤Lewis"></child>
</template>
// 子組件
<template>
    <p>boo: {{ boo }}</p>
    <p>child: {{ $attrs }}</p>
</template>
 
<code class="! language-!" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">Vue2.4 提供了$attrs,$listeners來傳遞數據與事件,跨級組件之間的通訊變得更簡單。
簡單來說:$attrs與$listeners 是兩個對象,$attrs 里存放的是父組件中綁定的非 Props 屬性,$listeners里存放的是父組件中綁定的非原生事件。
</code class="! language-!">
 

provide/inject

 

Vue2.2.0 新增 API,這對選項需要一起使用,以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,在上下游關系成立的時間里始終生效。一言而蔽之:祖先組件中通過 provider 來提供變量,然后在子孫組件中通過 inject來注入變量

 

provide / inject API 主要解決了跨級組件間的通信問題,不過它的使用場景,主要是子組件獲取上級組件的狀態,跨級組件間建立了一種主動提供與依賴注入的關系。

 
// 父組件
export default {
  provide: {
    name: '天道酬勤Lewis'
  }
}
// 子組件
export default {
  inject: ['name'],
  mounted () {
    console.log(this.name);  // 天道酬勤Lewis
  }
}
 
<code class="! language-!" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;">provide 和 inject 綁定並不是可響應的,這是刻意為之的。然而,如果你傳入了一個可監聽的對象,那么其對象的屬性還是可響應的。
</code class="! language-!">

4. 事件機制

Vue定義了四種添加事件監聽的方法:




  •  

on
Vue.prototype.$on = function (event, fn) {
    var this$1 = this;
    var vm = this;
    //如果傳參event是數組,遞歸調用$on
    if (Array.isArray(event)) {
      for (var i = 0, l = event.length; i < l; i++) {
        this$1.$on(event[i], fn);
      }
    } else {
      (vm._events[event] || (vm._events[event] = [])).push(fn);
      // 這里在注冊事件的時候標記bool值也就是個標志位來表明存在鈎子,而不需要通過哈希表的方法來查找是否有鈎子,這樣做可以減少不必要的開銷,優化性能。
      if (hookRE.test(event)) {
        vm._hasHookEvent = true;
      }
    }
    return vm
};
  • once</li></ul>¨G47G<ul><li>emit

  Vue.prototype.$emit = function (event) {
    var vm = this;
    {
      var lowerCaseEvent = event.toLowerCase();
      if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
        tip(
          "Event \"" + lowerCaseEvent + "\" is emitted in component " +
          (formatComponentName(vm)) + " but the handler is registered for \"" + event + "\". " +
          "Note that HTML attributes are case-insensitive and you cannot use " +
          "v-on to listen to camelCase events when using in-DOM templates. " +
          "You should probably use \"" + (hyphenate(event)) + "\" instead of \"" + event + "\"."
        );
      }
    }
    var cbs = vm._events[event];
    if (cbs) {
      //將類數組的對象轉換成數組
      cbs = cbs.length > 1 ? toArray(cbs) : cbs;
      var args = toArray(arguments, 1);
      for (var i = 0, l = cbs.length; i < l; i++) {
        try {
          //觸發當前實例上的事件,附加參數都會傳給監聽器回調。
          cbs[i].apply(vm, args);
        } catch (e) {
          handleError(e, vm, ("event handler for \"" + event + "\""));
        }
      }
    }
    return vm
};
  • $off

  Vue.prototype.$off = function (event, fn) {
    var this$1 = this;
    var vm = this;
    // 如果沒有參數,關閉全部事件監聽器
    if (!arguments.length) {
      vm._events = Object.create(null);
      return vm
    }
    // 關閉數組中的事件監聽器
    if (Array.isArray(event)) {
      for (var i = 0, l = event.length; i < l; i++) {
        this$1.$off(event[i], fn);
      }
      return vm
    }
    // 具體的某個事件
    var cbs = vm._events[event];
    if (!cbs) {
      return vm
    }
    //  fn回調函數不存在,將事件監聽器變為null,返回vm
    if (!fn) {
      vm._events[event] = null;
      return vm
    }
    // 回調函數存在
    if (fn) {
      // specific handler
      var cb;
      var i$1 = cbs.length;
      while (i$1--) {
        cb = cbs[i$1];
        if (cb === fn || cb.fn === fn) {
          // 移除 fn 這個事件監聽器
          cbs.splice(i$1, 1);
          break
        }
      }
    }
    return vm
};
  • 事件修飾符

<!-- 阻止單擊事件繼續傳播 -->
<v-on:click.stop="doThis"></a>

<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修飾符可以串聯 -->
<v-on:click.stop.prevent="doThat"></a>

<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件監聽器時使用事件捕獲模式 -->
<!-- 即元素自身觸發的事件先在此處處理,然后才交由內部元素進行處理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只當在 event.target 是當前元素自身時觸發處理函數 -->
<!-- 即事件不是從內部元素觸發的 -->
<div v-on:click.self="doThat">...</div>

5. 插件機制

Vue提供了插件機制,可以在全局添加一些功能。它們可以簡單到幾個方法、屬性,也可以 很復雜,比如一整套組件庫。
注冊插件需要一個公開的方法 install,它的第一個參數是 Vue 構造器,第二個參數是一個可選的選項對象,示例代碼如下:

MyPlugin.install = function (Vue, options) {
    //全局注冊組件(指令等功能資源類似〉
    Vue.component ('component-name',{
        //組件內容
    }),
    //添加實例方法
    Vue.prototype.$Notice = function() {
        //邏輯 ...
    },
    //添加全局方法或屬性
    Vue.globalMethod = function() {
        //邏輯 ...
    },
    //添加全局混合
    Vue.mixin ({
        mounted: function() {
            //邏輯 ...
        }
    }),
    //添加全局過濾器
    Vue.directive('my-directive', {
        bind (el, binding, vnode, oldVnode) {
            // 邏輯...
        }
    }
  })
};
// 通過 Vue.use()來使用插件:
Vue.use(MyPlugin);
// 或 
Vue.use(MyPlugin, {
    // 參數選項
});

絕大多數情況下,開發插件主要是通過NPM發布后給別人使用的,在自己的項目中可以直接在入口調用以上方法 ,無須多一步注冊和使用的步驟 。

6. 前端路由Vue-router

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

包含的功能有:

  • 嵌套的路由/視圖表

  • 模塊化的、基於組件的路由配置

  • 路由參數、查詢、通配符

  • 基於 Vue.js 過渡系統的視圖過渡效果

  • 細粒度的導航控制

  • 帶有自動激活的 CSS class 的鏈接

  • HTML5 歷史模式或 hash 模式,在 IE9 中自動降級

  • 自定義的滾動條行為

// 0. 如果使用模塊化機制編程,導入Vue和VueRouter,要調用 Vue.use(VueRouter)

// 1. 定義 (路由) 組件。
// 可以從其他文件 import 進來
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定義路由
// 每個路由應該映射一個組件。 其中"component" 可以是
// 通過 Vue.extend() 創建的組件構造器,
// 或者,只是一個組件配置對象。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. 創建 router 實例,然后傳 `routes` 配置
// 你還可以傳別的配置參數, 不過先這么簡單着吧。
const router = new VueRouter({
  routes // (縮寫) 相當於 routes: routes
})

// 4. 創建和掛載根實例。
// 記得要通過 router 配置參數注入路由,
// 從而讓整個應用都有路由功能
const app = new Vue({
  router
}).$mount('#app')

vue-router 默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新加載,這種模式利用監聽onhashchange事件,來實現頁面的跳轉;如果不想要很丑的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

當你使用 history 模式時,URL 就像正常的 url,例如  http://yoursite.com/user/id,也好看!

不過這種模式要玩好,還需要后台配置支持。因為我們的應用是個單頁客戶端應用,如果后台沒有正確的配置,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404,這就不好看了。

所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

7. 狀態管理Vuex

Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

以下是一個完整的vuex理念的簡單示意:

  • state,驅動應用的數據源;

  • view,以聲明方式將 state 映射到視圖;

  • actions,響應在 view 上的用戶輸入導致的狀態變化;

  • mutations, 更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation;

一般為了邏輯清晰,會按頁面對store進行module的區分,一個完整的module-store如下:

const moduleA = {
    state: { ... },
    mutations: { . . . },
    actions: { ... ),
    getters: { ... )
};
使用Vuex進行數據管理是有一定難度的,如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗余的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 global event bus就足夠您所需了。但是,如果您需要構建是一個中大型單頁應用,您很可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成為自然而然的選擇。

8. 服務端渲染Nuxt.js

Vue.js 是構建客戶端應用程序的框架。默認情況下,可以在瀏覽器中輸出 Vue 組件,進行生成 DOM 和操作 DOM。然而,也可以將同一個組件渲染為服務器端的 HTML 字符串,將它們直接發送到瀏覽器,最后將這些靜態標記"激活"為客戶端上完全可交互的應用程序。

與傳統 SPA (單頁應用程序 (Single-Page Application)) 相比,服務器端渲染 (SSR) 的優勢主要在於:

  1. 更好的 SEO,由於搜索引擎爬蟲抓取工具可以直接查看完全渲染的頁面。

  2. 更快的內容到達時間 (time-to-content),特別是對於緩慢的網絡情況或運行緩慢的設備。

Nuxt.js十分簡單易用,天然為Vue而生(Next.jsReact而生);Nuxt.js 是一個基於 Vue.js 的通用應用框架,預設了利用Vue.js開發服務端渲染的應用所需要的各種配置。一個簡單的項目只需將 nuxt 添加為依賴組件即可,更多細節請戳這里;

技術文可以關注我的blog(lewiscutey.github.io/blog)查看詳情😄

 

 

 
 

微信掃一掃
關注該公眾號


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM