kylinH5框架之項目組件理解

目錄

 

組件介紹

組件聲明結構

組件接口

script

dependency

template

style

狀態注入

接口聲明


組件介紹

Component 擴充自 Vue 的組件, 提供了 Vue 組件對等的輸入參數能力。在代碼書寫時提供類 class 的裝飾器 Decorator 風格。

import { Component, Watch } from '@ali/kylin-framework';

一個組件可以包含數據、JSX 渲染函數、模板、掛載元素、方法、生命週期等 Vue 的 options 選項的對等配置。

組件聲明結構

組件聲明包括以下幾部分, 分別使用 @Component 和 @Watch 兩種不同裝飾器進行包裝:

  • class 類聲明, 使用裝飾器 @Component
  • 類成員聲明, 不使用裝飾器。
  • 類成員方法聲明, 一般不裝飾器, 除非該方法需要 watch 另外一個已聲明的變量。

舉例子

<!-- Hello.vue -->
<template>
  <div>
    hello {{name}}
    <Child></Child>
  </div>
</template>
<style>
  /* put style here */
</style>
<component default="Child" src="./child.vue" />
<script>
  import { Component } from '@ali/kylin-framework';
  @Component
  class Hello {
    data = {
      name: 'world'
    }
  }
  export default Hello;
</script>

組件接口

跟 vue 基本一致,組件定義寫在 .vue 文件內,以下是一個簡單的例子:

<template>
  <div>
    <AButton @click="onClick">點擊</AButton>
  </div>
</template>
<style lang="less" rel="stylesheet/less">
    /* less */
</style>
<dependency component="{ AButton }" src="@alipay/antui-vue" lazy/>
<script type="text/javascript">
  import { Component } from '@ali/kylin-framework';
  @Component
  export default class IndexView {
    props = {}
    data = {c:666}
    get comput() { return this.data.c * 2 }
    onClick() {}
    mounted() {}
  }
</script>

上述例子中,<template><style><script>、<dependency>   4 個頂級標籤

其中 <template>、 <style> 與 vue 中定義一致。下文將對這 4 個標籤的具體作用分別進行闡述。

script

1.class 結構

定義一個 Component ,使用類 class 的裝飾器 Decorator 風格。

其中裝飾器有 @Component 和 @Watch 2 種,通過以下方式引入。

import { Component, Watch } from '@ali/kylin-framework';
@Component
export default class Hello {
}

2.方法類型

@Component

組件以 class 形式聲明,必須對該 class 進行裝飾器修飾。

在 class 內部,不需要被手動處理成員變量babel 插件在構建過程中自動進行處理。

而 成員函數 一般不需要裝飾器掛載,除非是使用 @Watch 的場景,其中 @Component 會處理的屬性如下表所示。

成員類型 名稱 功能
get/set property * 用以轉換成 Vue 的 computed 計算屬性,可以直接通過 this[varName] 調用
method 生命週期 生命週期方法,與 Vue 對等。
method * 普通成員方法, 用以轉換成 Vue 的 methods 方法列表。

分別舉例:

getter/setter屬性

@Component 
export default class Hello {
  get computName() {
    // to sth
  }
}

上述 getter 聲明,等價於如下 vue 配置

HelloOption = {
  computed: {
    computName: {
      get: computName() {
        // to sth
      }
    }
  }
}

同理,setter 也會被提取,如果同時存在 getter 和 setter 則會被一起提取。

生命週期函數

@Component 
export default class Hello {
  created() {}
  mounted() {}
}

上述 created 和 mounted 生命週期函數,會被提取爲數組。

TestOption = {
  created: [function created(){}],
  mounted: [function mounted(){}],
}

支持的生命週期方法名如下,beforeCreatecreatedbeforeMountmountedbeforeUpdateupdated、 beforeDestroydestroyed

Watch

該裝飾器的出現,只是因爲 watch 需要有以下幾個要素:

  • 被監聽的變量名
  • 監聽選項
  • 觸發函數

用法

完整的 @Watch 接口如下表所示。

function Watch( key: string [, option: Object = {} ] ): PropertyDecorator
參數名 類型 用途
key string 監聽的參數名,來自 computeddataprops三者之一。
option deep boolean 若監聽的是複雜對象,其內層數據變更是否觸發,默認爲 false
immediate boolean 立即以表達式的當前值觸發回調,默認爲 false

示例

  • 對於 @Watch 裝飾的成員函數,支持對成員函數配置多個變量的監聽,如下同時對 a 和 c 的變化進行了監聽,如果任何一個發生變化,會觸發 OnChangeA 成員方法。
  • 如下,OnChangeA 本質是成員方法,所以他也會和其他成員方法一起被提取到methods塊中,那麼必須保證沒有與其他方法重名。
  • 如果對Watch有額外配置項,請按 @Watch('a', {deep: false})的方法傳入。配置項請參考 watch配置項
@Component
class WTest {
  data = {
    a: {
      b: 2
    },
    c: 3
  }
  @Watch('c')
  @Watch('a', {deep: true}) 
  OnChangeA(newVal, oldVal) {
  }
}

注意: 以上對 data.a 的監聽,會轉換成如下形式,需要注意的是,如果沒開啓 deep: true 選項,當 data.a.b 發生變動的時候,不會觸發該 OnChangeA 監聽。

3.屬性類型

構建工具會自動對成員變量應用了 @Component.Property 裝飾器,不需要用戶手動填寫,

最終的合併策略取決於被裝飾的 成員變量 的標識符名稱,框架內置了以下幾種。如果不在下表中,會透傳至 VueComponent 的 options 對象中。

成員類型 名稱 功能
property props vue的props屬性
property data vue的data屬性,會被轉換成函數形式, 支持 this,請勿直接寫 data(){} 函數
property * 其他未知屬性,直接複製到 Vue 的 options 中的對應屬性上

props

@Component 
export default class Hello {
  props = {
    name: {
      type: String,
      default: 'haha'
    },
    num: Number
  }
}

上述 props 成員變量定義,會被直接轉換成到 options 中對應的 props。具體完整定義結構請參見 Vue 文檔 API-props

HelloOption = {
  props: {
    name: {
      type: String,
      default: 'haha'
    },
    num: Number
  }
}

data

@Component 
export default class Hello {
  props = {
    name: {
      type: Number,
      default: 1
    },
  }
  data = {
    hello: this.props.name + 2
  }
}

上述 data 成員變量定義,會被轉換成 data 函數形式,您無需手動編寫 data 函數。

TestOption = {
  props: {
    name: {
      type: Number,
      default: 1
    }, 
  },
  data: function data() {
    return {
      hello: this.props.name + 2
    }
  }
}

dependency

上述 <script> 定義中,沒有說明組件依賴的使用方式,在 .vue 文件中,推薦使用以下寫法來標記組件依賴,即 <dependency> 標籤,下面示例中即引用了 ./child.vue 組件。

<template>
  <child></child>
</template>
<dependency component="Child" src="./child.vue" />

標籤屬性

default 導入

針對 ES6 Module 的 default 導出或者 commonjs Module 對象的導出,可使用如下方式引入。

屬性 類型 默認值 備註
component string 必填 引入到 options.components 的標識符名。
src string 必填 組件來源,同require(src)。
lazy boolean false 是否對該組件啓用懶加載(當且僅當被 Vue 使用到時再進行 require 加載模塊)。
style string undefined 默認不啓用,如果設置了字符串,會根據 ${src}/${style} 的路徑來加載組件對應樣式文件。

如下示例:

<dependency component="name" src="source" lazy />

 

member 導入

針對 ES6 Module 的命名導出,可使用如下方式引入:

屬性 類型 默認值 備註
component string 必填 引入到 options.components 的多個命名標識符, 必須以花括號 {} 包括,否則會識別爲 default 引入
src string 必填 組件來源,同 require(src)。
lazy boolean false 是否對該組組件啓用懶加載(當且僅當被 Vue 使用到時再進行 require 加載模塊)。

如下示例:

<dependency component="{ List, ListItem, AButton }" src="@alipay/antui-vue" lazy />

默認對 @alipay/antui-vue 組件庫支持 babel-plugin-import 按需加載。

template

模板的內容結構與 vue 一致。

<template>
  <div>Hello World</div>
</template>

style

可以通過添加 scoped 屬性標記來使得該樣式只對當前組件生效。

<style lang="less" rel="stylesheet/less" scoped>
    /* less */
</style>

狀態注入

對於 Kylin 組件, 如果需要使用到 Store 中的屬性,使用計算屬性把 $store 對象中的屬性透傳出來是一種不推薦的寫法,如下所示:

@Component 
class Hello {
  // 通過計算屬性來關聯store中的狀態
  get hello() {
    return this.$store.state.hello
  }
}

推薦使用下面的 connect 機制來透傳 $store 數據:

接口聲明

@Component({
  mapStateToProps: Object|Array,
  mapActionsToMethods: Object|Array,
  mapMethods: Array|Boolean,
  mapEvents: Array
})
class Hello {
}

mapStateToProps

把 state 中的特定鍵值映射到當前組件的 props 中,其接收參數等價於 Vuex 提供的 mapState 輔助函數

有以下 3 種方式可實現上述功能:

函數方式

說明:把 $store.state 中名爲 bbb 的數據,映射到名爲 aaa 的 props 上。

{
  mapStateToProps: {
    aaa: (state, getters) => state.bbb
  }
}

字符串鍵值對方式

說明:把 $store.state 中名爲 bbb 的數據,映射到名爲 aaa 的 props 上。

{
  mapStateToProps: {
    aaa: 'bbb'
  }
}

字符串數組方式

說明

  • 把 $store.state 中名爲 aaa 的數據,映射到名爲 aaa 的 props 上。
  • 把 $store.state 中的名爲 bbb 的數據,映射到名爲 bbb 的props 上。
{
  mapStateToProps: ['aaa', 'bbb']
}

mapActionsToMethods

與 Vuex 中 mapActions 入參一致,支持使用對象方式(名稱映射)、數組方式(名稱)把在全局 $store 下配置的 actions 注入到當前組件的 methods 中。

@Component({
  mapActionsToMethods: ['a', 'b']
})
class IndexView {
  async doSomeAction() {
    const ret = await this.a(123);
    // 等價於調用
    // const ret = await this.$store.dispatch('a', 123);
  }
}

mapMethods

通過在父子組件之間加一層中間層組件的方式來具體實現 connect 機制。當父組件調用子組件中特定的 method 方法時,無法直接訪問子組件(實際訪問到的是中間層組件),需要通過以下配置實現訪問。

@Component({
  mapMethods: true
})
export default class Child {
  a() {}
}
<template>
  <div>
    this is parent
    <child ref="child"></child>
  </div>
</template>
<script>
  @Component
  export default class Parent {
    b() {
      // 此處可以訪問
      this.$refs.child.a();
    }
  }
</script>

 

吐槽:學這個麒麟框架真的像中了佐二助大招雷遁麒麟一樣難受(╯﹏╰)

 

 

 

 

 

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