xaml

eXtensible Application Markup Language

Usage no npm install needed!

<script type="module">
  import xaml from 'https://cdn.skypack.dev/xaml';
</script>

README

XAML 扩展应用标示语言

满足系统中动态内容的即时更新需求。

适合应用场景

- 运营活动页面(需要灵活的页面(模板)响应不同的运营内容)
- 动态子系统(广告、消息推送)
- 可视化非技术页面搭建(流程系统、表单系统、基于模板的宣传页面)

特点

- 领域描述:使用DSL描述页面布局、数据与交互。
- 框架独立:支持Vue/React/JSX/JS组件嵌入(当前暂未实现React)。
- 独立容器:只在需要支持动态内容地方插入即可。
- 数据绑定:支持组件与本地或远程数据源的绑定。
- 层级视图:视图元素采用树结构组织
- 数据同一:同一容器Portal数据集共享,方便数据绑定

总体结构

页面由多个Portal构成,功能紧密的部分构成一个Portal,Portal采用扁平的管理结构,但是视图结构采用组件树多层结构。Portal的组织结构图如下

img

页面布局解构

一个页面被划分为多个部分,每个模块之间应该是数据相对独立、交互关联少。 一个内部关联紧密,功能相似部分的模块我们用一个统一的Portal组件统一管理。 Portal是一个组件容器,内部组件在数据和值域上直属Portal管理,层级结构可以是多层结构

Portal

  • Portal 统一了模块内数据、行为和组件引用的管理,子组件的配置方法可以方便的获取数据,调用方法。
  • 统一模块内交互方式,比如可以直接修改数据和调用portal行为
    • this.$emit('change', {value: 123})
    • this.changeList([])
  • 统一组件的引用, 比如可以获取任意组件引用 this.$refs.table
{
    state: { // 公共数据字段
        weight: 0
    },
    children: [
        {
            html: '<p><b>温馨提示</b>:不要吃太多!</p>',
        },
        {
            type: 'component',
            uiType: 'NumberBox',
            field: 'weight',
            config: {
                value: 0.8,
                unit: 'kg'
            },
            on: {
                changeValue (e) {
                    if (this.validate(e.value, 'weight')) {
                        // 通过事件通知容器组件捕获变化
                        this.$emit('change', {value: e.value})
                        // 或者直接修改state
                        this.setState({weight: e.value})
                    }
                }
            }
        }
    ]
}

类型

html片段

{
    html: '<p><b>温馨提示</b>:不要吃太多!</p>'
}

text片段

{
    text: '提示:你的余额不足1千万'
}

组件

  • 组件配置
{
    type: 'component',
    uiType: 'DatePicker',
    field: 'range',
    config: {
        maxDates: 365
    },
    on: {
        'model-change': 'change',
        'value-change': 'change'
    }
}
  • 组件注册

对于Vue组件,需要提前全局注册好组件,或者在Portal注册组件即可。

import {DatePicker, RichTable} from 'smui'

export default {
    type: 'component',
    uiType: 'Portal',
    state: {},
    components: {
        DatePicker,
        RichTable
    }
}
  • 组件事件

通过ondispatch属性进行事件注册。处理函数的this被绑定为Portal容器,因此可以调用portal的方法和获取相关数据.

  • on 一般用于注册事件处理函数,如果是字符串也被处理为事件别名转发。
  • dispatch 一般用于注册事件别名转发,也可注册为处理函数。与on用法无本质区别
  • 为了支持多次注册,事件注册方法被压入事件队列,顺序触发。
{
    on: {
        'model-change': 'change',
        'range-change': function (e) {
            this.$emit('change', {value: e.value})
        }
    }
}

容器

通过指定typecontainer, 容器对象如果有children顺序将children内的元素/组件渲染。 容器可以包含容器,因此可以构成组件/元素树。 但是组件扩展的行为和事件函数内的this都将指向portal对象。

{
    type: 'container',
    children: [...]
}

扩展类型

为了减少相似组件的重复配置项,使用plugin作为扩展组件。

{
    plugin: {
        CutomType: {
            type: 'uiType',
            uiType: 'NumberBox',
            config: {
                validate: {
                    max: 1000,
                    min: 10
                }
            }
        }
    },
    children: [
        {
            type: 'CustomType',
            field: 'bid'
        }
    ]
}