脚手架简介
项目初始化结构如下
project
├── mock
│ ├── mock.config.js
│ └── rpc
│ └── test.js
├── package.json
├── www
└── src
├── common
│ ├── components
│ ├── css
│ │ └── base.less
│ ├── img
│ └── js
├── layout
│ ├── index.html
│ └── layout.html
└── pages
└── index
├── components
├── index.js
└── store
mock
该目录提供了一种数据方式,即使用 cnpm run dev:mock
启动时,会自动加载其中的 rpc 目录和 jsapi 目录的对应数据接口。
package.json
在 package.json 文件中的 kylinApp 字段包含了项目配置的元信息,主要有 pages、output、devPort、plugins、dirAlias。
www
执行 cnpm run build 之后,会自动将构建产物输出到www目录中
src/common
用以放置项目中使用的CSS,JS,IMG文件
src/layout
对应./src/pages/${pageName}
的各个页面,可以在 package.json
中配置对应页面使用的 HTML 模板路径。支持 Nunjucks 语法。
src/pages
此目录用于存放各个页面。页面存放于 ./src/pages/${pageName}/ 目录下,各页面分别包含 components , store 和 index.js 。
- components 目录中,每个组件都是 Vue 组件,具体编写规范请参考 组件规范。
- store 目录中,有一个 Vuex.Store 实例,具体使用请参考 状态注入。
- index.js 为当前 page 的主入口,这里的 page 页面最后会生成一个特定的 ${pageName}.html 页面
页面
Page是一个Webview的逻辑抽象层,同时也是组件挂载的根节点。
注意关于页面Page的代码全在src/pages的index.js里面
代码引入
import { Page } from '@ali/kylin-framework';
页面声明结构
一个Page包含的借口咋页面接口中声明,提供了对Vue实例的完整控制能力,简易的Page使用如下,initOptions负责处理额外的Vue配置选项。
demo
import { Page } from '@ali/kylin-framework';
import IndexComponent from './indexComponent.vue';
class IndexPage extends Page {
initOptions() {
return {}
}
render(h) {
return <IndexComponent></IndexComponent>
}
}
new IndexPage('#app');
实例代码
import { Page } from '@ali/kylin-framework';
import IndexView from './components/index-view.vue';
import store from './store';
import FastClick from 'fastclick';
import '@alipay/antui/dist/rem/antui.css';
import '@alipay/antui/dist/rem/widget/switch.css';
import "@alipay/antui/dist/rem/widget/dialog.css";
import "@alipay/antui/dist/rem/widget/toast.css";
// 自定义指令
import Vue from "vue";
import DiyDirective from 'common/js/registerDirectives.js';
Vue.use(DiyDirective);
FastClick.attach(document.body);
class IndexPage extends Page {
initOptions() {
return {
store
};
}
render() {
return <IndexView></IndexView>;
}
}
new IndexPage('#app');
页面接口
命名空间
es6 通过如下方式引入
import { Page } from '@ali/kylin-framework';
API
目前Page提供如下成员方法以供派生:
- initOptions
- render
initOptions
function initOptions(): VueOptions
返回值
返回结果要求是一个合法的Vue入参。一般来说,不建议在Page层引入过于复杂的配置,设计到的逻辑都可以放到 Component 中来维护。
render
该函数要求是一个合法的Vue的render函数
function render():VNode
返回值
返回结果要求是合法VNode元素,请按照JSX规范书写。
组件
Componet扩充自Vue的组件,提供了Vue组件对等的输入参数能力。在代码书写时提供类class的装饰器Decorator风格。
注意关于组件Component的代码全在src\pages\xxx\components里面
代码引入
import { Component, Watch } from '@ali/kylin-framework';
组件声明结构
一个组件可以包含数据,JSX渲染函数,模板,挂载元素,方法,生命周期等Vue的options选项的对等配置。组件声明包括以下几部分, 分别使用@Component和@Watch两种不同装饰器进行包装:
- class类声明,使用装饰器@ Component。
- 类成员声明,不使用装饰器
- 类成员方法声明,一般不装饰器,除非该方法需要watch另外一个已声明的变量。
vue单文件组件
<!-- 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文件内,以下是一个简单的例子:
demo
<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 = {}
get comput() { return this.data.c * 2 }
onClick() {}
mounted() {}
}
</script>
实例代码
<template>
<div>
<Toast @click="onClick">点击</Toast>
</div>
</template>
<style lang="less" rel="stylesheet/less" scoped>
/* less */
</style>
<dependency component='Toast' src="common/compoments/toast.vue" lazy/>
<script type="text/javascript">
import { Component } from '@ali/kylin-framework';
@Component({
mapStateToProps: ["xxxx", "yyyyy", "zzzzz"],//数据
mapActionsToMethods: ["bbbbb", "qaaaa"]//方法
})
export default class IndexView {
props = {}
data = {}
get comput() { return this.data.c * 2 }
mounted() {}
}
</script>
上述例子中,有个顶级标签,除了与vue相同的<template>、<style>、<script>
之外,还有一个 <dependency>
标签。
<template>、<style>与vue一致
script
class结构
定义一个Componet,在代码结构上,使用;类class的装饰器Decorator风格。其中装饰器有 @Component 和 @Watch 这 2 种,通过以下方式引入。
import { Component, Watch } from '@ali/kylin-framework';
@Component
export default class Hello {
}
方法类型
组件以class形式声明,必须对该class进行装饰修饰。在class内部,成员变量是不需要被手动处理的,在构建过程中通过 babel 插件自动进行处理,而成员函数一般不需要装饰器挂载,除非是使用@Watch的场景,其中@Component回处理的属性如下表
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() {}
}
Watch
该装饰器的出现,只是因为watch需要有以下几个要素
- 被监听的变量名
- 监听选项
- 触发函数
用法
完整的@Watch接口如下表所示
示例
- 对于@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: false})
OnChangeA(newVal, oldVal) {
}
}
注意 以上对 data.a 的监听,会转换成如下形式,需要注意的是,如果没开启 deep: true 选项,当 data.a.b 发生变动的时候,不会触发该 OnChangeA 监听。
实例代码
@Watch('count') // 监听倒计时,清理timeID并重置
mm(oldValue, newValue) {
if (oldValue < 1) {
clearInterval(this.t);
this.t = null;
this.count = 60;
this.$parent.$parent.sendSuccess = false;
}
}
@Watch('sendSuccess')
sendS(oldValue, newValue) {
if (oldValue) {
this.used = true;
this.t = setInterval(() => {
this.count = --this.count;
}, 1000);
}
}
属性类型
构建工具会自动对成员变量应用了@Component.Property装饰器,不需要用户手动填写,最终的合并策略取决于被装饰的成员变量的标识符名称,框架内置了以下几种。如果不在下表中,会透传至 VueComponent 的 options 对象中。
props
@Component
export default class Hello {
props = {
name: {
type: String,
default: 'haha'
},
num: Number
}
}
详情请看API-props
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
上述
<template>
<child></child>
</template>
<dependency component="Child" src="./child.vue" />
默认对 @alipay/antui-vue 组件库支持 babel-plugin-import 按需加载。
状态注入
推荐使用下面的connent机制来透传$store
数据
-
接口声明
-
透传数据有以下三种方式
1.mapStateToProps
2.mapActionsToMethods
3.mapMethods
接口声明
@Component({
mapStateToProps: Object|Array,
mapActionsToMethods: Object|Array,
mapMethods: Array|Boolean,
mapEvents: Array
})
class Hello {
}
mapStateToProps
把state中的特定键值映射到当前组件的props中,其接收参数等价于Vuex提供的mapState辅助函数
辅助函数图解
第一个版本
首先是html
第二个版本
首先是html
第三个版本
首先html
新写法
mapStateToProps:以下三种方式实现
1.函数方式
说明 把 $store.state 中的名为 bbb 的数据,映射到名为 aaa 的 props 上。
{
mapStateToProps: {
aaa: (state, getters) => state.bbb
}
}
2.字符串键值对方式
说明 把 $store.state 中名为 bbb 的数据,映射到名为 aaa 的 props 上。
{
mapStateToProps: {
aaa: 'bbb'
}
}
3.字符串数组方式
- 把 $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>
命令行工具
初始化
当工程脚手架初始化完后,如果需要新增页面,除了单纯的复制粘贴以外,提供了以下命令来添加页面定义和组件定义
- init-page
- init-component
init-page
命令格式
kylin init-page <pageName>
注意
- 上述命令中
pageName
为必选参数,指新创建页面的英文名称。 - 如果当前 cwd 下有 package.json 并且存在 kylinApp 字段,则会自动往 kylinApp.pages 添加新增的 page。
init-component
命令格式
kylin init-component <componentName>
``
**项目常用构建**
kylin build --dev # dev 构建及静态服务器
kylin build --server --no-prod --hot # dev 构建及静态服务器及启用热更新
kylin build --server # prod 构建及静态服务器
kylin build --no-prod --watch # dev 构建及监听文件变化