Agile Core - A powerful component based micro front-end framework
Agile框架结合Vite和VUE的技术栈+自定义组件模块(基于Web Component),形成一个组件式的微前端框架。该框架旨在实现跨框架调用的微前端组件定义和使用。
使用Agile框架创建的组件称为AUI组件,该组件可以在框架内使用,也可以打包后在任意框架中通过引入js的方式使用,包括任何标准的DOM操作方式调用和样式设置。
document.createElement、innerHTML等标准DOM操作方式.aui.vue文件格式,保持Vue开发习惯1. AUI组件必须以.aui.vue作为文件后缀
2. 组件名是唯一的,同一个组件名对应的实现只有一个,组件可以重复定义,但是后面定义的会覆盖前面的,其中有个名为auix的prop属性用于扩展属性
3. 组件名称必须是帕斯卡命名法(Pascal Case),即每个单词的首字母都是大写,单词之间没有分隔符
4. 组件名一般显式的在组件中通过name来定义,否则将取当前文件名的名称作为组件名
当组件mounted结束会执行两个动作:
1. 触发aui-init事件,事件的detail为{code: 0}。(该事件作用在原生DOM上,所以框架内和外都可以监听)
2. 执行组件内部的auiInit函数(如果存在),该函数与mounted同级。
函数定义:async $call(name: string, ...args: any[]) : any
该函数是通用的组件间函数调用的定义,AUI原生DOM调用VUE组件函数或者VUE组件调用AUI原生DOM的函数都是使用这个方法。
其中,name可以是组件里暴露的函数名或者属性名(支持多级属性访问),前提是这些函数或属性要暴露,当为函数时为执行函数并返回结果;当为属性时,如果没有args则返回属性值,如果有args,将取args的第一个元素赋值给属性,返回null;当匹配不到任何函数和属性将返回一个Error对象。
1. 原生DOM调用VUE组件,则组件内使用this.$call调用,框架外使用el.$call。
``js`
// $call是原生DOM上的扩展函数,用于组件外部调用内部的函数或者取值/赋值之用
const el = document.querySelector('aui-my-com');
const value = await el.$call('echo', 111); // value 为111
2. VUE组件调用原生DOM,则组件内使用this.$call调用
`js`
// $call也是VUE组件的扩展函数,用于组件内调用原生DOM的函数或者取值/赋值之用
export default {
...
methods: {
setDomStyle() {
this.$call('setAttribute', 'style', 'color: red;');
}
}
...
}
由于AUI组件本身是原生DOM,所以都是通过value值作为MVVM绑定的依据(注意区分通过setAttribute设置的value属性,非同一个意思)。
VUE组件扩展了两个重要的方法:$value和$anyToArray。$value: 该方法用于获取或设置组件的原生DOM的value值,主要用于MVVM绑定值传递给原生DOM。$anyToArray: 该方法用于将任意类型的值转换为数组类型,主要用于处理多选场景。
使用方式如下:
`html`
在组件内部需要绑定一个额外的变量做内部的MVVM,并同时监听value值和该变量的变化,如下:
`js`
{
...
data() {
return {
localValue: ''
}
},
watch: {
value(v) {
// 当原生DOM的value值变化,同时更新内部变量
this.localValue = v;
},
localValue(v) {
// 当内部变量变化,同时设置原生DOM的value值
this.$value(v);
},
}
...
}
注意:
1. 如果绑定的是多选类型,比如checkbox或者multiple类型的select以及一些自定义的组件,则内部变量的值必须是数组,而其他的则为字符串
2. value值默认是String类型,所以通过el.value获取到的值都是string类型,并且在设置value时也会被转为字符串,在多选场景下,如果希望直接获取到数组,可以在组件里为value添加prop,并设置type为Array即可
3. 如果多选场景没有单独设置value的type为Array,则需要自行在watch监听value变化的时候将字符串转为数组。VUE的methods上已经扩展里$anyToArray函数来转数组,比如:
`js
{
...
watch: {
value(v) {
this.localArray = this.$anyToArray(v);
},
localArray(v) {
this.$value(v);
}
},
...
}
`
由于AUI组件是原生DOM,所以使用上跟VUE本身的插槽使用方式有所不同。类似于DIV等标签,理论上所有子节点都是默认插槽的内容,而没有具名插槽,为了扩展具名插槽,AUI组件内部使用了aui-slot元素来实现具名插槽。
使用规范:
1. aui-slot仅在通过原生DOM方式时使用,通过标准VUE组件则仍使用template。aui-slot
2. 元素使用for属性指定需要插入的插槽名称。aui-slot
3. 不支持VUE插槽的高级用法。
比如:
`html
这是header
这是header
`
在框架内部调用组件,可以直接使用标签名(aui-comp-name)方式调用,也可以使用Vue风格的组件调用方式,如果是在框架外调用则只能通过标准的DOM操作方式调用,比如:
`html`
`js
// 通过标准创建原生DOM方式在框架内和框架外都可使用
const el = document.createElement('aui-my-comp');
document.body.append(el);
// 通过标准插入代码片段方式在框架内和框架外都可使用
document.body.innerHTML = '
`
Agile3.0框架目前只支持在Vite项目中开发,但是编译后可以在任何框架中使用。
版本要求:
1. node22+
2. vite7+
3. vue3+
`bash`
npm install agile-coretypes
安装完成会在当前工程的目录生成必要的代码模块定义,如果没有生成,可以到已安装的模块的types目录下把所有d.ts文件拷贝到项目的types目录,并且设置项目自身的tsconfig.json文件,添加types目录到include节点下
`js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { getAuiConfig } from 'agile-core'
import { mergeConfig } from 'vite'
// 引入aui插件
const { userConfig, isCustomElement } = getAuiConfig();
const baseConfig = {
plugins: [vue({
template: {
compilerOptions: {
// 设置以aui开头的原生DOM为自定义元素
isCustomElement
}
}
})],
}
// https://vite.dev/config/
export default defineConfig(async () => {
// 合并aui配置到vite配置中
return mergeConfig(baseConfig, userConfig)
})
`
所有aui组件都需要以.aui.vue文件的格式进行定义,ExampleComp.aui.vue文件:
`html
`
组件内容与VUE组件规范一致,但是需要遵循前面提到的规范。
注:如果是在框架内使用,在import一个.aui.vue文件时可能会报错,需要添加类型定义,即在合适的d.ts文件中添加:
`ts
// vite-env.d.ts文件内容
///
declare module '*.aui.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}
`
AUI组件可通过插件机制对原组件的定义进行修改,或者对组件重新进行定义。
需要注意的是,对组件更新只有在组件创建前有效,请注意时机。
`js
// 引入AUI核心
import { default as auiCore, type Component } from 'agile-core';
`
组件hook即对组件内部的行为进行变更,主要通过函数hookStructure(tagName: string, handle: HookHandler): void;实现
其中:
tagName是组件的完整标签名,比如:aui-my-comphandle是一个函数,用于对组件内部的行为进行变更,函数的参数为组件的定义,返回值为变更后的组件定义,也可以不返回。
比如:
`js
auiCore.hookStructure('aui-example-comp', function (structure: Component) {
const originMounted = structure.mounted;
structure.mounted = function () {
console.log('from hook aui-example-comp');
originMounted?.call(this);
}
console.log('hook aui-example-comp');
});
`
组件定义即对AUI组件进行定义,主要通过函数define(v: Component, force?: boolean): Component;实现。
其中:
v为组件的定义force为是否强制定义,默认值为false。仅在当组件已经被定义时生效,true则会覆盖定义,false则本次定义无效
比如:
`js
auiCore.define({
name: 'ExampleComp',
props: {
myMsg: {
type: String,
default: ''
}
},
render() {
return h('div', { class: 'container' }, ['这是强制定义的组件', h('div', this.myMsg)]);
}
}, true);
``