# widget开发
这里介绍一个从搭建微前端到完成widget开发案例的大概流程。
# 开发前提
本项目的运行依赖afcenter-ui和portal-ui项目+widget-ui项目(部分组件使用到components项目),开发过程中确保项目都在运行。
# 创建微前端项目
1.安装primeton命令
npm install primeton-cli -g
2.创建微前端项目
primeton create-m-app 指令参考:
primeton create-m-app [moduleName] [debugPort]
创建微前端项目myApp,调试端口:8888
primeton create-m-app myApp 8888
运行命令后,在当前工作目录生成微前端项目结构:
# 定义参数
在微前端项目myApp中新建配置文件,eg: src\utils\widgetSetting.js
注:如果开发过程中,涉及修改参数,需要重新拉取widget
export const dropConfig = {
my_widget: { // 与widget绑定资源code一致
code: 'my_widget',
showStyle: 'list',
eventLists: [], // 根据所需(0个或多个),自定义参数,
width: 60, // widget的初始宽度,非必填(屏幕总宽分为120个单元,默认值40,60就是一半)
height: 10, // widget的初始高度,非必填(屏幕总高分为20个单元,默认值8)
global: [{ // 头部的横向菜单
label: '清空',
eventCode: 'add',
component: 'widget_button'
}],
self:[{ // 头部的纵向菜单,按钮以及弹框组件
label: '新增', // 按钮名称
eventCode: 'add',
icon: 'el-icon-plus',
isDialog: true,
component: 'widget_form' //自定义事件对应的组件;需在 /views/settingComponents/目录下写的组件name一致
}]
}
}
# 暴露模块
- 暴露配置文件
- 并新建配置文件中出现的组件,在build/mfp.config.js中对外暴露页面(开发过程中修改此配置文件,需要重启项目)
exposes: {
...,
// 配置文件
'./settingConfig': './src/utils/widgetSetting.js',
// widget主页面
'./my_widget': './src/views/my_widget/index.vue',
// 横向布局组件
'./widget_button': './src/views/my_widget/widget_button.vue',
// 弹框组件
'./widget_form': './src/views/my_widget/widget_form.vue'
}
# 配置代理
添加微前端的代理
// webpack代理
'/myApp': {
target: 'http://localhost:8888/',
},
// nginx代理
location /myApp{
proxy_pass http://localhost:8888/myApp;
}
# 配置页面
在运行项目的<应用管理>页面里注册资源
- 配置微前端模块(添加并保存)
- 添加分组
添加页面
页面授权(勾选中,并保存)
添加门户
门户授权
添加widget
widget授权(一般添加后会自动授权,如果没有你想要的角色,可自行授权,同门户)
进入门户,并拖拽出widget
# 开发调试
页面大概拆分为主页面、横向菜单和纵向菜单
要想实现数据持久化,有两种途径,一种是直接调用自备的接口;另一种是通过widget的公共方法实现数据保存。下面的场景将详细介绍后者的实现。
# 主页面实现
页面实现
在页面中,获取到的props参数只有配置中的自定义参数(eventLists: [])
<div class="memo_main">
<el-row v-for="(event, index) in $attrs.eventLists" :key="event.id">
<el-divider v-if="index"></el-divider>
<el-col class="memo_item">
<div class="memo_title">{{ event.title }}</div>
<div class="memo_action">
<el-button type="text" @click="remove(event)">移除</el-button>
</div>
</el-col>
<el-col class="memo_item">
<div class="mr-20">{{ event.updateTime }}</div>
<div>{{ event.content }}</div>
</el-col>
</el-row>
</div>
数据持久化
实现数据持久化,通过触发updateItem方法,(这里的cloneDeep引入自lodash)
remove(event) {
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
let lists = cloneDeep(this.$attrs.eventLists)
lists = lists.filter(i => i.id !== event.id)
this.$emit('updateItem',{eventLists: lists})
})
.catch(() => {
})
}
# 横向菜单(global配置)
页面头部的横向菜单,涉及global配置,整个模块是一个slot,可以在对应的组件中实现所需功能。
页面实现和数据持久化
实现数据持久化,可通过更新configOption数据实现保存
<template>
<div>
<el-button @click="clearAll">清空</el-button>
</div>
</template>
<script>
export default {
name: 'myWidgetButton',
props: {
configOption: {},
},
methods:{
clearAll() {
const data = {
...this.configOption,
eventLists: [],
doSave: true
}
this.$emit('update:configOption', data)
}
}
}
</script>
# 纵向菜单(self配置)
页面头部的纵向菜单,点击打开弹框。涉及self配置,例如<新增>
在self配置项的label展示为下拉菜单,菜单点击事件已在公共方法里处理过,弹框组件为配置项的component值
弹框页面实现如下:
其中页面props参数:dialogVisible(弹框是否展示)、configOption(是整个widget的模型数据)
<div>
<el-dialog title="添加备忘录" :visible.sync="dialogVisible" width="800px" append-to-body :before-close="handleClose">
<el-form :ref="formRef" :model="form" :rules="validateRules" label-width="100px">
<el-row>
<el-col :span="22">
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" />
</el-form-item>
</el-col>
<el-col :span="22">
<el-form-item label="内容" prop="content">
<el-input v-model="form.content" type="textarea" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitForm">确 定</el-button>
</span>
</el-dialog>
</div>
弹框数据持久化如下
发公共方法,需要修改弹框的dialogVisible = false,这样在$emit('configOption')时会触发数据保存和更新
submitForm(){
this.$refs[this.formRef].validate(async valid => {
if (valid) {
let data = cloneDeep(this.configOption)
data.dialogVisible = false
const time = new Date()
const updateTime = time.getFullYear() + '/' + time.getMonth() + '/' + time.getDate()
data.eventLists.push({id: `t_${Math.random()*(100000)}`,...this.form, updateTime})
this.$emit('update:configOption', data)
}
})
}
# 编译部署
- 开发完成后,打包部署。在项目根目录下,执行命令
npm run build:prod
将打包生成的dist文件放置在widget-ui包同级目录下
添加代理,启动项目
← 平台/应用widget管理 微前端模式 →