Vue知識回顧-零碎知識點

文章目錄

1. 傳統的 MVP 開發模式與 MVVM 開發模式對比

  1. 對於傳統的mvp開發模式,m也就是model一般是通過發送ajax請求獲取到的數據,v也就是視圖,p就是Presenter相當於控制器,
    Presenter作爲View和Model之間的“中間人”,除了基本的業務邏輯外,還有大量代碼需要對從ViewModel和從ModelView的數據進行“手動同步”,這樣Presenter顯得很重,維護起來會比較困難。而且由於沒有數據綁定,如果Presenter對視圖渲染的需求增多,它不得不過多關注特定的視圖,一旦視圖需求發生改變,Presenter也需要改動,我們大部分的關注點是在視圖與數據,以及通過控制器進行操作。
  2. 對於vue的開發模式mvvm,他把ViewModel的同步邏輯自動化了,與MVP不同,沒有了ViewPresenter提供的接口,之前由Presenter負責的ViewModel之間的數據同步交給了ViewModel中的數據綁定進行處理,當Model發生變化,ViewModel就會自動更新;ViewModel變化,Model也會更新。我們的關注點主要是在modelview之間,而model發生變化,view進行同步更新,這些都交給了viewmodelmvp的模式我們大部分的關注點是在操作了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的值爲trueclass 列表將變爲"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的值爲trueclass 列表將變爲"static active text-danger"

<div class="active text-danger"></div>

這樣寫將始終添加errorClass,但是隻有在isActivetrue時才添加 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屬性時,如transformVue.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的數組操作函數,另一個是使用vueset方法、

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 變量名或屬性名,所以就沒有理由使用 camelCasePascalCase 了。並且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是因爲我們添加的namefade,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.csstransition標籤上直接使用: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" 並把它破壞!慶幸的是,classstyle 特性會稍微智能一些,即兩邊的值會被合併起來,從而得到最終的值: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 選項不會影響styleclass的綁定。

這個模式允許你在使用基礎組件的時候更像是使用原始的 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 的區別

JavascriptPromise對象與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}`);
	})

rejectreslove使用,在創建promise對象的時候進行判斷,如果符合條件,就執行resolve,不符合就執行reject
然後就是.then,不管是成功還是失敗,都會執行,也就是執行reject的時候會執行.catch.catch是執行失敗的時候會調用。

4.2. vue-cli 知識

.vue文件是代表vue的一個組件,在js文件中我們創建一個組件,是通過Vue.component('com-a',{})這樣,在vue工程化中,我們使用.vue的文件進行創建組件。
對於vue-cli腳手架的理解,首先我們在根目錄的main.js文件中,可以看到:引用了router以及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. 移動端像素問題

首先需要明白rempx像素單位之間的轉化;1rem = html font-size = 50px;經常爲了方便處理轉換rem;我們會將htmlfont-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

remCSS3新增的一個相對單位(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">&#xe64a;</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裏面也可以包含一個對象,這樣寫,如下面的代碼:代碼意思是將vuexcity映射到計算屬性的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-linkvue會渲染成一個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">&#xe624;</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 中的插件

Vuexstore 接受 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,前面我們是通過緩存的兩個鉤子函數activateddeactivated配合清除緩存的,下面是另一種方法。
代碼意思就是除了Detail這個頁面不被緩存,其他頁面都是被緩存的。

    <keep-alive exclude="Detail">
      <router-view/>
    </keep-alive>
7.2.2. 清除頁面滾動

清除頁面滾動行爲:我們在前面時候寫到一個請求滾動的也是通過緩存的兩個鉤子函數activateddeactivated配合清除滾動的,其實在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' }})

這裏需要注意:如果提供了pathparams會被忽略,上述例子中的 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.完整的導航解析流程
  1. 導航被觸發。
  2. 在失活的組件裏調用離開守衛。
  3. 調用全局的 beforeEach 守衛。
  4. 在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
  5. 在路由配置裏調用 beforeEnter。
  6. 解析異步路由組件。
  7. 在被激活的組件裏調用 beforeRouteEnter。
  8. 調用全局的 beforeResolve 守衛 (2.5+)。
  9. 導航被確認。
  10. 調用全局的 afterEach 鉤子。
  11. 觸發 DOM 更新。
  12. 用創建好的實例調用 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. 其他

  1. 使用JSX,需要注意的是:如果使用JSX,需要在webpack中進行配置babel-plugin-transform-vue-jsx
  2. 看了一篇文章,有關個人技術突破的,首先要了解技術門檻,認清自己當下局勢。然後進行習慣養成與指定目標計劃,
    比如讀源碼,或者整理原理圖,當完成目標可以給自己獎勵,也可以不斷測試自己的底線,調整目標。然後就是訓練自己的
    思維,善於對問題進行提問:問題是什麼,當前真相是什麼,爲什麼會發生。最後,,就是不怕喫虧。。
  3. Vue中的插件開發:使用一個公開的方法installv-router(實現原理跟使用is用來設置顯示組件一樣)、v-vuex(非父子組件之間通訊的原理)等插件。
  4. 瀏覽器的基本工作原理從輸入url到使用各種線程渲染頁面。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章