Vue深度學習總結

1. Vue生命週期解讀

這一部分參考自Vue官方文檔以及生命週期詳解

官網的生命週期圖示例如下:
Vue生命週期圖
測試代碼如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue生命週期學習</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <h1>{{message}}</h1>
      <br/><br/><br/>
      <!-- <h2>{{message + '這是在outer HTML中的'}}</h2> -->
    </div>
  </body>
  <script>
    var vm = new Vue({
      // 註釋el,可理解beforeMounted之前的生命週期
      el: '#app',
      // 同步不註釋h2定義的template,可理解template是如何加載
      // template: "<h2>{{message +'這是在template中的'}}</h2>",
      data: {
        message: 'Vue的生命週期'
      },
      beforeCreate: function() {
        console.group('------beforeCreate創建前狀態------');
        console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
        console.log("%c%s", "color:red","data   : " + this.$data); //undefined 
        console.log("%c%s", "color:red","message: " + this.message) 
      },
      created: function() {
        console.group('------created創建完畢狀態------');
        console.log("%c%s", "color:red","el     : " + this.$el); //undefined
        console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化 
        console.log("%c%s", "color:red","message: " + this.message); //已被初始化
      },
      beforeMount: function() {
        console.group('------beforeMount掛載前狀態------');
        console.log("%c%s", "color:red","el     : " + (this.$el)); //已被初始化
        console.log(this.$el);
        console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化  
        console.log("%c%s", "color:red","message: " + this.message); //已被初始化  
      },
      mounted: function() {
        console.group('------mounted 掛載結束狀態------');
        console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
        console.log(this.$el);    
        console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
        console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
      },
      beforeUpdate: function () {
        console.group('beforeUpdate 更新前狀態===============》');
        console.log("%c%s", "color:red","el     : " + this.$el);
        console.log(this.$el);   
        console.log("%c%s", "color:red","data   : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message); 
      },
      updated: function () {
        console.group('updated 更新完成狀態===============》');
        console.log("%c%s", "color:red","el     : " + this.$el);
        console.log(this.$el); 
        console.log("%c%s", "color:red","data   : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message); 
      },
      beforeDestroy: function () {
        console.group('beforeDestroy 銷燬前狀態===============》');
        console.log("%c%s", "color:red","el     : " + this.$el);
        console.log(this.$el);    
        console.log("%c%s", "color:red","data   : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message); 
      },
      destroyed: function () {
        console.group('destroyed 銷燬完成狀態===============》');
        console.log("%c%s", "color:red","el     : " + this.$el);
        console.log(this.$el);  
        console.log("%c%s", "color:red","data   : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message)
      }
    })
  </script>
</html>

在瀏覽器中打開,控制檯輸出如下圖所示:
這裏寫圖片描述

多次測試後,總結如下:


  • Vue用法:
    • Vue實例中鉤子函數有:beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed.
    • 在創建Vue實例時,能夠調用的鉤子:beforeCreate,created,beforeMount,mounted;
    • 當Vue實例的數據(data)發生改變時,會進行對應組件的重新渲染,能夠調用的鉤子:beforeUpdate,updated;
    • 在Vue實例銷燬前能調用鉤子beforeDestroy,銷燬後能夠調用鉤子destroyed.

  • 生命週期圖解讀:
    • 調用beforeCreate之前,僅僅初始化了Vue實例(都爲’undefined’)
    • 調用Created之前,已經進行了數據的初始化、屬性和方法的運算以及watch/event 事件回調,但還沒有將其掛載(此時頁面的數據已經獲取到,如message=’Vue的生命週期’,el=’undefined’)
    • 調用beforeMount之前,先判斷Vue實例是否有el屬性
    • 當Vue實例沒有el屬性時,會停止編譯,即beforeMount,mounted鉤子函數不會執行。此時只有手動調用vm.$(el)將el掛載在頁面後,才能調用這兩個鉤子函數。
    • 當Vue實例有el屬性時,如果Vue實例中有template屬性(用來包含組件的標籤),會把它當做render函數處理,該子組件的內容會替換掉頁面中定義的內容。
    • 調用mounted之前,Vue實例可以繼續添加el屬性,內容也會隨之覆蓋(此時,纔將用戶定義的內容顯示在頁面,之前只是用{{message}}進行佔位)
    • 當Vue實例的數據發生更新時,可以調用beforeUpdate和updated鉤子函數,詳情可見數據更新鉤子變化
    • 在Vue實例銷燬之前,可以調用beforeDestroy鉤子函數;在Vue 實例銷燬後可以調用destroyed鉤子函數,此時該Vue實例指向的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷燬。

2. 計算屬性、方法、偵聽

  • 計算屬性和方法的案例:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue計算屬性和方法</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
  </head>
  <body>
    <div id="example">
      <p>Original message: "{{ message }}"</p>
      <p>Computed reversed message: "{{ compute_reversedMessage }}"</p>
      <p>method Reversed message: "{{ method_reversedMessage() }}"</p>
    </div>
  </body>
<script>
  // 測試計算屬性和方法的區別
  var vm = new Vue({
    el: '#example',
    data: {
      message: 'Hello'
    },
    computed: {
      // 計算屬性的 getter
      compute_reversedMessage: function () {
        // `this` 指向 vm 實例
        return this.message.split('').reverse().join('')
      }
    },
    // 在組件中
    methods: {
      method_reversedMessage: function () {
        return this.message.split('').reverse().join('')
      }
    }
  })
</script>
</html>

頁面效果如圖所示:
計算屬性
- 偵聽的案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue屬性偵聽</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
  </head>
  <body>
    <div id="watch-example">
      <p>Ask a yes/no question:<input v-model="question"></p>
      <p>{{ answer }}</p>
      </div>
  </body>
  <!-- 因爲 AJAX 庫和通用工具的生態已經相當豐富,Vue 核心代碼沒有重複 -->
  <!-- 提供這些功能以保持精簡。這也可以讓你自由選擇自己更熟悉的工具。 -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
  <script>
    var watchExampleVM = new Vue({
      el: '#watch-example',
      data: {
        question: '',
        answer: 'I cannot give you an answer until you ask a question!'
      },
      watch: {
        // 如果 `question` 發生改變,這個函數就會運行
        question: function (newQuestion, oldQuestion) {
          this.answer = 'Waiting for you to stop typing...'
          this.getAnswer()
        }
      },
      methods: {
        // `_.debounce` 是一個通過 Lodash 限制操作頻率的函數。在這個例子中,我們希望限制訪問 yesno.wtf/api 的// 頻率AJAX 請求直到用戶輸入完畢纔會發出。想要了解更多關於`_.debounce` 函數 (及其近親 `_.throttle`) 的// 知識,請參考:https://lodash.com/docs#debounce
        getAnswer: _.debounce(
          function () {
            if (this.question.indexOf('?') === -1) {
              this.answer = 'Questions usually contain a question mark. ;-)'
              return
            }
            this.answer = 'Thinking...'
            var vm = this
            axios.get('https://yesno.wtf/api')
              .then(function (response) {
                vm.answer = _.capitalize(response.data.answer)
              })
              .catch(function (error) {
                vm.answer = 'Error! Could not reach the API. ' + error
              })
          },
          // 這是我們爲判定用戶停止輸入等待的毫秒數
          500
        )
      }
    })
  </script>
</html>

總結:
- 計算屬性和方法對數據進行操作,能達到相同的效果。計算屬性會基於依賴進行緩存,只有當其依賴的值(message)發生變化時,纔會重新求值。方法則是每次調用時均會進行計算求值。這裏需要根據實際需求進行選擇用計算屬性或者方法。
- watch偵聽question屬性。只要question發生變化,就會調用方法function(newQuestion,oldQuestion)。一般情況下,在數據變化時要執行異步或開銷較大的操作,採用這種方式更爲合理。

3. 渲染

  1. 條件渲染
    • 指令v-if與v-show兩者用法相似,但只有v-if能跟v-else等配合使用。
    • v-if 是“真正”的條件渲染,因爲它會確保在切換過程中條件塊內的事件監聽器和子組件適當地被銷燬和重建。v-show的元素總是會被渲染,只是簡單地基於 CSS (display)進行切換。
    • 這裏要注意:v-if與v-else對應兩個不同的標籤,兩者有相同的元素時,vue默認會複用它們。可以通過指定不同的key屬性,保證每次切換時不復用而是重新渲染。
  2. 列表渲染
    • v-for擁有對父作用域屬性的完全訪問權限。
    • 數組中,(item, index) in items,可選的index爲當前項的索引。
    • 對象中,(value, key, index) in object,可選的key爲對象屬性,可選的index爲對象屬性的索引。
    • v-for比v-if優先級高。
  3. 數組更新的編譯方法說明

這一部分方法會對原數組進行改變:
- push(item),從數組末尾插入一個元素item,返回值爲新數組的長度
- pop(),從數組末尾取出一個元素,返回值爲取出的元素
- shift(),從數組頭部取出一個元素,返回值爲取出的元素
- unshift(item),從數組頭部插入一個元素item,返回值爲新數組的長度
- splice(index),取出數組中下標index到末尾的所有元素,返回值爲取出元素組成的新數組
- reverse(),讓數組倒序重新排布,返回值爲重新排序後的新數組


這一部分方法不會對原數組進行改變
- slice(index),取出數組中下標index到末尾的所有元素,返回值爲取出元素組成的新數組
- filter(item),過濾出符合條件item的所有元素,返回值爲這些元素組成的數組
- concat(item),添加一個元素到數組中,返回值爲這些元素組成的數組


  1. 改變數組中指定下標的元素的值以及長度

由於JavaScript限制,vm.items[indexOfItem] = newValue改變數組中元素的值,vm.items.length = newLength改變數組的長度這種方式,在頁面是不會生效的

# 改變數組中指定元素的值,會引起狀態變化
## 方式一(將數組TargetArray的下標indexOfTarget的元素,值替換爲newValue)
Vue.set(TargetArray, indexOfTarget, newValue)
## 方式二(將數組TargetArray的下標indexOfTarget後count個元素,值替換爲newValue)
TargetArray.splice(indexOfTarget, count, newValue)
# 改變數組的長度(將數組TargetArray的長度設置爲newLength)
TargetArray.splice(newLength)

4. 事件處理

常用的事件修飾符如下:

# 事件修飾符
<!-- 阻止單擊事件繼續傳播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯 -->
<a 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>
<!-- 點擊事件將只會觸發一次 -->
<a v-on:click.once="doThis"></a>

# 按鍵修飾符
<!-- 只有在 `keyCode` 是 13 時調用 `vm.submit()` -->
<input v-on:keyup.13="submit">
<!-- 在用戶點擊enter後,調用'vm.submit()' -->
<input v-on:keyup.enter="submit">
<!-- 常用的還有 -->
{tab},{delete},{esc},{space},{up},{down},{left},{right}

# 其他
<!-- 在“change”時而非“input”時更新 -->
<input v-model.lazy="msg">
<!-- 輸入值轉爲數值類型 -->
<input v-model.number="age" type="number">
<!-- 過濾首尾空白字符 -->
<input v-model.trim="msg">

5. 組件使用

註冊並使用一個全局組件

<html>
  <body>
    <div id="example">
      <!-- 將組件my-component注入到根實例中 -->
      <my-component></my-component>
    </div>
  </body>
  <script>
    // 註冊全局組件
    Vue.component('my-component', {
      template: '<div>A custom component!</div>'
    })

    // 創建根實例
    new Vue({
      el: '#example'
    })
  </script>
</html>

組件注入後,在DOM解析時可能會有一些異常,以及解決辦法如下:

<!-- 類似table的標籤,在DOM解析時,只能識別指定的部分元素(th,tr,td等),此時加入自定義標籤(my-row爲自定義組件的名稱)時,會解析異常 -->
<table>
  <my-row>...</my-row>
</table>

<!-- 用元素的is特性進行封裝,可以解決上面的問題 -->
<table>
  <tr is="my-row"></tr>
</table>

6. 組件通訊


組件實例的作用域是孤立的。這意味着不能 (也不應該) 在子組件的模板內直接引用父組件的數據。prop 向下傳遞,事件向上傳遞。 父組件通過 prop 給子組件下發數據,子組件通過事件給父組件發送消息。


父組件向子組件下發數據的實現:

  1. 子組件定義時,指定屬性props的key值(myMessage)
  2. 在父組件中引入子組件後,將父組件的作用域內的數據(parentMsg)傳入子組件指定prop的key值(:my-message=”parentMsg”)
  3. 由於HTML不區分大小寫,這裏用的是”-“進行間隔的區分;由於這種數據的傳輸是單向的,子組件中值的改變不會影響父組件中的狀態。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue父子組件通訊-prop向下</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
  </head>
  <body>
    <div id="example">
      <div>
        <input v-model="parentMsg">
        <br>
        <child v-bind:my-message="myMessage"></child>
      </div>
    </div>
  </body>
  <script>
    Vue.component('child', {
      // 在 JavaScript 中使用 camelCase
      props: ['myMessage'],
      template: '<span>{{ myMessage }}</span>'
    })

    // 創建根實例
    new Vue({
      el: '#example',
      data: {
          parentMsg: ''
      },
      computed: {
        // 如果子組件獲取到父組件的數據後想更改,需要用計算屬性的方法進行更改
        // 下面這個計算屬性:將父組件的數據全小寫展示在子組件中
        myMessage: function() {
          return this.parentMsg.toLowerCase()
        }
      }
    })
  </script>
</html>

父組件獲知子組件觸發了某個事件的實現:
1. 通過Vue實例的(emit, on)方法實現子組件發送信息給父組件
2. 點擊按鈕,觸發子組件的點擊事件(incrementCounter),該事件會調用Vue實例的方法(this.$emit(‘increment’));父組件中時刻監聽increment(v-on:increment=”incrementTotal”),接收到了信號increment後會調用父組件的方法(incrementTotal),父組件更新total值。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue父子組件通訊-事件向上</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
  </head>
  <body>
    <div id="counter-event-example">
          <p>{{ total }}</p>
        <button-counter v-on:increment="incrementTotal"></button-counter>
        <button-counter v-on:increment="incrementTotal"></button-counter>
      </div>
  </body>
  <script>
    Vue.component('button-counter', {
        template: '<button v-on:click="incrementCounter">{{ counter }}</button>',
        data: function () {
            return {
            counter: 0
            }
        },
        methods: {
            incrementCounter: function () {
          this.counter += 1
          this.$emit('increment')
            }
        },
      })

      new Vue({
        el: '#counter-event-example',
        data: {
            total: 0
        },
        methods: {
            incrementTotal: function () {
          this.total += 1
            }
          }
      })
  </script>
</html>

非父子組件的通訊,可參考子組件傳遞信息給父組件。均是基於Vue實例的方法(emit, on)實現

7. 插槽

插槽,一種混合父組件內容與子組件模板內容的實現方式。
- 子組件模板包含至少一個slot插口,否則父組件的內容將會被丟棄。最初在slot標籤中的任何內容都被視爲備用內容。只有在宿主元素爲空,且沒有要插入的內容時才顯示備用內容。
- 具名插槽。父子組件根據slot標籤的name屬性進行配對分發內容,父組件匹配不到子組件的name時,內容會分發到默認的slot(未指定name屬性)中。
- 作用域插槽。一個 (能被傳遞數據的) 可重用模板,來代替已經渲染好的元素。

8.CSS過渡動畫

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue中的CSS過渡動畫效果</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
  </head>
  <body>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
    <div id="list-complete-demo" class="demo">
      <button v-on:click="shuffle">Shuffle</button>
      <button v-on:click="add">Add</button>
      <button v-on:click="remove">Remove</button>
      <transition-group name="list-complete" tag="p">
        <span
          v-for="item in items"
          v-bind:key="item"
          class="list-complete-item"
        >
          {{ item }}
        </span>
      </transition-group>
    </div>
  </body>
  <script>
    new Vue({
      el: '#list-complete-demo',
      data: {
        items: [1,2,3,4,5,6,7,8,9],
        nextNum: 10
      },
      methods: {
        randomIndex: function () {
          return Math.floor(Math.random() * this.items.length)
        },
        add: function () {
          this.items.splice(this.randomIndex(), 0, this.nextNum++)
        },
        remove: function () {
          this.items.splice(this.randomIndex(), 1)
        },
        shuffle: function () {
          this.items = _.shuffle(this.items)
        }
      }
    })
  </script>
  <style>
    .list-complete-item {
      transition: all 1s;
      display: inline-block;
      margin-right: 10px;
    }
    .list-complete-enter, .list-complete-leave-to {
      opacity: 0;
      transform: translateY(30px);
    }
    .list-complete-leave-active {
      position: absolute;
    }
    </style>
</html>

總結:
- Vue項目是通過transition標籤包裹需要動畫效果的元素,基於四種狀態該圖片的四種狀態,設置相應的播放效果。

9. Vue的常用API

  • nextTick()用法

常見的nextTick()用法如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Vue中nextTick用法案例</title>
    <script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <example></example>
    </div>
  </body>
  <script>
    Vue.component('example', {
      template: '<span>{{ message }}</span>',
      data: function () {
        return {
          message: '沒有更新'
        }
      },
      mounted () {
          this.updateMessage();
      },
      methods: {
        updateMessage: function () {
          this.message = '更新完成'
          console.log('數據更新後直接打印:' + this.$el.textContent) // => '沒有更新'
          this.$nextTick(function () {
            console.log('數據更新後在nextTick中打印:' + this.$el.textContent) // => '更新完成'
          })
        }
        }
      })

    new Vue({
      el:'#app'
    })    
  </script>
</html>

控制檯輸出結果:nextTick用法結果
說明:我們經常會遇到類似上例的場景—在頁面的數據(message)更新之後,需要根據更新後的數據去實現別的功能A(這裏是在控制檯打印:”更新完成”)。由於JavaScript中方法執行的異步性,執行功能A時所用數據可能不是更新後的數據,這會導致實現的功能並不符合我們的預期效果(就像這裏,控制檯輸出的是:”數據更新後直接打印:沒有更新”)。這時,我們可以用Vue的nextTick方法,保證功能達到預期效果。它能夠保證是在數據更新後才調用該方法,使用的是更新後的DOM.

  • Vue.set(target,key,value)
    說明:前面改變數組中指定元素的值並保證頁面正確顯示時已經用過這個方法。Vue實例時響應式的,在初始化時聲明的屬性也是響應式的,但後期掛載的屬性並不是響應式的。用Vue.set(target,key,value)方法能確保新建後的屬性也是響應式的。

  • Vue.component(id, [definition])

// 註冊組件,傳入一個擴展過的構造器
Vue.component('my-component', Vue.extend({ /* ... */ }))

// 註冊組件,傳入一個選項對象 (自動調用 Vue.extend)
Vue.component('my-component', { /* ... */ })

// 獲取註冊的組件 (始終返回構造器)
var MyComponent = Vue.component('my-component')

Vue-router的使用

  1. (路由導航)的實現
    • 1.1 用router-link實現路由跳轉

一個最基本的應用了路由的例子如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>router-link實現路由導航</title>
  </head>
  <body>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <div id="app">
      <h1>Hello App!</h1>
      <p>
        <!-- 使用 router-link 組件來導航. -->
        <!-- 通過傳入 `to` 屬性指定鏈接. -->
        <!-- <router-link> 默認會被渲染成一個 `<a>` 標籤 -->
        <router-link to="/foo">Go to Foo</router-link>
        <router-link to="/bar">Go to Bar</router-link>
      </p>
      <!-- 路由出口 -->
      <!-- 路由匹配到的組件將渲染在這裏 -->
      <router-view></router-view>
    </div>

    <script>
      // 0. 如果使用模塊化機制編程,導入Vue和VueRouter,要調用 Vue.use(VueRouter)
      // 1. 定義(路由)組件。
      const Foo = { template: '<div>foo</div>' }
      const Bar = { template: '<div>bar</div>' }

      // 2. 定義路由
      // 每個路由應該映射一個組件
      const routes = [
        { path: '/foo', component: Foo },
        { path: '/bar', component: Bar }
      ]

      // 3. 創建 router 實例,然後傳 `routes` 配置
      const router = new VueRouter({routes: routes})

      // 4. 創建和掛載根實例。
      const app = new Vue({router}).$mount('#app')
    </script>
  </body>
</html>

說明:/user/foo 導航到 /user/bar,原來的組件實例會被複用。因爲兩個路由都渲染同個組件,比起銷燬再創建,複用則顯得更加高效。不過,這也意味着組件的生命週期鉤子不會再被調用。要想監測變化,需要用watch或者beforeRouteUpdate.

  • 1.2 用router實例的方法(push,replace,go)實現路由跳轉

用法如下:

// 字符串
router.push('home')
// 對象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

// 在瀏覽器記錄中前進一步,等同於 history.forward()
router.go(1)
// 後退一步記錄,等同於 history.back()
router.go(-1)
// 前進 3 步記錄
router.go(3)

說明
- push方法的參數有name(目標路由名稱)和path(目標路由路徑)兩種方式,如果提供了path,此時params(參數)的使用會失效,這裏可以用query來替代;
- push和replace的用法一樣,只是如同字面意思,只會要指向效果,沒有history中添加相應的記錄。

  1. 命名視圖
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>命名視圖簡單用法</title>
  </head>
  <body>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <div id="app">
      <h1>Named Views</h1>
      <ul>
        <li>
          <router-link to="/">/</router-link>
        </li>
        <li>
          <router-link to="/other">/other</router-link>
        </li>
      </ul>
      <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>
    </div>
    <script>
      const Foo = { template: '<div>foo</div>' }
      const Bar = { template: '<div>bar</div>' }
      const Baz = { template: '<div>baz</div>' }

      const router = new VueRouter({
        mode: 'history',
        routes: [
          { path: '/',
            components: {
              default: Foo,
              a: Bar,
              b: Baz
            }
          },
          {
            path: '/other',
            components: {
              default: Baz,
              a: Bar,
              b: Foo
            }
          }
        ]
      })

      new Vue({
        router,
        el: '#app'
      })
    </script>
  </body>
</html>

說明:當點擊router-link(to=’/’),解析如下:跳轉至路徑(path)爲’/’的路由中,該路由的內容爲有命名視圖(name:component)構成的三個組件(default:Foo,a:Bar,b:Baz),按名稱在router-view中展示相應組件的內容(如router-view中name爲a的,展示組件Bar的內容)。這裏要注意的是,只有一個路由時用component,有多個路由時用components

  1. props解耦
// 解耦前
const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})

// 用props解耦後
const User = {
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User, props: true },
    // 對於包含命名視圖的路由,你必須分別爲每個命名視圖添加 `props` 選項:
    {
      path: '/user/:id',
      components: { default: User, sidebar: Sidebar },
      props: { default: true, sidebar: false }
    }
  ]
})

說明:直接在組件中通過$route獲取參數id,會導致該組件與路由緊緊耦合。用props解耦後,能讓該組件更易於重用和測試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章