文章目录

  • 1. approval介绍
  • 1.1 功能应用
  • 1.2 项目地址
  • 2. jsxPreview.vue应用
  • 2.1 页面结构
  • 2.2 表单解析
  • 3. 功能拓展
  • 3.1 数据回显
  • 3.2 拓展样式
  • 3.3必填字段完成后执行某方法


1. approval介绍

1.1 功能应用

approvalFlwo是一款关于工作流应用的开源免费项目,用户可以通过网页在线拖拽各个组件(输入框、选择框、布局容器、滑块20中常见的组件),自己布局、设计一个表单的样式,并配套着有相应的组件解析及 数据回显解析规则。

对比钉钉请假流程,请假需要的一个基本条件:

1、请假理由
2、向谁请假(审批人)
3、让谁看到(抄送人)
4、如果请假一天之内,审批人必须是xxx;请假一周,审批人必须是xxx

作者说明的功能简介:

1.表单配置(form-generator)
	拖拽表单,生成布局页面
	配置拖拽组件属性,定制组件形态
	生成JSON数据并生成预览页面
2.流程节点配置(仿钉钉界面)
	创建审批流程(发起人,审批人,条件节点,抄送人)
	配置节点详细数据,包括条件节点表达式及期望值等
	配置节点对表单得权限(目前并未在预览页面中做控制)
	必填节点校验

2. jsxPreview.vue应用

2.1 页面结构

jsxPreview的作用为:表单样式的回显,及数据回显的解析(案例上没有使用,但是我们可以去拓展这个功能,作者提供了表单填写完毕之后json数据的生成及解析),主要的功能拓展都是基于本页面来现实的。

<script>
	const xxx = {
		....
	};
	function xxx() {
		....
	};
	export default {
		....
	}
</script>
<style>
....
</style>

可以发现这个单页中没有用到<template></template>,全部是根据
var confGlobal = this.$route.params.formData || mockData.formData 获取到json数据后,通过解析动态生成的。
问题一: 如何在export default外层function中调用methods里的方法?
可以把方法定义在window中以供全局使用

mounted() {
    window.initialProcess = this.initialProcess;
},

2.2 表单解析

const layouts = {
	colFormItem: function(){},
	rowFormItem: function(){}
}

layouts定义了colFormItem、rowFormItem两种不同属性的表单解析方式。
查找怎么使用的?

{ Array.isArray(conf.children) && conf.children.map((el) => layouts[el.layout](el, h, ctx)) }
//--------------------------------------------------
return layouts[c.layout](c, h, this, initData);

根据json数据中定义的不同字段代入layouts从而执行colFormItem/rowFormItem的方法。

3. 功能拓展

3.1 数据回显

分析可得到layouts是解析json数据然后渲染到页面上的。

buildData(ctx, conf.defaultValue, conf.vModel);
//conf.defaultValue,数据中默认的值
//conf.vModel 同v-model,绑定的值

即可以判断是否存在要回显的数据,如果存在的话,就用要被回显的数据。不存在的话,就默认不是数据回显

if (defData) {
    !_isMounted && buildData(ctx, defData, conf.vModel);
} else {
    !_isMounted && buildData(ctx, conf.defaultValue, conf.vModel);
}

在调用layouts的时候,把回显的数据穿过来即可

3.2 拓展样式

render(h){}作为一个中心整合的存在,它return出来html代码

return <div class='preview-container only-read' style={'width:' + this.containerWidth + '%;'}>
    <el-row class='details-from-date'
        gutter={this.confGlobal.gutter}
        style='padding: 2rem 2rem 0;'
    >
        {this.buildForm(h)}
    </el-row>
    <div class='width-slider' style='display:none;'>
        <el-slider vModel={this.containerWidth} min={100} max={100}></el-slider>
    </div>
    {this.buildDrawer(h)}
}

同样可以在这儿定义相应的html,使页面渲染出来

3.3必填字段完成后执行某方法

layouts中定义着form数据变化的检查功能,

<render
   formData={ctx[ctx.confGlobal.formModel]}
   conf={conf}
   value={ctx[ctx.confGlobal.formModel][conf.vModel]}
   ref={conf.rowType === 'table' ? conf.vModel : undefined}
   onInput={handleInput}
/>

handleInput就是表单触发的方法

可以查看render.js中

function vModel ( self, dataObject, value ) {
  // dataObject.props.value = value
  dataObject.on.input = val => {
    self.$emit( 'input', val )
  }
  // 因为有些组件的v-model绑定的事件是change 所以这里也得监听
  dataObject.on.change = val => {
    self.$emit( 'input', val )
  }
}

每次输入或者改变都会触发一次,比如当在输入框中输入一串值得时候

每次输入的值改变

触发得到的值

1

1

12

12

123

123

12

12

失去焦点

失去焦点


12

这儿的思路是:判断最后一次和上一次的值是否相同,如有更好的思路也欢迎留言

// 全局定义两个变量
var aa = [];
var num = 0;
const layouts = {
	...
	colFormItem: function(){
		const handleInput = val => {
            if (num === 0) {
                aa[num] = val;
                num = 1;
            } else {
                aa[num] = val;
                num = 0;
            }
            // console.log(aa);
            if (val !== undefined && aa[0] === aa[1] && conf.required) {
                window.initialProcess();
            }
        }

	}

	...
}