低开开发笔记(二):低代码编辑器基本原理

好家伙,

完整代码已开源

https://github.com/Fattiger4399/ph-questionnaire.git

本片我们来讲述

如何将dsl的数据渲染为视图

1.数据格式

复制代码
dsl: {
                component: 'div',
                wid: 0,
                props: {
                },
                style: { background: '    #FFF8DC' },
                children: [

                    {
                        wid: 1,//序号
                        component: 'ph-radio', //组件名
                        props: {    //组件数据接口
                            No: 1,
                            title: "我是输入框",
                            options_1: "选项一一",
                            options_2: "选项二二"
                        },
                        style: { top: '300px', left: '300px', zIndex: '1', border: "2px dashed red" },//组件配置项
                        attrs: {

                        },
                        events: {
                        }
                    },
]

2.vue的h函数

h 函数是 Vue.js 中的一个辅助函数,通常用于创建虚拟 DOM 元素(VNode)。

在 Vue.js 中,h 函数实际上是 createElement 函数的别名

createElement 函数是 Vue.js 内部用来创建虚拟 DOM 元素(VNode)的核心函数。

h 函数接收三个参数

  • 第一个参数:表示要创建的元素的标签名、组件或者函数。
  • 第二个参数:是一个包含元素属性、样式、事件等信息的对象。
  • 第三个参数:是元素的子元素,可以是一个数组或者单个元素。

3.编辑器代码解释

代码如下:

复制代码
<script>
export default {
    data() {
        return {
            a: true
        }
    },
    props: ['dsl', 'model'],
    render(h) {
        let dsl = this.dsl;
        return this.generator(h, dsl);
    },
    methods: {
        adddraggable() {

        },
        select(e) {
            console.log(e);
        },
        generator(h, dsl) {
            //h(tagName,props,children)
            //当前元素,元素属性,子元素
            return h(dsl.component, this.generateProps(h, dsl), this.generateChildren(h, dsl));
        },
        generateProps(h, dsl) {
            let self = this;
            let result = {
            }
            result.props = {
                ...dsl.props
            }
            result.attrs = {
                ...dsl.attrs
            }
            result.style = { ...dsl.style }

            if (self.model.selected) {
                if (self.model.selected.wid == dsl.wid) {
                    // 获取所有的按钮元素
                    const allElements = document.getElementById('editor.div')
                    console.log(allElements)

                }
            }
            if (dsl.events) {
                result.on = {
                    click: function (e) {
                        // console.log(e, dsl.wid, this);
                        e.preventDefault();
                        self.$emit('select', { e, dsl });
                    },
                };

            }
            return result;
        },/**
 * 该函数用于生成child节点
 * @param {*} h 
 * @param {*} dsl 
 */
        generateChildren(h, dsl) {

            let result = dsl.children &&
                dsl.children.map((child) => this.generator(h, child))
                || [];

            // (A&&B)||C

            if (dsl.text) result.push(dsl.text)
            // console.log(result)
            return result;
        }
    },
    mounted() {
    }
}
</script>

解释

本质上是对props属性递归处理后,使用vue的h函数将dsl全部渲染出来

让我们把重点放在这句上

复制代码
return h(dsl.component, this.generateProps(h, dsl), this.generateChildren(h, dsl));
  1. generator 方法用于生成 Vue 元素,根据传入的 dsl 配置信息,设置元素的属性、样式、事件等,并返回生成的元素。

  2. generateProps 方法用于生成元素的属性,包括 propsattrsstyle,同时根据条件判断是否添加事件监听器。

  3. generateChildren 方法用于生成元素的子元素,遍历 dsl 中的 children,对每个子元素调用 generator 方法生成对应的 Vue 元素,并返回所有子元素的数组。

最终效果如下: