目錄
組件介紹
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(){}],
}
支持的生命週期方法名如下,beforeCreate
、created
、beforeMount
、mounted
、beforeUpdate
、updated
、 beforeDestroy
、destroyed
。
Watch
該裝飾器的出現,只是因爲 watch
需要有以下幾個要素:
- 被監聽的變量名
- 監聽選項
- 觸發函數
用法
完整的 @Watch
接口如下表所示。
function Watch( key: string [, option: Object = {} ] ): PropertyDecorator
參數名 | 類型 | 用途 | |
---|---|---|---|
key | string | 監聽的參數名,來自 computed 、data 、props 三者之一。 |
|
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>
吐槽:學這個麒麟框架真的像中了佐二助大招雷遁麒麟一樣難受(╯﹏╰)