文章目錄
- 1. 傳統的 MVP 開發模式與 MVVM 開發模式對比
- 2. 一些指令以及使用技巧
- 2.1. Vue 中計算屬性的使用技巧
- 2.2. v-bind 綁定 class 與 內聯樣式
- 2.3. v-if 與 v-else 標籤必須要連在一起使用,不然會拋出錯誤。
- 2.4. key 值
- 2.5. v-for 循環
- 2.6. Vue 中操作數組
- 2.7. template 模板佔位符
- 2.8. Vue 中遍歷對象進行渲染以及對根級別響應式對象添加屬性
- 2.9. 對於數組的 set 方法
- 2.10 v-text 與 v-html
- 3. 組件的一些知識
- 3.1. is屬性
- 3.2 . 子組件中 data
- 3.3. 組件中操作 DOM
- 3.4. 組件之間的通訊
- 3.5 組件綁定原生事件
- 3.6. 非父子組件傳值( Bus 總線/發佈訂閱模式/觀察者模式)
- 3.7. 插槽相關知識
- 3.8. 動態組件
- 3.9. vue 中的動畫
- 3.11. 非 Props 特性
- 3.12. 組件中替換/合併已有的特性
- 3.13. 組件的禁用特性繼承
- 4. vue-cli 以及 vue-router
- 5. 項目開發中的一些知識
- 5.1. 開發流程
- 5.2. vue 第三方輪播圖插件 vue-awesome-swiper
- 5.3. 瀏覽器的小技巧模擬網絡
- 5.4. css 代碼技巧
- 5.5. vue-cli 項目中的靜態資源訪問以及代碼提交配置
- 5.6. 項目接口的轉接
- 5.7. Math 對象的一些方法
- 5.8. CSS 的 rem 以及 vm
- 5.9. Better-scroll 插件
- 5.10. 防抖節流的例子
- 5.11. touch 事件與 click 事件的衝突
- 5.12. 解決手機不支持 es6 新特性
- 6. vuex 知識
- 6.1. vuex 的使用
- 6.2. 頁面之間跳轉
- 6.3. 訪問 vuex 數據技巧
- 6.4. vuex 中的 getters 屬性
- 6.5. 使用 keep-alive 優化性能
- 6.6. router-link 一些知識
- 6.7. \ 一些知識點
- 6.8. vuex 中的插件
- 6.8. 嚴格模式
- 7. vue-router 知識點
- 8. 項目上線準備
- 9. vue 學習路線
- 10. 其他
1. 傳統的 MVP 開發模式與 MVVM 開發模式對比
- 對於傳統的
mvp
開發模式,m
也就是model
一般是通過發送ajax
請求獲取到的數據,v
也就是視圖,p
就是Presenter
相當於控制器,
Presenter
作爲View和Model
之間的“中間人”,除了基本的業務邏輯外,還有大量代碼需要對從View
到Model
和從Model
到View
的數據進行“手動同步”,這樣Presenter
顯得很重,維護起來會比較困難。而且由於沒有數據綁定,如果Presenter
對視圖渲染的需求增多,它不得不過多關注特定的視圖,一旦視圖需求發生改變,Presenter
也需要改動,我們大部分的關注點是在視圖與數據,以及通過控制器進行操作。 - 對於
vue
的開發模式mvvm
,他把View
和Model
的同步邏輯自動化了,與MVP
不同,沒有了View
爲Presenter
提供的接口,之前由Presenter
負責的View
和Model
之間的數據同步交給了ViewModel
中的數據綁定進行處理,當Model
發生變化,ViewModel
就會自動更新;ViewModel
變化,Model
也會更新。我們的關注點主要是在model
與view
之間,而model
發生變化,view
進行同步更新,這些都交給了viewmodel
,mvp
的模式我們大部分的關注點是在操作了dom
,提高了開發效率。
2. 一些指令以及使用技巧
2.1. Vue 中計算屬性的使用技巧
get、set
;如果是獲取數值,通過get
獲取到值,也可以通過set
函數設置值,注意如果你爲一個計算屬性使用了箭頭函數,則 this 不會指向這個組件的實例,不過可以通過其實例作爲函數的第一個參數來訪問:
computed: {
aDouble: vm => vm.a * 2
}
get、set
用法:
var vm = new Vue({
data: { a: 1 },
computed: {
// 僅讀取
aDouble: function () {
return this.a * 2
},
// 讀取和設置
aPlus: {
get: function () {
return this.a + 1
},
set: function (v) {
this.a = v - 1
}
}
}
})
vm.aPlus // => 2
vm.aPlus = 3
vm.a // => 2
vm.aDouble // => 4
計算屬性的結果會被緩存,除非依賴的變量變化纔會重新計算。注意,如果某個依賴 (比如非響應式屬性) 在該實例範疇之外,則計算屬性是不會被更新的。 我們一般如果處理數據顯示,如果聲明函數、計算屬性、偵聽器這三者都可以實現的話,一般建議使用計算數據,因爲存在緩存機制。
計算屬性設置值的時候直接使用=
,如上面的aPlus
數值,而不是與函數類似進行賦值。
aPlus = 10
2.2. v-bind 綁定 class 與 內聯樣式
2.2.1. v-bind 綁定 class
在v-bind
中,綁定class
,使用:class="{active:isActive}"
,前面的active如果沒有在data中定義是不會報錯的,他是一個對象表達式,意思就是active
這個類的顯示與否都在於isActive
這個變量,該變量爲布爾類型,爲true
爲顯示,爲false
是不顯示。
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
data
:
data: {
isActive: true,
hasError: false
}
渲染的結果:如果hasError
的值爲true
,class
列表將變爲"static active text-danger"
<div class="static active"></div>
而如果使用:class="[chextType, active ]"
,這樣chextType
這個必須在data
中定義。div
顯示的類名就是顯示chextType、active
變量中存儲的類名。另外他也可以與普通的 class
共存
<div v-bind:class="[activeClass, errorClass]"></div>
data
:
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
渲染的結果:如果hasError
的值爲true
,class
列表將變爲"static active text-danger"
<div class="active text-danger"></div>
這樣寫將始終添加errorClass
,但是隻有在isActive
是true
時才添加 activeClass
。不過,當有多個條件 class
時這樣寫有些繁瑣。所以在數組語法中也可以使用對象語法:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
當在一個自定義組件上使用 class
屬性時,這些類將被添加到該組件的根元素上面。這個元素上已經存在的類不會被覆蓋。
例如,如果你聲明瞭這個組件:
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
然後在使用它的時候添加一些 class
:
<my-component class="baz boo"></my-component>
HTML
將被渲染爲:
<p class="foo bar baz boo">Hi</p>
對於帶數據綁定的class
跟前面是一樣的。
2.2.2. 綁定內聯樣式
對象語法:
v-bind:style
的對象語法十分直觀——看着非常像CSS
,但其實是一個 JavaScript
對象。CSS
屬性名可以用駝峯式 或短橫線分隔 (記得用引號括起來) 來命名:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
直接綁定到一個樣式對象通常更好,這會讓模板更清晰:同樣的,對象語法常常結合返回對象的計算屬性使用。
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
數組語法:
v-bind:style
的數組語法可以將多個樣式對象應用到同一個元素上:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
自動添加前綴:
當 v-bind:style
使用需要添加瀏覽器引擎前綴的 CSS
屬性時,如transform
,Vue.js
會自動偵測並添加相應的前綴。
2.3. v-if 與 v-else 標籤必須要連在一起使用,不然會拋出錯誤。
2.4. key 值
Vue
在重新渲染頁面的時候,會嘗試複用頁面裏面的dom
元素,如果頁面有兩個相同的標籤可以添加一個key
,這樣,vue
會區分,不會複用。
2.5. v-for 循環
一般在v-for
循環的時候,一般建議加一個:key
值,綁定一個唯一的標識,不建議直接綁定循環的index
,會消耗性能,建議綁定後臺傳入的數據的主鍵。
2.6. Vue 中操作數組
Vue
中,不能直接通過數組下標的方法,進行添加數據,這樣頁面不會渲染的,需要通過數據的操作函數進行增刪改查:push、pop、shift、unshift、splice、sort、reverse
2.7. template 模板佔位符
template
模板佔位符,比如我們使用v-for要循環兩個標籤,可以在兩個標籤外層加一個div
,但是這個div
會在頁面顯示出來,我們可以把外層的div
換成template
,不會顯示在頁面。
2.8. Vue 中遍歷對象進行渲染以及對根級別響應式對象添加屬性
對象的循環:key
是,鍵;index
是位置信息,item
是值;
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
渲染結果:
<div id="v-for-object-value-name-index" class="demo"><div>
0. title: How to do lists in Vue
</div><div>
1. author: Jane Doe
</div><div>
2. publishedAt: 2016-04-10
</div></div>
給對象直接修改屬性是可以再次進行渲染。
給對象直接添加值,是不變的,可以直接改變引用,換成一個全新的對象,也可以使用set
方法,Vue.set(vm.userInfo,"address","wuhan")
這樣,userInfo
對象會增加數據,頁面也會變動,重新渲染。也可以使用實例的$set方法
,vm.$set(vm.userInfo,"address","wuhan")
對於已經創建的實例,Vue 不允許動態添加根級別的響應式屬性。但是,可以使用 Vue.set(object, propertyName, value)
方法向嵌套對象添加響應式屬性。
2.9. 對於數組的 set 方法
對於數組的set
方法。Vue.set(vm.userInfo,4,5)
,將第四個位置的數據改成5,也可以用實例vm.$set(vm.userInfo,4,5)
,所以改變數組的值有兩種方法,第一個是使用js的數組操作函數,另一個是使用vue
的set
方法、
2.10 v-text 與 v-html
這兩個指令旨在顯示數值,跟我們直接在html
中使用插值表達式類似:
<div>{{message}}</div>
v-text
顯示的結果與插值表達式一致的,而v-html
會展示爲html
,如果字符串是一個html
的字符串,他會進行渲染顯示。
3. 組件的一些知識
3.1. is屬性
有些 HTML
元素,諸如 <ul>
、<ol>
、<table>
和 <select>
,對於哪些元素可以出現在其內部是有嚴格限制的。而有些元素,諸如 <li>
、<tr>
和 <option>
,只能出現在其它某些特定的元素內部。比如tbody
裏只能顯示tr
,我們希望在tr裏放其他的內容,可以藉助is
屬性:
<table>
<blog-post-row></blog-post-row>
</table>
這個自定義組件<blog-post-row>
會被作爲無效的內容提升到外部,並導致最終渲染結果出錯。幸好這個特殊的 is 特性給了我們一個變通的辦法:
<table>
<tr is="blog-post-row"></tr>
</table>
這句代碼就是說,我們在tbody
是顯示tr
,其實是is
裏面的組件;遇到組件上的小bug
,可以使用is
進行解決;比如ol、select
等等。
3.2 . 子組件中 data
子組件中data
爲函數;是爲了保證每一個組件中的數據互不干擾;
3.3. 組件中操作 DOM
ref
:引用 ,被用來給元素或子組件註冊引用信息。引用信息將會註冊在父組件的 $refs
對象上。如果在普通的DOM
元素上使用,引用指向的就是 DOM
元素;如果用在子組件上,引用就指向組件實例:
<!-- `vm.$refs.p` will be the DOM node -->
<p ref="p">hello</p>
<!-- `vm.$refs.child` will be the child component instance -->
<child-component ref="child"></child-component>
獲取dom
節點,通過this.$refs.ref
的值這樣獲取dom
節點;比如上面的結構,如果需要獲取this.$refs.child
就會獲取到對應的dom
信息。
當 v-for 用於元素或組件的時候,引用信息將是包含 DOM 節點或組件實例的數組。
關於 ref 註冊時間的重要說明:因爲 ref 本身是作爲渲染結果被創建的,在初始渲染的時候你不能訪問它們 - 它們還不存在!$refs 也不是響應式的,因此你不應該試圖用它在模板中做數據綁定。
3.4. 組件之間的通訊
3.4.1 子組件向父組件派發事件
使用this.$emit('change')
;在父組件觸發change事件。@change="handleChange";
父組件的change
事件執行handleChange
方法。
3.4.2 父組件向子組件傳遞
父組件向子組件傳遞是通過屬性,用v-bind
進行綁定,子組件儘量不要修改父組件傳進來的參數,可以使用data
複製一份傳入的值;
對於組件參數的校驗,直接在props
,接收的時候,爲一個對象,type
爲類型,default
爲默認值,required
爲設置參數是否必須,validator(value){return (value.length>5)}
傳入的值必須大於五;
Vue.component('my-component', {
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 帶有默認值的數字
propD: {
type: Number,
default: 100
},
// 帶有默認值的對象
propE: {
type: Object,
// 對象或數組默認值必須從一個工廠函數獲取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函數
propF: {
validator: function (value) {
// 這個值必須匹配下列字符串中的一個
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
還是需要注意的是v-bind綁定的屬性後面是一個對象,直接跟class
一樣綁定屬性,爲字符串;props
傳遞的屬性,在dom
渲染出來的HTML
上不會顯示出來。
3.5 組件綁定原生事件
給父組件綁定事件,其實是一個自定義事件,想要給組件綁定事件,需要在template
裏面進行綁定。子組件想要觸發自定義事件,需要使用this.$emit('chandleClick');
如果想在父組件添加事件,需要添加native
事件修飾符:@click.native="handleClick";
這裏在子組件向父組件傳值定義事件名的時候需要注意,不同於組件和
prop
,事件名不存在任何自動化的大小寫轉換。而是觸發的事件名需要完全匹配監聽這個事件所用的名稱。所以如果我們定義了一個this.$emit('myEvent')
,然後在父組件監聽的時候:<my-component v-on:my-event="doSomething"></my-component>
使用短橫行的方式去監聽,是監聽不到的,因爲不同於組件和prop
,事件名不會被用作一個JavaScript
變量名或屬性名,所以就沒有理由使用camelCase
或PascalCase
了。並且v-on
事件監聽器在DOM
模板中會被自動轉換爲全小寫 (因爲HTML
是大小寫不敏感的),所以v-on:myEvent
將會變成v-on:myevent
——導致myEvent
不可能被監聽到。
所以推薦我們一般使用短橫線的方式去命名。
3.6. 非父子組件傳值( Bus 總線/發佈訂閱模式/觀察者模式)
Vue.prototype.bus = new Vue();
//子組件觸發事件
this.bus.$emit('change',this.value)//來觸發事件;然後組件進行監聽:
//在父組件的mounted中去監聽子組件觸發的事件
mounted(){
this.bus.$on('change',function(msg)
{
//...
}
);
3.7. 插槽相關知識
在slot
插槽中,如果在父組件中不進行插入dom
,在子組件的<slot>
默認內容</slot>
,裏面的字會顯示出來,自定義的內容放在<slot>中間
,如果父組件有數據,則不會顯示;具名插槽也可以有默認內容。
具名插槽:
有時我們需要多個插槽。例如對於一個帶有如下模板的 組件:
<div class="container">
<header>
<!-- 我們希望把頁頭放這裏 -->
</header>
<main>
<!-- 我們希望把主要內容放這裏 -->
</main>
<footer>
<!-- 我們希望把頁腳放這裏 -->
</footer>
</div>
對於這樣的情況,<slot>
元素有一個特殊的特性:name
。這個特性可以用來定義額外的插槽:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
一個不帶name
的 <slot>
出口會帶有隱含的名字“default”
。
在向具名插槽提供內容的時候,我們可以在一個 <template>
元素上使用v-slot
指令,並以v-slot
的參數的形式提供其名稱:
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
現在 <template>
元素中的所有內容都將會被傳入相應的插槽。任何沒有被包裹在帶有v-slot
的<template>
中的內容都會被視爲默認插槽的內容。
然而,如果你希望更明確一些,仍然可以在一個 <template>
中包裹默認插槽的內容:
<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>Here's some contact info</p>
</template>
</base-layout>
最終上面的代碼渲染的結果爲:
<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>Here's some contact info</p>
</footer>
</div>
注意 v-slot 只能添加在一個
<template>
上
作用域插槽:在父組件向子組件傳入內容時候,需要使用template
標籤進行包裹,這裏的template
是必須的
<child>
<template slot-scope="props">
<h1>{{props.item}}</h1>
</template>
</child>
在子組件中:
<div>
<ul>
<slot
v-for="item of list"
:item=item
>
</slot>
</ul>
</div>
應用場景:子組件進行循環或者某一dom渲染的樣式需要外部傳入,進行不同的顯示;作用域插槽也就相當於就是插槽之間的數據通訊。
3.8. 動態組件
動態組件:component
標籤的is
屬性來自動加載組件:<component :is="com-a"></component>,
顯示com-a
組件;不像v-if
,它是將組件進行緩存在內存裏面的。
3.9. vue 中的動畫
vue
中的動畫,需要使用transition
標籤進行包裹需要動畫顯示的組件,他會給裏面包裹的元素添加多個類名fade-enter、fade-enter-active、fade-enter-to
等, 前綴爲fade
是因爲我們添加的name
爲fade,vue
默認爲v-enter、v-enter-active
等等。div
標籤外只要使用transition
包裹,div
不管使用v-show
還是v-if
過渡動畫都是可以顯示的。如果我們需要自定義類名,直接在transform
標籤上添加 enter-active-class="active" leave-active-class="leave"
對應的active
以及leave
是自定義的類名;
vue
中使用animate.css
在transition
標籤上直接使用:enter-active-class="animated swing" leave-active-class="animated shake"
;
爲了讓div
能在初次進去頁面的時候有動畫,添加一個自定義屬性appear-active-class
,還需要加一個appear
,意思就是讓組件第一次顯示的時候也有一個動畫效果,就是appear-active-class
;可以添加屬性type=""
來指定動畫播放時長;
3.11. 非 Props 特性
一個非prop
特性是指傳向一個組件,但是該組件並沒有相應 prop
定義的特性。
因爲顯式定義的 prop
適用於向一個子組件傳入信息,然而組件庫的作者並不總能預見組件會被用於怎樣的場景。這也是爲什麼組件可以接受任意的特性,而這些特性會被添加到這個組件的根元素上。
例如,想象一下你通過一個 Bootstrap
插件使用了一個第三方的 <bootstrap-date-input>
組件,這個插件需要在其 <input>
上用到一個 data-date-picker
特性。我們可以將這個特性添加到你的組件實例上:
然後這個data-date-picker="activated"
特性就會自動添加到<bootstrap-date-input>
的根元素上。
3.12. 組件中替換/合併已有的特性
如果定義了一個組件 的模板是這樣的:
<input type="date" class="form-control">
爲了給我們的日期選擇器插件定製一個主題,我們可能需要像這樣添加一個特別的類名:
<bootstrap-date-input
data-date-picker="activated"
class="date-picker-theme-dark"
></bootstrap-date-input>
在這種情況下,我們定義了兩個不同的class
的值:
form-control
,這是在組件的模板內設置好的date-picker-theme-dark
,這是從組件的父級傳入的
對於絕大多數特性來說,從外部提供給組件的值會替換掉組件內部設置好的值。所以如果傳入 type="text"
就會替換掉 type="date"
並把它破壞!慶幸的是,class
和style
特性會稍微智能一些,即兩邊的值會被合併起來,從而得到最終的值:form-control date-picker-theme-dark
。
3.13. 組件的禁用特性繼承
如果你不希望組件的根元素繼承特性,也就是說你不希望你的組件的根元素取綁定你沒有接受的屬性值,你可以在組件的選項中設置 inheritAttrs: false。例如:
Vue.component('my-component', {
inheritAttrs: false,
// ...
})
這尤其適合配合實例的 $attrs
屬性使用,該屬性包含了傳遞給一個組件的特性名和特性值,例如:
{
required: true,
placeholder: 'Enter your username'
}
有了 inheritAttrs: false
和$attrs
,你就可以手動決定這些特性會被賦予哪個元素。在撰寫基礎組件的時候是常會用到的:
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})
注意
inheritAttrs: false
選項不會影響style
和class
的綁定。
這個模式允許你在使用基礎組件的時候更像是使用原始的 HTML
元素,而不會擔心哪個元素是真正的根元素:
<base-input
v-model="username"
required
placeholder="Enter your username"
></base-input>
可以看到我們的組件並沒有接收required
以及placeholder
屬性,因此,$attrs
的值就是:
{
required: true,
placeholder: 'Enter your username'
}
然後我們在組件中直接將這些屬性進行綁定了:v-bind="$attrs"
,也就是說$attrs
存儲非prop
特性,inheritAttrs
控制vue
對非prop
特性默認行爲,在標籤內添加$attrs
可以渲染上未註冊的屬性inheritAttrs:false
是允許組件綁定的未註冊屬性渲染到組件根節點上的。$attrs
是一個對象。
4. vue-cli 以及 vue-router
4.1. Javascript 中 Promise 對象與 callbacks 的區別
Javascript
中Promise
對象與callbacks
的區別進行比較,顯著的優點就是,promise
對象減少了嵌套,有效的防止了進入回調地獄;並且可以一次觸發多個promise
對象:
const eatMeal=Promise.all([firstPromise,burgerPromise,drinkPromise])
.then([fries,burger,drinks]=>{
console.log(`Chomp. Awesome ${burger}`);
console.log(`Chomp. Awesome ${fries}`);
console.log(`Chomp. Awesome ${drinks}`);
});
reject
與reslove
使用,在創建promise
對象的時候進行判斷,如果符合條件,就執行resolve
,不符合就執行reject
;
然後就是.then
,不管是成功還是失敗,都會執行,也就是執行reject
的時候會執行.catch
;.catch
是執行失敗的時候會調用。
4.2. vue-cli 知識
.vue
文件是代表vue
的一個組件,在js
文件中我們創建一個組件,是通過Vue.component('com-a',{})
這樣,在vue
工程化中,我們使用.vue
的文件進行創建組件。
對於vue-cli
腳手架的理解,首先我們在根目錄的main.js
文件中,可以看到:引用了route
r以及app
文件。
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
// 局部組件
components: { App },
// 下面這句話意思是將app組件渲染在頁面中,可以不在這裏寫,直接在index裏面進行書寫app標籤。
template: '<App/>'
})
// 路由 <route-view>顯示的是當前路由地址所對應的內容
在App.vue
文件中,我們可以看到:<route-view>
顯示的是當前路由地址所對應的內容 ,
<template>
<div id="app">
[外鏈圖片轉存失敗(img-cbxcO81D-1562120294364)(https://mp.csdn.net/mdeditor/assets/logo.png)]
<!-- <route-view>顯示的是當前路由地址所對應的內容 -->
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
打開Router
夾子中的index.js
文件:它配置了當路由顯示爲home
,也就是http://localhost:8080/#/home
這樣的時候,顯示組件HelloWorld
,這樣控制到不同的路由顯示不同的內容。
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/home',
name: 'HelloWorld',
component: HelloWorld
}
]
})
下面的代碼註釋:
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home'
import List from '@/pages/list/List'
Vue.use(Router)
export default new Router({
routes: [
// 當用戶訪問根目錄的時候,<router-view>顯示home組件
{
path: '/',
// 路由名字
name: 'home',
component: Home
}, {
// 當用戶訪問根目錄的時候,<router-view>顯示home組件
path: '/list',
name: 'List',
component: List
}
]
})
有關.vue
中的頁面跳轉,以前我們使用a
標籤進行跳轉的,在.vue
中,我們使用<router-link>
,進行跳轉,如下面代碼:
<template>
<!-- 這裏需要注意的是template只能包裹一個內容,如果有多個,需要在外層再加一個div -->
<div>
<div>home</div>
<!-- 頁面跳轉 to裏面是跳轉到根路徑下的list頁面,就是路由裏面配置-->
<router-link to="/list">列表</router-link>
</div>
</template>
<script>
export default {
// 組件的名字
name: 'Home'
}
</script>
<style>
div {
font-size: 19px;
}
</style>
當然我們可以使用router
的函數式導航的方式進行跳轉頁面:可以看到跳轉到了backCar
頁面,傳入的參數爲id: carInfo.CARID
,在另一個組件接收傳入的參數this.$router.query.id
, 對於頁面傳值的方式還有很多。
this.$router.push({ path: '/backCar', query: {ID: carInfo.CARID} });
還有一個需要注意的是:<template>標籤只能向外暴露一個根標籤,如果有多個,需要再到外層加一個div
;
單頁應用:通過js進行控制頁面的顯示。
4.3. 項目中一些技巧
4.3.1. import 引入 css
通過import可以直接引用css,如下面代碼,可以直接寫在main.js
中:
import './assets/style/reset.css'
4.3.2. 移動端 Click 事件延遲執行
防止移動端中出現點擊click
事件,延遲300毫秒執行的插件,在工程中輸入下面命令進行安裝:
cnpm install fastclick --save
然後在main.js
中進行設置:
// 使用attach方法,綁定到body中。
fastClick.attach(document.body)
4.3.3. vue-cl項目中配置路徑別名
在vue-cli
項目中配置路徑引用的標記,我們經常在項目中看到@符號,代表就是src
路徑,~@
代表的是src
路徑下的兩層路徑,有時候我們的層級特別多,不能使用@符號,我們可以進行配置我們的簡寫路徑。打開配置文件,修改如下:
styles
就是代表我們的src/assets/style
這個路徑。
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'styles': resolve('src/assets/style'),
}
},
所以我們在引用該目錄下的文件的直接就直接這樣寫:
import 'styles/border.css'
import 'styles/iconfont.css'
4.3.4. vue-cl項目中使用 stylus
引入stylus
,他類似sass
或者less
這種,可以直接在css中進行定義變量;幫助我們工程化代碼;輸入下面的命令進行安裝:
npm install stylus --save
npm install stylus-loader --save
然後我們可以在我們的項目中使用,如下面的`<style>`標籤內,需要添加一個`lang="stylus"`屬性,這樣就直接可以使用`stylus`進行寫css代碼,
<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.header
display: flex
line-height: .86rem
background: $bgColor
color: #fff
.header-left
width: .64rem
float: left
.back-icon
text-align: center
font-size: .4rem
</style>
這裏還有需要注意的是,我們可以使用stylus
,新建一個varibles.styl
文件,來進行定義變量,比如我們主題的顏色,在很多css文件中都要使用,如果後期需要更換主題顏色,就很麻煩;這時候,我們可以通過新建一個styl
後綴的文件,在裏面進行定義我們的變量,這樣後期維護就比較方便;varibles.styl
文件內如下:
$bgColor = #00bcd4
$darkTextColor = #333
$headerHeight = .86rem
```
然後我們引入這個文件,直接可以使用在裏面定義的變量,代碼如下:
```css
@import '~styles/varibles.styl'
.header
display: flex
line-height: .86rem
background: $bgColor
4.3.5. 移動端像素問題
首先需要明白rem
與px
像素單位之間的轉化;1rem = html font-size = 50px
;經常爲了方便處理轉換rem
;我們會將html
的font-size
設置爲50px
,這樣我們直接在頁面中寫rem
的時候就方便計算了,直接是像素(px
)/100這樣計算就可以了。比如我們要設置width=86px
,直接寫成width=.86rem
就可以了。
需要注意的一個問題是,如果修改了
webpack
裏面的配置項,需要重新啓動服務纔會有效。
5. 項目開發中的一些知識
5.1. 開發流程
開發項目中的流程:大多數公司在進行開發一個項目的時候,都會首先建立一個主分支(master
),然後將其他功能的編寫,都放在其他分支上,最後將其他分支合併到主分支這樣的開發流程。
在碼雲上新建分支,然後在項目文件夾下輸入命名:
git push
他會提示提交到哪一個分支上,然後輸入命令:git checkout index-swiprer
其中index-swiprer
是我們新建的一個分支。
將分支內容提交到主分支,還是通過git add . ; git commit -m '" ; git push
提交之後,然後輸入命令git checkout master
切換到主分支,然後進行合併,輸入命令:git merge origin/index-swiper
其中index-swiprer
是我們要合併的分支;最後再git push
5.2. vue 第三方輪播圖插件 vue-awesome-swiper
vue
第三方輪播圖插件vue-awesome-swiper
,安裝如下:
輸入命令npm install [email protected] --save
然後根據官網的操作步驟,就可以使用了。官網地址:https://github.com/surmon-china/vue-awesome-swiper
5.3. 瀏覽器的小技巧模擬網絡
瀏覽器的小技巧:可以點擊調試面試的network
右側有一個offline
右側的向下的箭頭,可以模擬不同的網速,比如可以選擇slow 3G
模擬3G
網絡。
5.4. css 代碼技巧
5.4.1. 寬高保持一定的百分比
高度根據寬度撐開百分比,設置寬高始終保持在31.25%
如下面的代碼:
overflow: hidden
width: 100%
height: 0
/*高度會根據寬度自動撐開31.25% */
padding-bottom: 31.25%
或者直接寫一個height:31.25vm
,把overflow
以及padding-bottom
刪除 ,也是可以的。
5.4.2. 修改第三方插件樣式
查找wrapper
下面的swiper-pagination-bullet-active
類都加一個背景色。應用場景是,有時候引用了第三方的插件,需要改插件的顏色,直接通過加! important
是不行的,可以通過下面的方法進行修改。
.wrapper >>> .swiper-pagination-bullet-active
background: #fff
另一個技巧:當頁面顯示的時候有可能顯示的字體會很多,我們可以設置多餘的顯示爲...
,可以通過css類控制:
overflow: hidden
white-space: nowrap
text-overflow: ellipsis
我們可以藉助stylus
進行封裝css函數,如下面代碼:
ellipsis()
overflow: hidden
white-space: nowrap
text-overflow: ellipsis
然後在css中進行引入:mixins.styl
文件就是我們寫的代碼,直接加一個ellipsis()
就可以了。
@import '~styles/mixins.styl'
.icon-desc
position: absolute
left: 0
right: 0
bottom: 0
height: .44rem
line-height: .44rem
text-align: center
color: $darkTextColor
ellipsis()
5.4.3. div 元素垂直居中
CSS
技巧:讓給div
中的元素垂直居中:
display: flex
flex-direction: column
justify-content: center
然後裏面的可以設置css
進行水平居中:
line-height: .44rem
text-align: center
5.4.4. 移動端獲取元素離頂部元素真實高度
對於頁面中獲取離上面元素高度:
// 元素離頂部元素的高度
const startY = this.$refs['A'][0].offsetTop
// 獲取到手離開屏幕的高度,他是獲取到設備的最頂部到手指離開時的高度,這裏高度需要減去頂部的header
//touch事件會傳入一個手勢參數,第一個存儲着變量,跟點擊事件一樣,存儲事件屬性。
const touchY = e.touches[0].clientY - 79
5.5. vue-cli 項目中的靜態資源訪問以及代碼提交配置
vue-cli
項目中,我們一般是將就靜態文件放在static
文件夾中,因爲整個項目,只能那個文件夾可以被外部訪問到。訪問其他文件夾中的內容會自動跳轉到主頁面。我們可以修改項目中的.gitignore
文件,進行配置在git提交代碼的時候,提交哪些文件。如下面代碼。設置將static
下面的mock
文件夾內的東西不進行提交:
.DS_Store
node_modules/
/dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
static/mock
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
5.6. 項目接口的轉接
我們在寫項目代碼的時候,前端寫的模擬數據,通過自己寫的模擬接口,有可能是通過模擬的json
數據,但是當項目 上線的時候需要進行替換真的API
接口,如果在上線前進行替換,是有風險的,我們可以通過webpack
提供的配置,在config
文件夾下通過配置,將接口進行跳轉,如下面的配置:
proxyTable: {
'/api': {
target: 'http://localhost:8080',
pathRewrite: {
'^/api': 'static/mock'
}
}
},
代碼的意思是,將有/api
請求的路徑替換成http://localhost:8080/static/mock
這樣
5.7. Math 對象的一些方法
Math.round(),Math.ceil(),Math.floor(),Math.trunc
的區別:Math.floor()
首先是向下取整,Math.ceil()
是向上取整,Math.round()
就類似我們的四捨五入,Math.trunc()
方法會將數字的小數部分去掉,只保留整數部分。
5.8. CSS 的 rem 以及 vm
rem
是 CSS3
新增的一個相對單位(root em)
,即相對 HTML
根元素的字體大小的值。
em
也是一個相對單位,卻是相對於當前對象內文本的字體大小。
一般建議在 line-height
使用em
。因爲在需要調整字體大小的時候,只需修改font-size
的值,而line-height
已經設置成了相對行高了。
首行縮進兩個字符:text-indent: 2em
視口單位 vw | vh
:
vw: 1vw = 視口寬度的 1%
vh: 1vh = 視口高度的 1%
5.9. Better-scroll 插件
Better-scroll
插件的用法:
首先進行安裝,輸入命令:cnpm install better-scroll --save
然後在頁面就可以使用,如下面的代碼:它主要的功能是做一個滾動,還有一個彈性的動畫。
import Bscroll from 'better-scroll'
export default {
name: 'CityList',
mounted () {
// 傳入dom元素
this.scroll = new Bscroll(this.$refs.wrapper)
}
}
可以使用該插件自帶的方法,進行滾動到對應的DOM
元素,element
是對應要滾動到的元素DOM
節點,代碼如下
this.scroll.scrollToElement(element)
在vue
中,我們獲取組件,通常是在組件添加一個ref
屬性,然後通過this.$refs.wrapper
獲取到對應的組件,其中wrapper
是我們定義組件的ref
屬性名字。
5.10. 防抖節流的例子
一個防抖節流的例子:這個是做了一個類似通訊錄滑動右側字母列表進行顯示對應首字母的人員,我們會通過touch
事件來完成。思路是這樣的:首先獲取到A
到頂部的距離,然後獲取到手指滑動結束後的位置,用手指滑動後的位置減去A
的位置,就是之間的距離差,然後根據距離差除以每一個字母的高度,就可以獲取到到第幾個位置,然後顯示對應的數據。
但是當我們手指拖動的時候,會頻繁的觸發觸摸事件,所以我們在這裏就可以做一個節流的操作,定義一個計時器,每次移動完之後,首先清除上次的定時器,然後重新定義計時器,每隔16毫秒執行一次事件。這樣避免了頻繁調用事件,下面是實現的代碼:
handleTouchMove (e) {
if (this.touchStatus) {
if (this.timer) {
clearTimeout(this.timer)
}
// 延遲16毫秒執行
this.timer = setTimeout(() => {
// 獲取到手離開屏幕的高度,他是獲取到設備的最頂部到手指離開時的高度,這裏高度需要減去頂部的header
const touchY = e.touches[0].clientY - 79
const index = Math.floor((touchY - this.startY) / 20)
if (index >= 0 && index < this.letter.length) {
this.$emit('change', this.letter[index - 1])
}
}, 16)
}
},
5.11. touch 事件與 click 事件的衝突
有時候我們做的拖動頁面,比如通訊錄的右側拖動字母表,顯示對應的人,但是發現拖動的時候整個頁面也會動,這個時候就需要阻止touchstart
事件的默認行爲,需要在給組件綁定該事件的時候加一個事件修飾符,如下代碼:
@click="handleLetterClick"
@touchstart.prevent="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
5.12. 解決手機不支持 es6 新特性
有些手機會不支持promise
對象,進行發送ajax
請求,這時候我們需要使用一個插件來解決;在項目中安裝插件,輸入下面的命令:
這個插件,會檢測瀏覽器是否支持es6
的新特性,如果不支持,會進行修改。
npm install babel-polyfill --save
然後在main.js
文件中直接引入該插件就可以了import 'babel-polyfill'
6. vuex 知識
6.1. vuex 的使用
他是爲了在多個組件共享數據的時候,方便我們管理共享狀態;首先如果需要使用該插件,還是等進行安裝。可以看下面的vuex
實現步驟:
每一個 Vuex
應用的核心就是 store
(倉庫)。“store”
基本上就是一個容器,它包含着你的應用中大部分的狀態 (state
);所以在使用的使用進行實例化Store
對象,如下面的代碼:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
city: '武漢'
},
// 組件可以直接調用commit進行修改數據,可以不進行事件的派發dispatch
// actions: {
// changeCity (ctx, city) {
// // 通過觸發commit事件,來觸發mutations來修改數據
// ctx.commit('changeCity', city)
// }
// },
mutations: {
changeCity (state, city) {
state.city = city
}
}
})
從上面的示意圖可以看到,如果需要改變狀態裏面的數據,首先得執行Dispatch
進行分發一個事件,去執行一個Actions
,然後通過commit
去觸發Motations
裏面的方法,去改變狀態值;下面代碼是Dispatch
進行分發一個事件:
// 觸發changeCity這個Action
this.$store.dispatch('changeCity', city)
在Store
對象的Actions
裏面我們這樣寫
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
city: '武漢'
},
// 組件可以直接調用commit進行修改數據,可以不進行事件的派發dispatch
actions: {
changeCity (ctx, city) {
// 通過觸發commit事件,來觸發mutations來修改數據
ctx.commit('changeCity', city)
}
},
mutations: {
changeCity (state, city) {
state.city = city
}
}
})
組件可以直接通過commit調用執行mutation裏面的方法就行修改數據,在頁面直接這樣寫
// 組件可以直接通過commit調用執行mutation裏面的方法就行修改數據
this.$store.commit('changeCity', city)
然後在Store
對象的Mutations
直接寫對應的處理函數changeCity
,代碼:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
city: '武漢'
},
mutations: {
changeCity (state, city) {
state.city = city
}
}
})
在頁面中,我們直接這樣訪問store
對象裏面的數值:
<div class="header-right">
{{this.$store.state.city}}
<span class="iconfont arrow-icon"></span>
</div>
6.2. 頁面之間跳轉
對於頁面跳轉的,不僅可以使用<router-link to="/"></router-link>
這種方法跳轉,也可以使用編程式導航這種。進行push要跳轉的地址就可以,代碼如下:
methods: {
handleCityClick (city) {
// 觸發changeCity這個Action
// this.$store.dispatch('changeCity', city)
// 組件可以直接通過commit調用執行mutation裏面的方法就行修改數據
this.$store.commit('changeCity', city)
// 不僅可以使用<router-link></router-link>這種方法跳轉,也可以使用編程式導航這種。進行push要跳轉的地址就可以
this.$router.push('/')
}
},
6.3. 訪問 vuex 數據技巧
6.3.1. 組件中訪問state數據
由於 Vuex
狀態存儲是響應式的,從store
實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態:
// 創建一個 Counter 組件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
調用Vue.use(Vuex)
狀態從根組件“注入”到每一個子組件中:
const app = new Vue({
el: '#app',
// 把 store 對象提供給 “store” 選項,這可以把 store 的實例注入所有的子組件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
然後在組件中可以使用:
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
6.3.2. mapState 輔助函數
訪問vuex
數據技巧:前面寫了可以通過this.$store.state.city
這樣來獲取到我們在Store
對象中定義的state
裏面的數據,我們也可以這樣寫:需要注意的是,遍歷命名只能使mapState
這樣,下面的代碼就是將store
裏面的city
映射到計算屬性裏面的city
import { mapState } from 'vuex'
computed: {
// 展開運算符 把 store裏面的city映射到計算屬性裏面的city
...mapState(['city'])
}
其實mapState
裏面也可以包含一個對象,這樣寫,如下面的代碼:代碼意思是將vuex
的city
映射到計算屬性的currentCity
import { mapState } from 'vuex'
computed: {
// 將vuex的city映射到計算屬性的currentCity
...mapState({
currentCity: 'city'
})
},
同樣對於通過commit
調用Mutations
中的方法,也可以進行改寫,之前是這樣的:
handleCityClick (city) {
// 觸發changeCity這個Action
// this.$store.dispatch('changeCity', city)
// 組件可以直接通過commit調用執行mutation裏面的方法就行修改數據
this.$store.commit('changeCity', city)
// 不僅可以使用<router-link></router-link>這種方法跳轉,也可以使用編程式導航這種。進行push要跳轉的地址就可以
this.$router.push('/')
},
可以藉助 vuex
的簡單方法,進行改寫如下:需要注意的是changeCity
這個方法要對應你在store
對象的Mutations
中定義的一致。還有需要注意的是,需要進行引入import { mapState, mapMutations } from 'vuex'
import { mapState, mapMutations } from 'vuex'
methods: {
handleCityClick (city) {
// 觸發changeCity這個Action
// this.$store.dispatch('changeCity', city)
// 組件可以直接通過commit調用執行mutation裏面的方法就行修改數據
// this.$store.commit('changeCity', city)
// 可以用下面的方法這樣寫
this.changeCity(city)
// 不僅可以使用<router-link></router-link>這種方法跳轉,也可以使用編程式導航這種。進行push要跳轉的地址就可以
this.$router.push('/')
},
...mapMutations(['changeCity'])
},
6.3.3. 使用常量替代 Mutation 事件類型
使用常量替代 mutation
事件類型在各種 Flux
實現中是很常見的模式。這樣可以使linter
之類的工具發揮作用,同時把這些常量放在單獨的文件中可以讓你的代碼合作者對整個app
包含的mutation
一目瞭然:
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// 我們可以使用 ES2015 風格的計算屬性命名功能來使用一個常量作爲函數名
[SOME_MUTATION] (state) {
// mutate state
}
}
})
6.4. vuex 中的 getters 屬性
vuex
中的getters
屬性:他類似vue
的計算屬性一樣,可以根據state
中的數據計算出其他數據,也就是從state
中派生出一些狀態;比如下面的代碼。我需要獲取到我的城市名,出現兩次,代碼如下:下面是store
裏面的代碼
getters: {
doubleCity (state) {
return state.city + ' ' + state.city
}
}
然後在頁面中,我們同樣首先引入mapGetters
,代碼如下:
import { mapGetters } from 'vuex'
computed: {
// 展開運算符 把 store裏面的doubleCity映射到計算屬性裏面的doubleCity
...mapGetters(['doubleCity'])
}
6.5. 使用 keep-alive 優化性能
使用keep-alive
優化性能:我們的頁面每次切換之後,都會進行重新的ajax
請求,這樣會耗費性能,我們可以在<router-view/>
外層包裹一個<keep-alive>
,他是隻要路由渲染過的頁面,會存儲在內存中,再一次加載的時候,不會進行重新渲染 相當於添加了一個緩存
<!-- keep-alive是隻要路由渲染過的頁面,會存儲在內存中,再一次加載的時候,不會進行重新渲染 相當於添加了一個緩存-->
<keep-alive>
<router-view/>
</keep-alive>
但是有的時候,我們需要重新渲染頁面,而不是讀取緩存的內容,在使用keep-alive
會觸發一個activated
方法,只要緩存的頁面,再次顯示,都會執行這個方法。我們可以在這裏進行判斷某些值是否改變,用不用重新發送請求。
activated () {
// 如果添加了keep-alive會有這個事件
if (this.lastCity !== this.city) {
this.lastCity = this.city
this.getHomeInfo()
}
},
6.6. router-link 一些知識
6.6.1. tag 屬性
router-link
一些知識:對於router-link
,vue
會渲染成一個a
標籤,當我們點擊跳轉到其他頁面之後,會變顏色,當然我們可以通過css
進行控制跳轉後鏈接的顏色,我們還可以直接將其他元素改爲 router-link
然後添加一個tag
屬性,等於替換的標籤,如下面的代碼:下面的代碼。本身是一個li
標籤,用router-link
替換之後,添加一個tag="li"
屬性
<router-link tag="li" class="item border-bottom" v-for="item of list" :key="item.id" to="/detail">
![在這裏插入圖片描述]()
<div class="item-info">
<p class="item-title">{{item.title}}</p>
<p class="item-desc">{{item.desc}}</p>
<button class="item-button">查看詳情</button>
</div>
</router-link>
6.6.2. 返回到前一頁
router-link
中:如果想要返回到前一個頁面,屬性to='/'
這樣就可以了,代碼如下
<router-link tag="div" to="/" class="header-abs">
<div class="iconfont header-abs-back"></div>
</router-link>
6.7. <keep-alive> 一些知識點
<keep-alive>
一些知識點:對全局事件解析解綁;當我們在全局使用它進行包裹我們的組件的時候,前面也說了,會將我們的組件進行緩存,但是,他會因此產生兩個生命週期函數,上面介紹了一個每次進入緩存頁面的時候,執行的activated
鉤子函數,還有一個與之對應的鉤子函數就是deactivated
函數,就是離開這個頁面的時候執行的方法。比如現在我們有一個頁面,需要在windoes
對象綁定scroll
事件,但是如果在這個頁面進行綁定了該事件之後,在其他的頁面,還是會執行這個方法,所以我們需要對全局事件進行解綁。代碼如下:activated
鉤子函數是當進入到使用<keep-alive>
緩存的頁面的時候執行的方法,我們在整理進行綁定了滾動事件,deactivated
是當要離開緩存的這個頁面的時候,執行的鉤子函數,我們在這裏進行移除綁定的滾動事件。
activated () {
window.addEventListener('scroll', this.handleScroll)
},
deactivated () {
window.removeEventListener('scroll', this.handleScroll)
}
6.8. vuex 中的插件
Vuex
的 store
接受 plugins
選項,這個選項暴露出每次mutation
的鉤子。Vuex
插件就是一個函數,它接收store
作爲唯一參數:
const myPlugin = store => {
// 當 store 初始化後調用
store.subscribe((mutation, state) => {
// 每次 mutation 之後調用
// mutation 的格式爲 { type, payload }
})
}
使用:
const store = new Vuex.Store({
// ...
plugins: [myPlugin]
})
6.8. 嚴格模式
開啓嚴格模式,僅需在創建store
的時候傳入strict: true
:
const store = new Vuex.Store({
// ...
strict: true
})
7. vue-router 知識點
7.1. 路由中參數的傳遞
如果需要在路由帶參數,直接在路由後面寫上:id
這樣,id
是參數名;如下面的代碼:
{
// 動態路由 id爲參數
path: '/detail/:id',
name: 'Detail',
component: Detail
}
如果需要在頁面中需要獲取路由中的參數,如下面的代碼:使用this.$route.params.id
來進行獲取該頁面中的參數
getDetailInfo () {
axios.get('/api/detail.json?id=', {
params: {
id: this.$route.params.id
}
}).then(this.handleGetDataSucc)
}
一般我們發送
ajax
請求的時候,一般是在頁面掛載之後執行,也就是mounted
鉤子函數裏面去執行發送請求。
還有一種傳遞參數的方式:
<router-link :to="{path:'/mailDetail',query:{id: item.id, type: 'rec'}}" :key="item.id">
<InfoList :info="item"></InfoList>
</router-link>
在組件中接收參數:
data () {
return {
form: {},
fjhref:'',
activeName: '1',
id: this.$route.query.id,
type: this.$route.query.type,
}
},
7.2 組件中 name 的用法總結
組件中name
的用法:組件的遞歸、去除緩存 、清除頁面滾動。
7.2.1. 去除緩存
在指定頁面去除緩存:在keep-alive
組件中添加一個屬性exclude
,屬性內容就是要去除緩存的頁面的name
值,如下面的代碼:
這裏我的組件名叫Detail
,前面我們是通過緩存的兩個鉤子函數activated
和deactivated
配合清除緩存的,下面是另一種方法。
代碼意思就是除了Detail
這個頁面不被緩存,其他頁面都是被緩存的。
<keep-alive exclude="Detail">
<router-view/>
</keep-alive>
7.2.2. 清除頁面滾動
清除頁面滾動行爲:我們在前面時候寫到一個請求滾動的也是通過緩存的兩個鉤子函數activated
和deactivated
配合清除滾動的,其實在vue-router
中,有一個配置項,是清除頁面滾動行爲的,使用前端路由,當切換到新路由時,想要頁面滾到頂部,或者是保持原先的滾動位置,就像重新加載頁面那樣。 vue-router
能做到,而且更好,它讓你可以自定義路由切換時頁面如何滾動,在router
添加下面的代碼,如下:scrollBehavior
選項意思就是每次進行路由切換,始終回到最頂部。
export default new Router({
routes: [
// 當用戶訪問根目錄的時候,<router-view>顯示home組件
{
path: '/',
// 路由名字
name: 'home',
component: Home
}, {
// 動態路由 id爲參數
path: '/detail/:id',
name: 'Detail',
component: Detail
}
],
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
})
7.2.3. 組件的遞歸
遞歸組件:有時候我們在頁面中,會有類似摺疊菜單的這種,樣式是一樣的,使用同一個組件,這就需要使用遞歸組件,如下面數據:
categoryList": [{
"title": "成人票",
"children": [{
"title": "成人三館聯票",
"children": [{
"title": "成人三館聯票 - 某一連鎖店銷售"
}]
},{
"title": "成人五館聯票"
}]
遞歸組件就是在組件中調用他本身,上面的數據,只要有children
我們就進行調用它本身,代碼如下:
<div class="item" v-for="(item,index) of list" :key="index">
<div class="item-title border-bottom">
<span class="item-title-icon"></span>
{{item.title}}
</div>
<div class="item-chilren" v-if="item.children">
<detail-list :list="item.children"></detail-list>
</div>
</div>
需要注意的是
detail-list
這個是改組件的name
值,這就是組件name
的其他用法
7.3. 響應路由參數的變化
當使用路由參數時,例如從 /user/foo
導航到/user/bar
,原來的組件實例會被複用。因爲兩個路由都渲染同個組件,比起銷燬再創建,複用則顯得更加高效。不過,這也意味着組件的生命週期鉤子不會再被調用。
複用組件時,想對路由參數的變化作出響應的話,你可以簡單地 watch
(監測變化) $route
對象:
const User = {
template: '...',
watch: {
'$route' (to, from) {
// 對路由變化作出響應...-----可以再次請求數據
}
}
}
或者使用 2.2 中引入的beforeRouteUpdate
導航守衛:
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
7.4. 路由中傳遞參數
函數式編程導航:
// 字符串
router.push('home')
// 對象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
這裏需要注意:如果提供了path
,params
會被忽略,上述例子中的 query
並不屬於這種情況。取而代之的是下面例子的做法,你需要提供路由的name
或手寫完整的帶有參數的path
:
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 這裏的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
7.5. 命名路由
我們在寫路由對象的時候可以給路由對象加一個name
屬性,通過一個名稱來表示一個路由會顯得更方便一些:
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
要鏈接到一個命名路由,可以給 router-link 的 to 屬性傳一個對象:
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
或者使用編程式導航的方式:
router.push({ name: 'user', params: { userId: 123 }})
兩種方式導航的地址:/user/123
7.6. 命名視圖
如果我們的一個頁面需要展示多個視圖,就可以使用命名視圖,如果 router-view
沒有設置名字,那麼默認爲 default
。
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
一個視圖使用一個組件渲染,因此對於同個路由,多個視圖就需要多個組件。確保正確使用 components
配置 (帶上 s
):
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})
7.7. 組建內的守衛
組建內的守衛有三種:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 `this`
// 因爲當守衛執行前,組件實例還沒被創建
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,但是該組件被複用時調用
// 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 由於會渲染同樣的 Foo 組件,因此組件實例會被複用。而這個鉤子就會在這個情況下被調用。
// 可以訪問組件實例 `this`
},
beforeRouteLeave (to, from, next) {
// 導航離開該組件的對應路由時調用
// 可以訪問組件實例 `this`
}
}
這個離開守衛通常用來禁止用戶在還未保存修改前突然離開。該導航可以通過 next(false)
來取消。
beforeRouteLeave (to, from , next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
7.8.完整的導航解析流程
- 導航被觸發。
- 在失活的組件裏調用離開守衛。
- 調用全局的 beforeEach 守衛。
- 在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
- 在路由配置裏調用 beforeEnter。
- 解析異步路由組件。
- 在被激活的組件裏調用 beforeRouteEnter。
- 調用全局的 beforeResolve 守衛 (2.5+)。
- 導航被確認。
- 調用全局的 afterEach 鉤子。
- 觸發 DOM 更新。
- 用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。
8. 項目上線準備
8.1. API 接口的替換
在項目上線的時候,需要前後臺的聯調,需要使用真實的api
接口進行測試,這時候,我們需要在config
文件夾下的index
進行配置後臺的接口,地址,配置如下面的代碼:這裏,我的後臺的對應的地址是http://localhost:80
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': {
target: 'http://localhost:80',
pathRewrite: {
'^/api': 'static/mock'
}
}
如果後臺跟前臺寫的api
地址是一樣的,可以不進行配置pathRewrite
選項,如下:
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': {
target: 'http://localhost:80'
}
8.2. 移動端項目真機調試
在vue
項目中,webpack
服務器默認是不能通過ip
地址進行訪問我們的項目,比如運行cmd
輸入ipconfig
查看我們的ip
地址,輸入到網頁,是看不到我們的項目,輸入端口80是可以看到的,我們可以通過修改配置,只需要修改項目中的package.json
文件的配置項,代碼如下:
"scripts": {
"dev": "webpack-dev-server --host 0.0.0.0 --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"lint": "eslint --ext .js,.vue src",
"build": "node build/build.js"
},
8.3. 項目打包
vue
項目打包上線:輸入命令npm run build
將我們的代碼進行打包編譯,然後我們的項目會多出來一個dist
的文件夾。裏面就是我們打包項目的代碼。直接將dist
文件夾放在後臺的站點就可以運行了,但是有時候我們的站點需要放在後臺服務器的一個文件夾裏面,比如說,我們需要將前臺的代碼放在一個project
的文件夾中,如果直接放進去,運行項目,你會發現報錯,這個時候,我們需要修改config
文件夾中的inedx.js
裏面的打包項:主要是assetsPublicPath: '/project',
這個
build: {
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: '/project',
}
9. vue 學習路線
vue
學習思路:邊緣知識點進行查看,查看生態系統v-router
中的路由別名等等,查看vuex
中的一些核心概念,然後查看服務器端渲染,然後學習vue
的插件,查看官網的vue
資源。最後研究vue
源碼,查看commit
,瞭解每次提交的的添加的功能的思路。
10. 其他
- 使用
JSX
,需要注意的是:如果使用JSX
,需要在webpack
中進行配置babel-plugin-transform-vue-jsx
, - 看了一篇文章,有關個人技術突破的,首先要了解技術門檻,認清自己當下局勢。然後進行習慣養成與指定目標計劃,
比如讀源碼,或者整理原理圖,當完成目標可以給自己獎勵,也可以不斷測試自己的底線,調整目標。然後就是訓練自己的
思維,善於對問題進行提問:問題是什麼,當前真相是什麼,爲什麼會發生。最後,,就是不怕喫虧。。 - Vue中的插件開發:使用一個公開的方法
install
;v-router
(實現原理跟使用is用來設置顯示組件一樣)、v-vuex
(非父子組件之間通訊的原理)等插件。 - 瀏覽器的基本工作原理從輸入url到使用各種線程渲染頁面。