前言
目前自己开源了一个低代码开发平台,里面主要包含流程设计器、表单设计器、代码生成器。其中在设计表单设计器时碰到了一些问题,在这里想与大家分享一下。
问题来源
在设计表单设计器的时候,如果针对开发者(而非业务人员时),经常需要手动写JS或者CSS调整样式,那么 平台如何去覆盖这一层需求呢?
问题分析
可不可以 针对每一个组件,都设置一个 动态JS属性和CSS属性变量,开发者将手动输入对应脚本。就会引出以下几个问题:
- 如何设置动态脚本呢?
- 这个脚本如何与vue 的method 关联呢?
- 可以做到动态method 吗?
- 如何触发这个脚本呢?
下面带着几个问题进一步探讨。
提出方案
通过设置动态字符串,然后将 字符串渲染成可执行函数。将这个函数 通过动态事件绑定到组件中。
动态事件: v-on="{eventName:methodName(param),eventName1:methodName1(param1)}" 即v-on="{触发事件名称(如:click,change,bulr…):方法名(参数…)}"
解决方案
问题一 :如何设置动态脚本呢?
方案一:重新构造script标签(不推荐)
分析
这个思路其实非常简单,用innerHTML添加的script无法执行,但是我们script创建节点,并用appendChild追加上去是可以的,所以我们只需要做一下二次工作就可以了,看下面的例子:
示例
<div id="easyBpm"></div>
var html = '<div>html</div><script>console.log(1);<\/script>';
var easyBpm= document.getElementById('easyBpm');
cont.innerHTML = html;
var oldScript = cont.getElementsByTagName('script')[0];
easyBpm.removeChild(oldScript);
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.innerHTML = oldScript.innerHTML;
easyBpm.appendChild(newScript);
方案二: eavl()(不推荐)
分析
虽然eval因为其安全性不推荐使用,但是在此特殊场景,使用eval确是非常简单的解决方案,就是把script标签中的代码eval一下手动执行,就ok了,看下面代码:
示例
var html = '<div>html</div><script>console.log(1);<\/script>';
var easyBpm= document.getElementById('easyBpm');
cont.innerHTML = html;
var oldScript = cont.getElementsByTagName('script')[0];
easyBpm.removeChild(oldScript);
var scriptText = oldScript.innerHTML;
eval(scriptText);
方案三: new Function()(推荐)
分析
有一个很少被用到的新建函数的方法,但是有时候不得不使用它。new Function允许将任何字符串转换为函数,传入name参数和字符串函数体,字符串函数体由模板字符串提供,非常简洁方便。
语法
let func = new Function ([arg1[, arg2[, ...argN]],] functionBody)
换句话说,函数的参数(或更确切地说,各参数的名称)首先出现,而函数体在最后。所有参数都写成字符串形式。
示例
通过查看示例,可以更容易理解。这是一个有两个参数的函数:
let sum = new Function('a', 'b', 'return a + b');
alert( sum(1, 2) ); // 3
如果所要新建的函数没有参数,那么new Function()只有一个函数体参数:
let sayHi = new Function('alert("Hello")');
sayHi(); // Hello
问题2 脚本如何与vue 的method 关联呢
解决方案:
通过定义一个固定的方法名,方法里调用 字符串解析的方法
问题3 可以做到动态method 吗?
答案显然是不可以的,可以通过 问题2 的解决方案 处理这个问题,就是方法名固定,具体方法是动态的。
问题 4. 如何触发这个脚本呢?
解决方案:
v-on="{eventName:methodName(param),eventName1:methodName1(param1)}" 即v-on="{触发事件名称(如:click,change,bulr...):方法名(参数...)}"
完整示例:
<template>
<div id="app">
<input v-on="{change:dynamicFun}" />
</div>
</template>
<script>
var app = new Vue({
el: '#app',
data() {
return {
myArray: [{id:1, name: 'aa'}],
myArray2: [],
funDetail: 'console.log(111)',
eventName: 'change'
}
},
methods: {
dynamicFun() {
var val = new Function(this.funDetail)
val()
}
}
});
</script>