Vue.js學習

weixin_34402408發表於2018-10-01

一、瞭解Vue.js

1.1.1 Vue.js是什麼?

  • 簡單小巧、漸進式、功能強大的技術棧

1.1.2 為什麼學習Vue.js?

  • 學習曲線平緩、易上手、功能強大、輕便
  • 目前最流行的三大框架之一,適用範圍廣
  • 升職加薪 ------ 哈哈哈哈哈哈哈哈

1.1.3 Vue.js的模式

  • MVVM模式,檢視層和資料層的雙向繫結,讓我們無需再去關係DOM操作的事情,更過的精力放在資料和業務邏輯上去

1.1.4 Vue.js環境搭建

  • script
  • vue腳手架工具vue-cli搭建。

二、資料繫結,指令,事件

2.1.1 vue例項和資料繫結

一、

<script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>

通過建構函式Vue就可以建立一個Vue的根例項,並啟動Vue應用---入口

var app = new Vue({
  el: '',
  data: {
  }
})

二、
其中必不可少的一個選項就是el,el用於指定一個頁面中已存在的DOM元素來掛載Vue例項

三、
通過Vue例項的data選項,可以宣告應用內需要雙向繫結的資料。建議所有會用到的資料都預先在data內宣告,這樣不至於將資料散落在業務邏輯中,難以維護。也可以指向一個已經有的變數

四、
掛載成功後,我們可以通過app.$el來訪問該元素。Vue提供了很多常用的例項屬性與方法,都已 $開頭,比如 $el,Vue例項本身也代理了data物件裡所有屬性,所以可以這樣訪問

五、
如果是訪問data裡的屬性,用app.屬性名

2.1.2

created: 例項穿件完成後呼叫,此階段完成了資料的觀測等,但尚未掛載,$el還不可用。需要初始化處理一些資料時會比較有用。------還未掛載

mounted: el掛載到例項上後呼叫,一般我們的第一個業務邏輯會從這裡開始。------剛剛掛載

beforeDestroy: 例項銷燬之前呼叫。主要解綁一些使用addEventListener監聽的事件等。

2.1.3 文字插值和表示式

語法: 使用雙大括號(Mustache語法)"{{ }}"是最基本的文字插值方法,他會自動將我們雙向繫結的資料實時顯示出來

用法:

  • 在{{ }}中,處了簡單的繫結屬性值外,還可以使用JavaScript表示式進行簡單的運算、三元運算等
  • Vue.js只支援單個表示式,不支援語句和流控制

2.2.1 過濾器

Vue支援在{{ }}插值的尾部新增一小管道符"|"對資料進行過濾,經常用於格式化文字,比如字母全部大寫、貨幣千位使用逗號分隔等。過濾的規則是自定義的,通過給Vue例項新增選項filters來設定
過濾器:{{data | filter1 | filter2}}
{{data | formatData(1,2)}}中的第一個和第二個引數,分別對應過濾器的第二個和第三個引數

2.2.2 指令和事件

指令( Directives )是 Vue 模板中最常用的一項功能,它帶有字首 v-,能幫我們
快速完成DOM操作。迴圈渲染。顯示和隱藏

  • v-­text:—————­解析文字 和{{ }} 作用一樣
  • v­-html:————— 解析html
  • v­-bind—————–v­bind 的基本用途是動態更新 HTML 元素上的屬性,比如 id 、class 等,本節只介紹基本章節,後面章節會更加深入詳細講述
  • v­-on——————它用來繫結事件監聽器
    v­-on具體介紹
    在普通元素上, v­on 可以監聽原生的 DOM 事件,除了 click 外,還有
    dblclick、 keyup, mousemove 等。表示式可以是一個方法名,這些方法都寫在 Vue 例項的 methods屬性內,並且是函式的形式,函式內的 this 指向的是當前 Vue 例項本身,因此可以直接使用 this.xxx 的形式來訪問或修改資料vue中用 到的所有方法都定義在methods

2.2.3 語法糖

語法糖是指在不影響功能的情況下 , 新增某種簡潔方法實現同樣的效果 , 從而更加方便程
序開發。

  • v-bind ——> : (冒號)
  • v-on ——> @

運用以上知識點,總和一個小demo:

<!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>demo</title>
    <style>
      .data {
          background: red;
          height: 18px;
      }
    </style>
</head>
<body>
    <div id="app">
        {{name}} <br>
        {{name | formatDate}}
        <br>
        <div v-html="html"></div>
        <span v-text="weather"></span>
        <br>
        <div v-bind:class="className"></div>
        <button v-on:click="click">{{countnum}}</button>
    </div>
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
        var plusDate = function(value){
            return value < 10 ? '0' + value : value
        }
      var app = new Vue({
          el : '#app',
          data : {
              name: new Date(),
              html: '<div>你好</div>',
              weather: '今天天氣不錯',
              className: 'data',
              countnum: 0
          },
          
          filters:{
              formatDate: function(value) {
                  var date = new Date(value)
                  var year = date.getFullYear()
                  var month = plusDate(date.getMonth()+1)
                  var day = plusDate(date.getDate())
                  var hours = plusDate(date.getHours())
                  var min = plusDate(date.getMinutes())
                  var sec = plusDate(date.getSeconds())
                  return year + '--' + month + '--' + day + '  ' + hours + ':' + min + ':' + sec
              }
          },
          mounted: function(){
              var _this = this
              this.timer = setInterval(function(){
                  _this.name = new Date()
              },1000)
          },
          methods: {
              click: function(){
                  this.countnum = this.countnum + 1 
              }
          },
          beforeDestroy: function(){
              clearInterval(this.timer)
          }
      })
    </script>
</body>
</html>

三、 計算屬性

3.1 什麼是計算屬性

我們己經可以搭建出一個簡單的 Vue 應用,在模板中雙向繫結一些資料或表示式了。但是表示式如果過長,或邏輯更為複雜時,就會變得雕腫甚至難以閱讀和維護

<div>
{{ text.split ( ’,’ ) •reverse () . join (’,’)}}
</div>
  • 這裡的表示式包含 3 個操作,並不是很清晰,所以在遇到複雜的邏輯時應該使用 計算屬性
  • 所有的計算屬性都以函式的形式寫在 Vue 例項內的computed 選項內,最終返回計算後的結果。

3.2 計算屬性用法

  • 在一個計算屬性裡可以完成各種複雜的邏輯,包括運算、函式呼叫等,只要最終返回一個結果就可以。除了上例簡單的用法
  • 計算屬性還可以依賴多個 Vue 例項的資料,只要其中任一資料變化,計算屬性就會重新執行,檢視也會更新

getter和setter

  • 每一個計算屬性都包含一個 getter 和一個 setter,我們上面的兩個示例都是計算屬性的預設用法 , 只是利用了 getter來讀取。在你需要時,也可以提供一個 setter 函式 , 當手動修改計算屬性的值就像修改一個普通資料那樣時,就會觸發 setter函式,執行一些自定義的操作

  • 計算屬性除了上述簡單的文字插值外,還經常用於動態地設定元素的樣式名稱 class 和內聯樣式 style

小技巧: 計算屬性還有兩個很實用的小技巧容易被忽略:

  • 一、是計算屬性可以依賴其他計算屬性:
  • 二、是計算屬性不僅可以依賴當前 Vue 例項的資料,還可以依賴其他例項的資料

3.3計算屬性快取

呼叫 methods 裡的方法也可以與計算屬性起到同樣的作用

  • 頁面中的方法: 如果是呼叫方法,只要頁面重新渲染。方法就會重新執行,不需要渲染,則不需要重新執行

  • 計算屬性:不管渲染不渲染,只要計算屬性依賴的資料未發生變化,就永遠不變

  • 結論: 沒有使用計算屬性,在 methods 裡定義了一個方法實現了相同的效果,甚至該方法還可以接受引數,使用起來更靈活。既然使用 methods 就可以實現,那麼為什麼還需要計算屬性呢?原因就是計算屬性是基於它的依賴快取的。 一個計算屬性所依賴的資料發生變化時,它才會重新取值,所以text 只要不改變,計算屬性也就不更新

何時使用: -----------使用計算屬性還是 methods 取決於你是否需要快取,當遍歷大陣列和做大量計算時,應當使用計算屬性,除非你不希望得到快取。

計算屬性demo

<!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>計算屬性</title>
</head>
<body>
    <div id="data">
        {{fullName}} <br>
        {{watch()}}
    </div>
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
      var app = new Vue({
          el: '#data',
          data: {
              firstName:'Cai',
              lastName: 'hua'
          },
          computed: {
             fullName: function(){
                  return this.firstName + ' ' + this.lastName
              }
          },
          methods: {
              watch: function(){
                return this.firstName + ' ' + this.lastName
              }
          }
      })
    </script>
</body>
</html>

四、 v-­bind以及class與style的繫結

應用場景: DOM 元素經常會動態地繫結一些 class 類名或 style 樣式

4.1 瞭解bind指令

v-­bind的複習:

  • 連結的 href 屬性和圖片的 src 屬性都被動態設定了,當資料變化時,就會重新渲染。

  • 在資料繫結中,最常見的兩個需求就是元素的樣式名稱 class 和內聯樣式 style 的動態繫結,它們也是 HTML的屬性,因此可以使用 v­-bind 指令。

  • 我們只需要用 v­-bind計算出表示式最終的字串就可以,不過有時候表示式的邏輯較複雜,使用字串拼接方法較難閱讀和維護,所以 Vue.js 增強了對 class 和 style 的繫結。

4.2 繫結 class 的幾種方式

4.2.1 物件語法

  • 給 v-­bind:class 設定一個物件,可以動態地切換 class,值對應true ,false

  • 當 class 的表示式過長或邏輯複雜時,還可以繫結一個計算屬性,這是一種很友好和常見的用法,一般當條件多於兩個時, 都可以使用 data 或 computed

4.2.2 陣列語法

當需要應用多個 class 時, 可以使用陣列語法 , 給:class 繫結一個陣列,應用一個 class列表:

  • 陣列成員直接對應className--類名
  • 可以用三目運算實現,物件和陣列混用

4.2.3 在元件上使用 : 暫時不考慮—­挖坑

4.3 繫結內聯樣式

使用 v­-bind:style (即:style ) 可以給元素繫結內聯樣式,方法與 :class 類似,也有物件語法和陣列語法,看起來很像直接在元素上寫 CSS

注意 : css 屬性名稱使用駝峰命名( came!Case )或短橫分隔命名( kebab­case),應用多個樣式物件時 , 可以使用陣列語法,在實際業務 中,style 的陣列語法並不常用 , 因為往往可以寫在一個物件裡面, 而較為常用 的應當是計算屬性

使用 :style 時, Vue .js 會自動給特殊的 css 屬性名稱增加字首, 比如 transform 。

無需再加字首屬性!!!!

v-bind繫結demo:

<!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>v-bind繫結</title>
    <style>
      .divStyle{
          width: 88px;
          height: 88px;
          background: red;
      }
      .borderStyle{
          border: 8px solid black;
      }
      .color{
          color: red;
      }
      .size{
          font-size: 28px;
      }
      .blueClass{
          color: blue;
      }
      .font{
          font-size: 36px;
      }
    </style>
</head>
<body>
    <div id="demo">
        //物件語法 <br>
        <div v-bind:class="{divStyle : isActive, borderStyle : isBorder}"></div>
        <hr>
        //陣列語法<br>
        <div v-bind:class="[colorClass,sizeClass]">Hello word</div>
        <hr>
        //物件和陣列混用
        <div v-bind:class="[{blueClass : isBlue},fontClass]">你好!</div>
        <hr>
        //繫結內聯樣式
        <div v-bind:style="{'background':background,'fontSize':fontSize + 'px'}">真好!</div>
    </div>
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
      var app = new Vue({
          el:'#demo',
          data:{
              isActive: true,
              isBorder: true,
              colorClass:"color",
              sizeClass: "size",
              isBlue:true,
              fontClass:"font",
              background: 'red',
              fontSize:'56'
          }
      })
    </script>
</body>
</html>

五、vueJS中的內建指令

5.1 基本指令

5.1.1 v-­cloak一般與display:none進行結合使用

作用:解決初始化慢導致頁面閃動的最佳實踐

5.1.2 v-­once

定義:它的元素和元件只渲染一次

5.2 條件渲染指令

5.2.1 v-­if, v-­eles-­if ,v-­else

用法: 必須跟著屁股走

v-if的弊端 :
Vue 在渲染元素時 ,出於效率考慮,會盡可能地複用已有的元素而非重新渲染, 因此會出現烏龍,只會渲染變化的元素,也就是說,input元素被複用了

解決方法: 加key,唯一,提供key值可以來決定是否複用該元素

5.2.2 v-­show

  • 只改變了css屬性display
v­-if和v­-show的比較

v-­if:

  • 實時渲染:頁面顯示就渲染,不顯示。我就給你移除

v-­show:

  • v-­show的元素永遠存在也頁面中,只是改變了css的display的屬性

5.3 列表渲染指令v­-for

用法: 當需要將一個陣列遍歷或列舉一個物件屬性的時候迴圈顯示時,就會用到列表渲染指令 v­-for。

兩種使用場景:
  • 遍歷多個物件
  • 遍歷一個物件的多個屬性

v-for demo

<body>
    <div id="demo">
            //遍歷多個物件一定是遍歷的陣列
            //帶索引的寫法:括號的第一個變數,代表item,第二個代表index
        <ul>
            <li v-for="vuestu in vueStudy">{{vuestu.name}}</li>
        </ul>
        <br>
        //遍歷一個物件的多個屬性
        //拿到value,key,index的寫法 v-k-i--外開
        <div v-for="(value,key,index) in women">{{index}}-----{{key}}------{{value}}</div>
    </div>
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
      var app = new Vue({
          el:'#demo',
          data:{
              vueStudy:[
                  //每個物件對應一個li
                  {name:'敲程式碼'},
                  {name:'看資料'},
                  {name:'看蔡華鵬部落格'}
              ],
              women:{
              grid1: '張柏芝',
              grid2: '迪麗熱巴',
              grid3: '高圓圓'
          }
          }
      })
    </script>
</body>

5.4 陣列更新,過濾與排序

改變陣列的一系列方法:

  • push() 在末尾新增元素
  • pop() 將陣列的最後一個元素移除
  • shift() 刪除陣列的第一個元素
  • unshift():在陣列的第一個元素位置新增一個元素
  • splice() :可以新增或者刪除函式—返回刪除的元素
    三個引數:
    • 第一個引數 表示開始操作的位置
    • 第二個參數列示:要操作的長度
    • 第三個為可選引數:
  • sort():排序
  • reverse()

兩個陣列變動vue檢測不到:

  1. 改變陣列的指定項
  2. 改變陣列長度

改變指定項: Vue.set(app.arr,1,”car”);
app.arr.splice(1): 改變陣列長度
過濾:filter

解決方法:

1. set
2. splice

5.5 方法和事件

[object MouseEvent]

5.5.1 基本用法

v-­on繫結的事件類似於原生 的onclick等寫法:

methods:{
  handle:function (count) {
    count = count || 1;
    this.count += count;
  }
}

如果方法中帶有引數,但是你沒有加括號,預設傳原生事件物件event

5.5.2 修飾符

  • 在vue中傳入event物件用 $event
  • 向上冒泡
    stop:阻止單擊事件向上冒泡
    prevent:提交事件並且不過載頁面
    self:只是作用在元素本身而非子元素的時候呼叫
    once: 只執行一次的方法
可以監聽鍵盤事件:

<input @keyup.13 ="submitMe"> ——­指定的keyCode

vueJS為我們提供了:

.enter
.tab
.delete 等等、、、、、、

六、 表單與v-­model

6.1 基本用法

v­-model:

VUE提供了v­model指令, 用於在表單類元素上雙向繫結事件

input和textarea

可以用於input框,以及textarea等

注意: 所顯示的值只依賴於所繫結的資料,不再關心初始化時的插入的value

單選按鈕:

  • 單個單選按鈕,直接用v­-bind繫結一個布林值,用v-­model是不可以的
  • 如果是組合使用,就需要v­-model來配合value使用,繫結選中的單選框的value值,此處所繫結的初始值可以隨意給

核取方塊:

  • 單個核取方塊,直接用定一個布林值,可以用v­-model可以用v-­bind
  • 多個核取方塊– 如果是組合使用,就需要v­-model來配合value使用,v-model繫結一個陣列—如果繫結的是字串,則會轉化為true。false,與所有繫結的核取方塊的checked屬性相對應

下拉框:

  • 如果是單選,所繫結的value值初始化可以為陣列,也可以為字串,有value直接優先匹配一個value值,沒有value就匹配一個text值
  • 如果是多選,就需要v­-model來配合value使用,v­-model繫結一個陣列,與核取方塊類似
  • v-­model一定是繫結在select標籤上

總結一下:
如果是單選,初始化最好給定字串,因為v­model此時繫結的是靜態字串或者布林值如果是多選,初始化最好給定一個陣列

6.2 繫結值

  • 單選按鈕
    只需要用v­-bind給單個單選框繫結一個value值,此時,v­-model繫結的就是他的value值

  • 核取方塊

  • 下拉框
    在select標籤上繫結value值對option並沒有影響

6.3 修飾符

  • lazy
    v-model預設是在input輸入時實時同步輸入框的資料,而lazy修飾符,可以使其在失去焦點或者敲Enter鍵之後在更新
  • number
    將輸入 的字串轉化為number型別
  • trim
    trim自動過濾輸入過程中收尾輸入的空格

七、 可複用性的元件詳解

7.1 使用元件的原因

  • 作用:提高程式碼的複用性

7.2 元件的使用方法

1. 全域性註冊
Vue.component('my-component',{
template:'<div>我是元件的內容</div>'
})
優點:所有的vue例項都可以用
缺點:許可權太大,容錯率降低
2. 區域性註冊
var app = new Vue({
  el:'#app',
  components:{
    'my-component':{
      template: '<div>我是元件的內容</div>'
    }
  }
})
3. vue元件的模板在某些情況下會受到html標籤的限制,比如 <table> 中只能還有 <tr> , <td> 這些元素,所以直接在table中使用元件是無效的,此時可以使用is屬性來掛載元件
<table>
  <tbody is="my-component"></tbody>
</table>

7.3 元件使用的奇淫技巧

  • 推薦使用小寫字母加­-進行命名(必須) child, my-­componnet命名元件
  • template中的內容必須被一個DOM元素包括 ,也可以巢狀
  • 在元件的定義中,除了template之外的其他選項---data,computed,methods
  • data必須是一個方法

7.4 使用props傳遞資料 父親向兒子傳遞資料

  • 在元件中使用props來從父親元件接收引數,注意,在props中定義的屬性,都可以在元件中直接使用
  • props來自父級,而元件中data return的資料就是元件自己的資料,兩種情況作用域就是元件本身,可以在template,computed,methods中直接使用
  • props的值有兩種,一種是字串陣列,一種是物件
  • 可以使用v-­bind動態繫結父元件來的內容

7.5 單向資料流

  • 解釋 : 通過 props 傳遞資料 是單向的了, 也就是父元件資料變化時會傳遞給子元件,但是反過來不行。
  • 目的 :是儘可能將父子元件解稿,避免子元件無意中修改了父元件的狀態。
  • 應用場景: 業務中會經常遇到兩種需要改變 props 的情況

一種是父元件傳遞初始值進來,子元件將它作為初始值儲存起來,在自己的作用域下可以隨意使用和修改。這種情況可以在元件 data 內再宣告一個資料,引用父元件的 props
步驟一:註冊元件
步驟二:將父元件的資料傳遞進來,並在子元件中用props接收
步驟三:將傳遞進來的資料通過初始值儲存起來

<div id="app">
<my-comp init-count="666"></my-comp>
</div>
<script>
var app = new Vue({
  el:'#app',
  components:{
    'my-comp':{
      props:['init-count'],
      template:'<div>{{count}}</div>',
      data:function () {
        return{
        count:this.initCount
        }
      }
    }
  }
})
</script>

另一種情況就是 prop 作為需要被轉變的原始值傳入。這種情況用計算屬性就可以了
步驟一:註冊元件
步驟二:將父元件的資料傳遞進來,並在子元件中用props接收
步驟三:將傳遞進來的資料通過計算屬性進行重新計算

<body>
    <div id="data">
        <input type="text" v-model="width">
        <my-conponent :width="width"></my-conponent>
    </div>
    
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
      var app = new Vue({
          el:'#data',
          data:{
              width:''
          },
          components:{
              'my-conponent':{
                props:['width'],
                template:'<div :style="style"></div>',
                computed:{
                  style:function(){
                      return{
                          width:this.width+'px',
                          background:'red',
                          height:'30px'
                      }
                  }
              }
              }
          }
      })
    </script>
</body>

7.6 資料驗證

  • @ vue元件中camelCased (駝峰式) 命名與 kebab­case(短橫
    線命名)

@ 在html中, myMessagemymessage 是一致的,,因此在元件中的html
中使用必須使用kebab-­case(短橫線)命名方式。在html中不允許使用駝
峰!!!!!!
@ 在元件中, 父元件給子元件傳遞資料必須用短橫線。在template中,必須使用駝峰命名方式,若為短橫線的命名方式。則會直接保錯。
@ 在元件的data中,用this.XXX引用時,只能是駝峰命名方式。若為短橫線
的命名方式,則會報錯。

驗證的 type 型別可以是:
  • String
  • Number
  • Boolean
  • Object
  • Array
  • Function
Vue.component ( ’ my-compopent ’, {
  props : {
  //必須是數字型別
    propA : Number ,
    //必須是字串或數字型別
    propB : [String , Number] ,
    //布林值,如果沒有定義,預設值就是 true
    propC: {
      type : Boolean ,
      default : true
    },
    //數字,而且是必傳
    propD: {
      type: Number ,
      required : true
    },
    //如果是陣列或物件,預設值必須是一個函式來返回
    propE: {
      type : Array ,
      default : function () {
      return [] ;
    }
  },
    //自定義一個驗證函式
    propF: {
      validator : function (value) {
      return value > 10;
    }
  }
}
});

7.7 元件通訊

元件關係可分為父子元件通訊、兄弟元件通訊、跨級元件通訊

7.7.1 自定義事件—子元件給父元件傳遞資料

使用v-­on 除了監昕 DOM 事件外,還可以用於元件之間的自定義事件。
JavaScript 的設計模式 一一觀察者模式, dispatchEventaddEventListener這兩個方法。 Vue 元件也有與之類似的一套模式,子元件用$emit()觸發事件 ,父元件用$on()監聽子元件的事件
直接來程式碼

  • 第一步:自定義事件
  • 第二步: 在子元件中用$emit觸發事件,第一個引數是事件名,後邊的引數是要傳遞的資料
  • 第三步:在自定義事件中用一個引數來接受
<body>
    <div id="app">
        <p>您好,您現在的銀行餘額是{{total}}元</p>
        <btn-compnent @change="handleTotal"></btn-compnent>
        <!-- <button-component @change="money"></button-component> -->
    </div>
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
        
        var app = new Vue({
            el: '#app',
            data: {
                total: 0
            },
            components: {
                'btn-compnent': {
                    template: '<div>\
                <button @click="handleincrease">+10000</button> \
                <button @click="handlereduce">-10000</button>\
                </div>',
                    data: function () {
                        return {
                            count: 0
                        }
                    },
                    methods: {
                        handleincrease: function () {
                            this.count = this.count + 10000;
                            this.$emit('change', this.count);
                        },
                        handlereduce: function () {
                            this.count = this.count - 10000;
                            this.$emit('change', this.count);
                        }
                    }
                }
            },
            methods: {
                handleTotal: function (total) {
                    this.total = total;
                }
            }
        })
    </script>
</body>

7.7.2 在元件中使用v-­model

$emit的程式碼,這行程式碼實際上會觸發一個 input事件, ‘input’後的引數就是傳遞給v-­model繫結的屬性的值

v-­model 其實是一個語法糖,這背後其實做了兩個操作:

  • v­-bind 繫結一個 value 屬性
  • v­-on 指令給當前元素繫結 input 事件

要使用v-­model,要做到:

  • 接收一個 value 屬性。
  • 在有新的 value 時觸發 input 事件
<body>
    <div id="app">
        <p>您好,您現在的銀行餘額是{{total}}元</p>
        <btn-compnent v-model="total"></btn-compnent>
    </div>
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
        //關於
        var app = new Vue({
            el: '#app',
            data: {
                total: 0
            },
            components: {
                'btn-compnent': {
                    template: '<div>\
                <button @click="handleincrease">+1</button> \
                <button @click="handlereduce">-1</button>\
                </div>',
                    data: function () {
                        return {
                            count: 0
                        }
                    },
                    methods: {
                        handleincrease: function () {
                            this.count++;
----------------------注意觀察.這一行,emit的是input事件----------------
                            this.$emit('input', this.count);
                        },
                        handlereduce: function () {
                            this.count--;
                            this.$emit('input', this.count);
                        }
                    }
                }
            },
            methods: {
                /* handleTotal:function (total) {
                this.total = total;
                }*/
            }
        })
    </script>
</body>

7.7.3 非父元件之間的通訊

官網描述:

11945856-08d2785ddb701e9b.jpg
image

    <div id="app">
        <my-acomponent></my-acomponent>
        <my-bcomponent></my-bcomponent>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js">
    </script>
    <script>
        Vue.component('my-acomponent', {
            template: '<div><button @click="handle">點選我向B元件傳遞資料</button></div>',
            data: function () {
                return {
                    aaa: '我是來自A元件的內容'
                }
            },
            methods: {
                handle: function () {
                    this.$root.bus.$emit('lala', this.aaa);
                }
            }
        })
        Vue.component('my-bcomponent', {
            template: '<div></div>',
            created: function () {
                //A元件在例項建立的時候就監聽事件---lala事件
                this.$root.bus.$on('lala', function (value) {
                    alert(value)
                });
            }
        })
    </script>

父鏈:this.$parent

Vue.component('child-component', {
            template: '<button @click="setFatherData">通過點選我修改父親的資料</button>',
            methods: {
                setFatherData: function () {
                    this.$parent.msg = '資料已經修改了'
                }
            }
        })

子鏈:this.$refs

提供了為子元件提供索引的方法,用特殊的屬性ref為其增加一個索引

var app = new Vue({
            el: '#app',
            data: {
                //bus中介
                bus: new Vue(),
                msg: '資料還未修改',
                formchild: '還未拿到'
            },
            methods: {
                getChildData: function () {
                    //用來拿子元件中的內容 ---- $refs
                    this.formchild = this.$refs.c.msg;
                }
            }
        })

7.8使用slot分發內容

7.8.1 什麼是slot(插槽)

為了讓元件可以組合,我們需要一種方式來混合父元件的內容與子元件自己的模板。這個過程被稱為 內容分發.Vue.js 實現了一個內容分發 API,使用特殊的 ‘slot’ 元素作為原始內容的插槽。

7.8.2 編譯的作用域

在深入內容分發 API 之前,我們先明確內容在哪個作用域裡編譯。假定模板為:

<child-component>
{{ message }}
</child-component>

message 應該繫結到父元件的資料,還是繫結到子元件的資料?答案是父元件。元件作用域簡單地說是:

  • 父元件模板的內容在父元件作用域內編譯
  • 子元件模板的內容在子元件作用域內編譯

7.8.3 插槽的用法

  • 父元件的內容與子元件相混合,從而彌補了檢視的不足
  • 混合父元件的內容與子元件自己的模板
    單個插槽:
<div id="app">
        <my-component>
            <p>我是父元件的內容</p>
        </my-component>
    </div>
    Vue.component('my-component',{ template:'
    <div>\
        <slot>\ 如果父元件沒有插入內容,我就作為預設出現\
        </slot>\
    </div>' })

具名插槽:

   具名插槽:
    <name-component>
        <h3 slot="header">我是標題</h3>
        <p>我是正文內容</p>
        <p>正文內容有兩段</p>
        <p slot="footer">我是底部資訊</p>
    </name-component>
    Vue.component('name-component',{ template:'
    <div>\
        <div class="header">\n' + '
            <slot name="header">\n' + ' \n' + ' </slot>\n' + '
        </div>\n' + '
        <div class="contatiner">\n' + '
            <slot>\n' + ' \n' + ' </slot>\n' + '
        </div>\n' + '
        <div class="footer">\n' + '
            <slot name="footer">\n' + '\n' + ' </slot> \n' + '
        </div>'+ ' </div>' })

7.8.4 作用域插槽

作用域插槽是一種特殊的slot,使用一個可以複用的模板來替換已經渲染的元素——從子元件獲取資料
template模板是不會被渲染的

  Vue.component('my-component',{ template:'
    <div>\
        <slot text="我是來自子元件的資料" ss="fdjkfjlsd" name="abc">\
        </slot>\
    </div>' })

7.8.5 訪問slot

通過this.$slots.(NAME)

mounted:function () {
        //訪問插槽
        var header = this.$slots.header;
        var text = header[0].elm.innerText;
        var html = header[0].elm.innerHTML;
        console.log(header)
        console.log(text)
        console.log(html)
        }

7.9 元件高階用法–動態元件

VUE給我們提供 了一個元素叫component

  • 作用是: 用來動態的掛載不同的元件
  • 實現:使用is特性來進行實現的

直接甩程式碼:

<body>
    <div id="data">
            <component :is ="show"></component>
            <button @click="msg('a')">第一句</button>
            <button @click="msg('b')">第二句</button>
            <button @click="msg('c')">第三句</button>
            <button @click="msg('d')">第四句</button>
    </div>
    <script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script>
        Vue.component('msga', {
                template: '<div>鋤禾日當午</div>',
                data:function(){
                    return{                                           
                    }
                }
            })
            Vue.component('msgb', {
                template: '<div>汗滴禾下土</div>',
                data:function(){
                    return{                                           
                    }
                }
            })
            Vue.component('msgc', {
                template: '<div>誰知盤中餐</div>',
                data:function(){
                    return{                                           
                    }
                }
            })
            Vue.component('msgd', {
                template: '<div>粒粒堅辛苦</div>',
                data:function(){
                    return{                                           
                    }
                }
            })
      var app = new Vue({
          el:'#data',
          data:{
              show:'msga'
          },
          methods:{
              msg:function(value){
                  this.show = 'msg' + value
              }
          }
      })
    </script>
</body>

八、 自定義指令

自定義指令的基本用法

和元件類似分全域性註冊和區域性註冊,區別就是把component換成了derective

鉤子函式

指令定義函式提供了幾個鉤子函式(可選):

  • bind: 只呼叫一次,指令第一次繫結到元素時呼叫,用這個鉤子函式可以定義一個在繫結時執行一次的初始化動作。
  • inserted: 被繫結元素插入父節點時呼叫(父節點存在即可呼叫,不必存在於 document中)。
  • update: 被繫結元素所在的模板更新時呼叫,而不論繫結值是否變化。通過比較更新前後的繫結值,可以忽略不必要的模板更新(詳細的鉤子函式引數見下)。
  • componentUpdated: 被繫結元素所在模板完成一次更新週期時呼叫。
  • unbind: 只呼叫一次, 指令與元素解綁時呼叫。

鉤子函式的引數有:

  • el: 指令所繫結的元素,可以用來直接操作 DOM 。

  • binding: 一個物件,包含以下屬性:

    • name: 指令名,不包括 v-­ 字首。
    • value: 指令的繫結值, 例如: v­-my­-directive=”1 + 1”, value 的值是2。
    • oldValue: 指令繫結的前一個值,僅在 update 和componentUpdated 鉤子中可用。無論值是否改變都可用。
    • expression: 繫結值的字串形式。 例如 v­-my-­directive=”1 + 1” , expression 的值是“1 + 1”。
    • arg: 傳給指令的引數。例如 v-­my-­directive:foo, arg 的值是 “foo”。
    • modifiers: 一個包含修飾符的物件。 例如: v­-my-­directive.foo.bar, 修飾符物件,,,modifiers 的值是 { foo: true, bar: true }。
  • vnode: Vue 編譯生成的虛擬節點。

  • oldVnode: 上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用。

自定義的指令
<div v-cuihua:.a.b.c="obq"></div>

九 、render函式

9.1 render函式初步瞭解

template下只允許有一個子節點

 <template id="hdom">
        <div>
            <h1 v-if="level==1">
                <slot></slot>
            </h1>
            <h2 v-if="level==2">
                <slot></slot>
            </h2>
            <h3 v-if="level==3">
                <slot></slot>
            </h3>
        </div>
    </template>
    <script>
        //是用vue元件定義
        // Vue.component('child',{
        // props:['level'],
        // template:'#hdom'
        // })
        //使用render函式進行定義元件
        Vue.component('child', {
            render: function (createElement) {
                return createElement('h' + this.level,
                    this.$slots.default);
            },
            props: ['level']
        })

9.2 render函式的第一個引數

在render函式的方法中,引數必須是createElement,createElement的型別是function,render函式的第一個引數可以是 String | Object | Function

Vue.component('child', {
            // ----第一個引數必選
            //String--html標籤
            //Object---一個含有資料選項的物件
            //FUnction---方法返回含有資料選項的物件
            render: function (createElement) {
                alert(typeof createElement)
                // return createElement('h1')
                // return createElement({
                // template:'<div>鋤禾日當午</div>'
                // })
                var domFun = function () {
                    return {
                        template: '<div>鋤禾日當午</div>'
                    }
                }
                return createElement(domFun());
            }
        });

9.3 render函式的第二個引數

Vue.component('child', {
            // ----第二個引數可選,第二個引數是資料物件----只能是Object
            render: function (createElement) {
                return createElement({
                    template: '<div>我是龍的傳人</div>'
                }, {
                        'class': {
                            foo: true,
                            baz: false
                        },
                        style: {
                            color: 'red',
                            fontSize: '16px'
                        },
                        //正常的html特性
                        attrs: {
                            id: 'foo',
                            src: 'http://baidu.com'
                        },
                        //用來寫原生的Dom屬性
                        domProps: {
                            innerHTML: '<span style="color:blue;font-size: 18px">我是藍色</span>'
                        }
                    })
            }
        });

9.3 render函式的第三個引數

第三個引數也是可選===String | Array—作為我們構建函式的子節點來使用的

Vue.component('child', {
            // ----第三個引數是可選的,可以是 String | Array---代表子節點
            render: function (createElement) {
                return createElement('div', [
                    createElement('h1', '我是h1標題'),
                    createElement('h6', '我是h6標題')
                ])
            }
        });

9.4 this.$slots在render函式中的應用

第三個 引數存的就是VNODE
createElement(‘header’,header), 返回的就是VNODE
var header = this.$slots.header; //–這返回的內容就是含有=VNODE的陣列

Vue.component('my-component', {
            render: function (createElement) {
                debugger
                var header = this.$slots.header; //--這返回的內容就是含有=V
                NODE的陣列
                var main = this.$slots.default;
                var footer = this.$slots.footer;
                return createElement('div', [
                    createElement('header', header),
                    createElement('main', main),
                    createElement('footer', footer)
                ]);
            }
        })

9.5 在render函式中使用props傳遞資料

    <div id="app">
        <button @click="switchShow">點選切換美女</button>  {{show}}
        <my-component :show="show">

        </my-component>
    </div>
    <script>
            Vue.component('my-component', {
                props: ['show'],
                render: function (createElement) {
                    var imgsrc;
                    if (this.show) {
                        imgsrc = 'img/001.jpg'
                    } else {
                        imgsrc = 'img/002.jpg'
                    }
                    return createElement('img', {
                        attrs: {
                            src: imgsrc
                        },
                        style: {
                            width: '600px',
                            height: '400px'
                        }
                    });
                }
            })
    </script>

9.6 v-­model在render函式中的使用

    <!--<my-component :name="name" @input="showName"></my-componen
t>-->
    <my-component :name="name" v-model="name"></my-component>
    <br> {{name}}

    <script>
        Vue.component('my-component', {
            render: function (createElement) {
                var self = this;//指的就是當前的VUE例項
                return createElement('input', {
                    domProps: {
                        domProps: {
                            value: self.name
                        },

                        value: self.name
                    },
                    on: {
                        input: function (event) {
                            debugger
                            var a = this;
                            //此處的this指的是什麼?指的就是window
                            self.$emit('input', event.target.value)
                        }
                    }
                })
            },
            props: ['name']
        })
    </script>

9.7 作用域插槽在render函式中的使用

Vue.component('my-component', {
                render: function (createElement) {
                    return createElement('div', this.$scopedSlots.default({
                        text: '我是子元件傳遞過來的資料',
                        msg: 'scopetext'
                    }))
                }
            })

9.8 函式化元件的應用

使用context的轉變

// this.text----context.props.text
//this.$slots.default-----context.children

functional: true,表示該元件無狀態無例項

十、 使用vue-­cli腳手架一鍵搭建工程

首先電腦上要安裝最新版的nodeJS.官網下載,安裝完之後安裝淘寶npm映象

npm install -g cnpm --registry=https://registry.npm.taobao.org

五部走:

  • 全域性安裝vue-­cli
npm install -g vue-cli
  • 進入目錄–初始化專案
vue init webpack my-project
  • 進入專案
cd my-project
  • 安裝依賴
npm install
  • 啟動專案
npm run dev
目錄結構的分析
├── build // 專案構建(webpack)相關程式碼 記憶:(夠賤) 9個
│ ├── build.js // 生產環境構建程式碼
│ ├── check­versions.js // 檢查node&npm等版本
│ ├── dev­client.js // 熱載入相關
│ ├── dev­server.js // 構建本地伺服器
│ ├── utils.js // 構建配置公用工具
│ ├── vue­loader.conf.js // vue載入器
│ ├── webpack.base.conf.js // webpack基礎環境配置
│ ├── webpack.dev.conf.js // webpack開發環境配置
│ └── webpack.prod.conf.js // webpack生產環境配置
二、
├── config// 專案開發環境配置相關程式碼 記憶: (環配) 3個
│ ├── dev.env.js // 開發環境變數(看詞明意)
│ ├── index.js //專案一些配置變數
│ └── prod.env.js // 生產環境變數
三、
├──node_modules// 專案依賴的模組 記憶: (依賴) *個
四、
├── src// 原始碼目錄 5
1
│ ├── assets// 資源目錄
│ │ └── logo.png
2
│ ├── components// vue公共元件
│ │ └── Hello.vue
3
│ ├──router// 前端路由
│ │ └── index.js// 路由配置檔案
4
│ ├── App.vue// 頁面入口檔案(根元件)
5
│ └── main.js// 程式入口檔案(入口js檔案)
五、
└── static// 靜態檔案,比如一些圖片,json資料等
│ ├── .gitkeep
剩餘、
├── .babelrc// ES6語法編譯配置
├── .editorconfig// 定義程式碼格式
├── .gitignore// git上傳需要忽略的檔案格式
├── index.html// 入口頁面
├── package.json// 專案基本資訊
├── README.md// 專案說明

十一、 vue-­router路由和前端狀態管理

11.1 vue­-router路由基本載入

簡單四步走

  1. 安裝
npm install --save vue-router
  1. 引用
import router from 'vue-router'
Vue.use(router)
  1. 配置路由檔案,並在vue例項中注入
var rt = new router({
  routes:[{
    path:'/',//指定要跳轉的路徑
    component:HelloWorld//指定要跳轉的元件
  }]
})
new Vue({
  el: '#app',
  router:router,
  components: { App },
  template: '<App/>'
})
  1. 確定檢視載入的位置
<router-view></router-view>

11.2 vue-­router路由的跳轉

<router-link to="/"></router-link>
<template>
  <ul>
    <li>
      <router-link to="/helloworld">HELLO WORLD</router-link>
    </li>
    <li>
      <router-link to="/helloearth">HELLO EARTH</router-link>
    </li>
  </ul>
</template>

11.3 vue-­router路由引數的傳遞

  • 必須在路由內加入路由的name
  • 必須在path後加/: +傳遞的引數
  1. 傳遞引數和接收引數看下邊程式碼
<router-link
  :to="{name: helloearth,params:{msg: 只有一個地球}}">
  HELLO WORLD
</router-link>
讀取引數: $route.params.XXX
方式:===/helloworld/你好世界


<router-link
  :to="{path: '/helloearth',query:{msg: 只有一個地球}}">
  HELLO WORLD
</router-link>
方式:===/helloworld?name=XX&count=xxx
函式模式
你可以建立一個函式返回 props。這樣你便可以將引數轉換成另一種型別,將靜態值與基於路由的值結合等等。
const router = new VueRouter({
  routes: [
    { path: '/search', component: SearchUser, props: (route) => ({
      query: route.query.q }) }
  ]
})

11.4.1 Axios之get請求詳解

axios的簡介:

axios 是一個基於Promise 用於瀏覽器和 nodejs 的 HTTP 客戶端,它本身具有以下特徵:

  • 從瀏覽器中建立 XMLHttpRequest
  • 從 node.js 發出 http 請求
  • 支援 Promise API
  • 攔截請求和響應
  • 轉換請求和響應資料
  • 取消請求
  • 自動轉換JSON資料
  • 客戶端支援防止 CSRF/XSRF
  1. 安裝
npm install axios
  1. 引入載入
import axios from 'axios'
  1. 將axios全域性掛載到VUE原型上
Vue.prototype.$http = axios;
  1. 發出請求 以cnode社群API為例子
// 為給定 ID 的 user 建立請求
使用傳統的function
getData(){
  var self = this;
  this.$http.get('https://cnodejs.org/api/v1/topics')
  .then(function (res) {
//此處的this指向的不是當前vue例項
    self.items = res.data.data
    console.log(res.data.data)
  })
  .catch(function (err) {
    console.log(err)
  })
}
// 可選地,上面的請求可以這樣做
兩種傳遞引數的形式
axios.get('/user', {
  params: {
    ID: 12345
  }
})
axios.get('/user', {
  ID: 12345
})
---------------------------------
axios.get('https://cnodejs.org/api/v1/topics?page=1&limit=15')

11.4.2 Axios之post請求詳解

// 為給定 ID 的 user 建立請求
使用傳統的function
getData(){
  var self = this;
  this.$http.post(url,{
    page:1,
    limit:10
  })
  .then(function (res) {
//此處的this指向的不是當前vue例項
    self.items = res.data.data
    console.log(res.data.data)
  })
  .catch(function (err) {
    console.log(err)
  })
}

POST傳遞資料有兩種格式:

  • form-­data ?page=1&limit=48
  • x­-www-­form­-urlencoded { page: 1,limit: 10 }

在axios中,post請求接收的引數必須是form­data
qs外掛—­qs.stringify

11.5 Vuex之store

用來管理狀態,共享資料,在各個元件之間管理外部狀態如何使用?

  • 第一步:引入vuex,並通過use方法使用它
  • 第二步: 建立狀態倉庫
  • 第三步:通過this.$sore.state.XXX直接拿到需要的資料
//建立狀態倉庫,注意Store,state不能改
var store = new Vuex.Store({
  state:{
    XXX:xxx
  }
})
//直接通過this.$sore.state.XXX拿到全域性狀態

11.6 Vuex的相關操作

vuex狀態管理的流程
view———­>actions———–>mutations—–>state————­>view

除了能夠獲取狀態如何改變狀態呢?

//建立狀態倉庫,注意Store,state不能改
var store = new Vuex.Store({
  state:{
    XXX:xxx
  },
  mutations:{
  }
})
this.$store.commit(XXX);
// 此處的XXX是你在mucations中定義的方法名
var store = new Vuex.Store({
  state:{
    XXX:xxx
  },
  mucations:{
    a:function(state){
    }
  },
  actions:{
    b:function(context){
      context.commit('a');
    }
  }
})
// 如何呼叫
this.$store.dispatch(XXX);
getters:{
}
this.$store.getters.getCount

注意:actions提交的是mutation,而不是直接變更狀態
actions可以包含非同步操作,但是mutation只能包含同步操作

The early bird catches the worm

相關文章