Vue.js+vue-element搭建屬於本身的後臺管理模板:更深刻了解Vue.js(三)

前言

上一章咱們介紹了關於Vue實例中一些基本用法,可是組件、自定義指令、Render函數這些放到了本章來介紹,緣由是它們要比前面講的要難一些,組件是Vue.js最核心的功能,學習使用組件也是必不可少的知識點。html

Vue實例屬性和方法

在咱們學習組件以前,更深刻的瞭解下Vue實例,它除了data數據對象屬性外,Vue實例還暴露了一些有用的實例屬性和方法,它們都有前綴$,以便與用戶定義的屬性區分開來,詳細適用方法能夠查閱官方API文檔。vue

實例屬性:node

  • vm.$data:類型Object,Vue 實例觀察的數據對象。Vue 實例代理了對其 data 對象屬性的訪問。
  • vm.$props:類型Object,當前組件接收到的 props 對象。Vue 實例代理了對其 props 對象屬性的訪問。
  • vm.$el:類型:Element,只讀,Vue 實例使用的根 DOM 元素。
  • vm.$options:類型Object,只讀,用於當前 Vue 實例的初始化選項。須要在選項中包含自定義屬性時會有用處
  • vm.$parent:類型:Vue instance,只讀,父實例,若是當前實例有的話。
  •  vm.$root:類型:Vue instance,只讀,當前實例的直接子組件。須要注意 $children 並不保證順序,也不是響應式的。若是你發現本身正在嘗試使用 $children 來進行數據綁定,考慮使用一個數組配合 v-for 來生成子組件,而且使用 Array 做爲真正的來源。
  • vm.$slots:類型:{ [name: string]: ?Array<VNode> },只讀,用來訪問被插槽分發的內容。每一個具名插槽 有其相應的屬性 (例如:v-slot:foo 中的內容將會在 vm.$slots.foo 中被找到)。default 屬性包括了全部沒有被包含在具名插槽中的節點,或 v-slot:default 的內容。
  • vm.$scopedSlots:類型:{ [name: string]: props => Array<VNode> | undefined },只讀,用來訪問做用域插槽。對於包括 默認 slot 在內的每個插槽,該對象都包含一個返回相應 VNode 的函數。vm.$scopedSlots 在使用渲染函數開發一個組件時特別有用。
  • vm.$refs:類型:Object,只讀,一個對象,持有註冊過 ref 特性 的全部 DOM 元素和組件實例。
  • vm.$isServer:類型:boolean,只讀,當前 Vue 實例是否運行於服務器。
  • vm.$attrs:類型:{ [key: string]: string },只讀,包含了父做用域中不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這裏會包含全部父做用域的綁定 (class 和 style 除外),而且能夠經過 v-bind="$attrs" 傳入內部組件——在建立高級別的組件時很是有用。
  • vm.$listeners:類型:{ [key: string]: Function | Array<Function> },只讀,包含了父做用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它能夠經過 v-on="$listeners" 傳入內部組件——在建立更高層次的組件時很是有用。

實例方法 / 數據:webpack

  • vm.$watch( expOrFn, callback, [options] ):返回值:{Function} unwatch,用法:觀察 Vue 實例變化的一個表達式或計算屬性函數。回調函數獲得的參數爲新值和舊值。表達式只接受監督的鍵路徑。對於更復雜的表達式,用一個函數取代。
  • vm.$set( target, propertyName/index, value ):返回值:設置的值。用法:這是全局 Vue.set 的別名。
  • vm.$delete( target, propertyName/index ): 這是全局 Vue.delete 的別名。

實例方法 / 事件:web

  • vm.$on( event, callback ) :監聽當前實例上的自定義事件。事件能夠由vm.$emit觸發。回調函數會接收全部傳入事件觸發函數的額外參數。
  • vm.$once( event, callback ):監聽一個自定義事件,可是隻觸發一次,在第一次觸發以後移除監聽器。
  • vm.$off( [event, callback] ):移除自定義事件監聽器。
  • vm.$emit( eventName, […args] ):觸發當前實例上的事件。附加參數都會傳給監聽器回調。

實例方法 / 生命週期:spring

  • vm.$mount( [elementOrSelector] ):返回值:vm - 實例自身,若是 Vue 實例在實例化時沒有收到 el 選項,則它處於「未掛載」狀態,沒有關聯的 DOM 元素。可使用 vm.$mount() 手動地掛載一個未掛載的實例。
  • vm.$forceUpdate():迫使 Vue 實例從新渲染。注意它僅僅影響實例自己和插入插槽內容的子組件,而不是全部子組件。
  • vm.$nextTick( [callback] ):將回調延遲到下次 DOM 更新循環以後執行。在修改數據以後當即使用它,而後等待 DOM 更新。它跟全局方法 Vue.nextTick 同樣,不一樣的是回調的 this 自動綁定到調用它的實例上。
  • vm.$destroy():徹底銷燬一個實例。清理它與其它實例的鏈接,解綁它的所有指令及事件監聽器。

 

組件

組件是Vue.js中最強大的功能之一,核心目標是爲了可重用性高,減小重複性開發。組件須要註冊纔可使用,註冊有全局註冊和局部註冊兩種方式,全局註冊的組件能夠在任何Vue實例上均可以使用。Vue實例中使用compoents選項來註冊局部組件,局部組件只能在當前實例中使用,組件中也可使用compoents選項來註冊子組件,使組件能夠嵌套使用。vuex

 

全局註冊,代碼示例以下:express

<div id="app">
  <my-component></my-component>
</div>
<script>
Vue.component('my-component', {
  template: '<div>這裏是組件內容</div>'
})

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

渲染後的結果是:數組

<div id="app">
  <div>這裏是組件內容</div>
</div>

 

局部註冊,代碼示例以下:服務器

<div id="app">
  <my-component></my-component>
</div>
<script>
var app = new Vue({
  el: '#app',
  components: {
    'my-component': {template:'<div>這裏是組件內容</div>'}
  }
})
</script>

組件中除了template選項外,還能夠像Vue實例那樣使用其餘選項,好比data、methods、computed等,data選項必須是函數,必須return返回纔有效。

代碼實例以下:

<div id="app">
  <my-component></my-component>
</div>
<script>
Vue.component('my-component', {
  template: '<div>這裏是組件內容</div>',
  data: function(){
    return {
      message: '組件內容'  //組件內部定義的數據
    }
  }
})

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

prop傳遞數據:

Vue實例或父組件中調用子組件時,一般須要向子組件傳遞數據,這個過程須要經過prop來實現,組件中提供了props選項來接收參數,props的值分兩種,一種是字符串數組,另外一種是對象,使用對象方式實際項目中最爲常見,代碼示例以下:

<div id="app">
  <my-component message="來自父組件的數據"></my-component>
</div>
<script>
Vue.component('my-component', {
  props: ['message'],
  template: '<div>{{ message }}</div>'
})

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

一般父組件中傳遞的數據並非寫死的,而是來自父級的動態數據,這時可使用指令v-bind來動態綁定prop的值,當父組件的數據變化時也會傳遞給子組件,上面例子中props的值使用的是字符串數組方式,下面咱們使用另外一種對象方式接收,代碼實例以下:

<div id="app">
  <input type="test" v-model="msg">
  <my-component :message="msg"></my-component>
</div>
<script>
Vue.component('my-component', {
  props: {
    message: String
  },
  template: '<div>子組件中顯示:{{ message }}</div>'
})

var app = new Vue({
  el: '#app',
  data: {
    msg: ''
  }
})
</script>

數據驗證:
當props值爲對象時,定義參數類型type,包括String、Number、Boolean、Object、Array、Function,參數也能夠設置初始值default,定義是否必傳參數required:true,還有自定義驗證函數等,當prop驗證失敗時,在開發版本下會在控制檯拋出一條警告。
代碼實例以下:

<script>
  Vue.component('my-component', {
    props: {
      propA: Number,  //必須是數字類型
      propB: [String, Number],  //必須是字符串或數字類型
      propC: {  //布爾類型,若是未傳入,默認值爲true
        type: Boolean,
        default: true
      },
      propD: {  //數字類型,必傳參數
        type: Number,
        required: true
      },
      propE: {  //若是是數組或對象類型,默認值必須是一個函數來返回
        type: Array,
        default: function () {
          return [];
        }
      },
      propF: {  //自定義一個驗證函數
        validator: function () {
          return value > 10;
        }
      }
    }
  })
</script>

自定義事件:
上面咱們知道了父組件向子組件傳遞數據時使用prop來完成,這裏說明一下prop值屬於引用類型,當改變prop值會直接影響父組件,重複使用組件時直接改變prop值時就失去了複用的目的。那麼子組件中向父組件傳遞數據要怎麼處理呢,這裏咱們就用到了自定義事件,自定義事件首先要在父組件中經過v-on監聽一個事件,事件鉤子函數在父組件實例中建立,在子組件中經過this.$emit()來觸發這個自定義事件,$emit()方法的第一個參數是自定義事件的名稱,後面參數爲要傳遞的數據,後面參數能夠爲空或多個,代碼實例以下:

<div id="app">
  <p>總數:{{ total }}</p>
  <my-component @inccount="handleInc"></my-component>
</div>
<script>
  Vue.component('my-component', {
    template: '<div><button @click="handleIncrease">+1</button></div>',
    data: function(){
      return {
        counter: 0
      }
    },
    methods: {
      handleIncrease: function(){
        this.counter++;
        this.$emit('inccount', this.counter); //觸發父組件中自定義事件
      }
    },
  })
  var app = new Vue({
    el: '#app',
    data: {
      total: 0
    },
    methods: {
      handleInc: function (count){
        this.total = count;
      }
    }
  })
</script>

 

組件上使用v-model:
前面章節中咱們講過v-model是一個特殊的語法糖,實際它等同於input自定義事件,咱們這裏經過v-model來建立自定義的表單輸入組件,進行數據雙向綁定,代碼實例以下:

<div id="app">
  <p>總數:{{ total }}</p>
  <my-component v-model="total"></my-component>
</div>
<script>
  Vue.component('my-component', {
    props: ['value'],
    template: '<div><input :value="value" @input="updateValue"></div>',
    methods: {
      updateValue: function(){
        this.$emit('input', event.target.value);
      }
    },
  })
  var app = new Vue({
    el: '#app',
    data: {
      total: 0
    }
  })
</script>

非父子組件通訊:
在實際業務中,除了父子組件通訊外,還有不少非父子組件通訊的場景,好比兄弟組件和跨多級組件,Vue.js中提供了一個方法,建立一個空的Vue實例做爲中央事件總線(bus),也就是一箇中介,初始化Vue實例時,監聽這個中介事件來完成本身的業務邏輯。除了它Vue還提供了一個更好的解決方案 vuex狀態管理插件。

 

插槽

 Vue.js 實現了內容分發,使用slot元素做爲承載分發內容的出口,混合父組件內容與子組件的模板時使用。

單個Slot:
在子組件內使用特殊的<slot>元素就能夠開啓一個slot默認插槽,在父組件模板中調用子組件標籤內的全部內容將替換子組件的<slot>元素內的內容,代碼實例以下:

<div id="app">
  <my-component>
    <p>分發的內容</p>
    <p>更多分發的內容</p>
  </my-component>
</div>
<script>
  Vue.component('my-component', {
    template: '\
      <div>\
        <slot>\
          <p>若是父組件沒有插入內容,我將做爲默認出現</p>\
        </slot>\
      </div>'
  })
  var app = new Vue({
    el: '#app'
  })
</script>

渲染後的結果是:

<div id="app">
  <div>
    <p>分發的內容</p>
    <p>更多分發的內容</p>
  </div>
</div>

具名Slot:
子組件模板中有時咱們須要多個插槽,slot元素中指定name屬性,能夠分發多個內容,具名Slot能夠與單個Slot共存,自 2.6.0 起咱們能夠在一個 <template> 元素上使用 v-slot 指令,代碼實例以下:

<div id="app">
  <my-component>
    <h2 slot="header">標題</h2>
    <p>分發的內容</p>
    <p>更多分發的內容</p>
    <h5 slot="footer">底部信息</h5>
  </my-component>
  <!-- 自 2.6.0 起新推薦的語法 -->
  <my-component>
    <template v-slot:header>
      <h2>標題</h2>
    </template>
    <p>分發的內容</p>
    <p>更多分發的內容</p>
    <template v-slot:footer>
      <h5>底部信息</h5>
    </template>
  </my-component>
</div>
<script>
  Vue.component('my-component', {
    template: '\
    <div>\
      <div class="header">\
        <slot name="header"><slot>\
      </div>\
      <div class="main">\
        <slot><slot>\
      </div>\
      <div class="footer">\
        <slot name="footer"><slot>\
      </div>\
    </div>'
  })
  var app = new Vue({
    el: '#app'
  })
</script>

 

編譯做用域:
父級模板裏的全部內容都是在父級做用域中編譯的;子模板裏的全部內容都是在子做用域中編譯的。

做用域插槽:
做用域插槽是一種特殊的Slot,使用slot-scope特性能夠接收傳遞給插槽的 prop,自 2.6.0 起已廢棄的使用 slot-scope 特性語法,新推薦的語法在<slot>元素的一個特性綁定子組件內部數據,這個特性綁定稱爲插槽prop,在父組件中v-slot具名插槽帶一個值類定義咱們提供的插槽prop的名字,代碼實例以下:

<div id="app">
  <my-component :user="{firstName:'newfirst',lastName:'newlast'}">
    <!-- user名字能夠隨意定義 -->
    <template v-slot:default="user"> 
        {{user.lastName}}
    </template>
    <template v-slot:main="data">
        {{data.message}}
    </template>
  </my-component>
</div>
<script>
  Vue.component('my-component', {
    data() {
      return {
        message: '子組件內部消息'
      }
    },
    props: {
      user: {
        type: Object,
        default: function () {
          return {
            firstName: 'first',
            lastName: 'last'
          };
        }
      }
    },
    template: '\
    <div>\
      <div>\
        <slot :lastName="user.lastName">\
          {{user.firstName}}\
        </slot>\
      </div>\
      <div>\
        <slot name="main" :message="message">\
        </slot>\
      </div>\
    </div>'
  })
  var app = new Vue({
    el: '#app'
  })
</script>

 

自定義指令

咱們已經介紹過了許多Vue內置的指令,好比 v-if、 v-show 等,這些內置指令能知足咱們絕大部分業務需求,不過在須要一些特殊功能時,咱們仍然但願對DOM底層進行操做,這時咱們就要用到自定義指令來完成。

註冊自定義指令:
自定義指令的註冊方法也分全局註冊和局部註冊,跟組件註冊方式很像,代碼實例以下:

 

// 註冊一個全局自定義指令
Vue.directive('focus', {
  inserted: function (el) {
    el.focus()
  }
})

//在組件中註冊局部自定義指令
var app = new Vue({
  el: '#app',
  directives: {
    focus: {
      inserted: function (el) {
        el.focus()
      }
    }
  }
})

鉤子函數:
一個指令定義對象能夠提供以下幾個鉤子函數,每一個都是可選的。

  • bind:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。
  • inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。
  • update:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 (詳細的鉤子函數參數見下)。
  • componentUpdated:指令所在組件的 VNode 及其子 VNode 所有更新後調用。
  • unbind:只調用一次,指令與元素解綁時調用。

鉤子函數參數:
指令鉤子函數會被傳入如下參數:

  • el:指令所綁定的元素,能夠用來直接操做 DOM 。
  • binding:一個對象,包含如下屬性:
    • name:指令名,不包括 v- 前綴。
    • value:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值爲 2。
    • oldValue:指令綁定的前一個值,僅在 update 和 componentUpdated 鉤子中可用。不管值是否改變均可用。
    • expression:字符串形式的指令表達式。例如 v-my-directive="1 + 1" 中,表達式爲 "1 + 1"。
    • arg:傳給指令的參數,可選。例如 v-my-directive:foo 中,參數爲 "foo"。
    • modifiers:一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象爲 { foo: true, bar: true }。
  • vnode:Vue 編譯生成的虛擬節點。移步 VNode API 來了解更多詳情。
  • oldVnode:上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用。

下面是結合了以上參數的一個具體示例,代碼實例以下:

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})

new Vue({
  el: '#hook-arguments-example',
  data: {
    message: 'hello!'
  }
})

Render函數

什麼是Render函數,Vue.js2.x開始使用了Virtual Dom(虛擬DOM)來更新DOM節點,提高渲染性能,Vue.js編譯時會把template模板解析爲Virtual Dom,Vue.js也提供了Render函數選項,即渲染函數,使用 JavaScript 代替模板功能。組件的template基本上知足咱們業務需求,但有些場景中,使用Virtual Dom會更簡單。(這個咱們暫時用不到,若是想了解的朋友能夠去官方文檔中進一步學習)

 

目錄導航

參考資料

Vue.js

相關文章
相關標籤/搜索