mpaaS的kylin框架-项目结构(脚手架)

脚手架简介

项目初始化结构如下

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 构建及监听文件变化


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值