低代码研学笔记之 VForm(三)

原创
2024/12/11 08:49
阅读数 57

表单设计器布局、方法、属性定义解析

表单设计器布局

主要依赖element-ui实现布局,上下分为顶部和正文区域;正文区域划分为左、中、右三块区域;

 

<template>
  <el-container class="main-container full-height">
    <!-- 顶部 -->
    <el-header class="main-header">
      <div class="float-left main-title">
        <img src="../../assets/vform-logo.png" @click="openHome">
        <span class="bold">VForm</span> {{i18nt('application.productTitle')}} <span class="version-span">Ver {{vFormVersion}}</span></div>
      <div class="float-right external-link">
        <el-dropdown v-if="showLink('languageMenu')" :hide-timeout="2000" @command="handleLanguageChanged">
          <span class="el-dropdown-link">{{curLangName}}<i class="el-icon-arrow-down el-icon--right"></i></span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item command="zh-CN">{{i18nt('application.zh-CN')}}</el-dropdown-item>
            <el-dropdown-item command="en-US">{{i18nt('application.en-US')}}</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
        <a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, gitUrl)" target="_blank"><svg-icon icon-class="github" />{{i18nt('application.github')}}</a>
        <a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, docUrl)" target="_blank"><svg-icon icon-class="document" />{{i18nt('application.document')}}</a>
        <a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, chatUrl)" target="_blank">{{i18nt('application.qqGroup')}}</a>
        <a v-if="showLink('externalLink')" href="javascript:void(0)" @click="(ev) => openUrl(ev, subScribeUrl)" target="_blank">
          {{i18nt('application.subscription')}}<i class="el-icon-top-right"></i></a>
      </div>
    </el-header>
    <!-- 中间区域(垂直方向,正文部分) -->
    <el-container>
      <!-- 左边栏,可拖拽组件 -->
      <el-aside class="side-panel">
        <widget-panel :designer="designer" />
      </el-aside>
      <!-- 正文区域 -->
      <el-container class="center-layout-container">
        <!-- 正文区域之头部工具栏 ,引用工具栏组件 toolbar-panel  -->
        <el-header class="toolbar-header">
          <toolbar-panel :designer="designer" :global-dsv="globalDsv" ref="toolbarRef">
            <template v-for="(idx, slotName) in $slots" #[slotName]>
              <slot :name="slotName"></slot>
            </template>
          </toolbar-panel>
        </el-header>
        <!-- 正文区域之表单设计器, 引用表单组件 v-form-widget  -->
        <el-main class="form-widget-main">
          <el-scrollbar class="container-scroll-bar" :style="{height: scrollerHeight}">
            <v-form-widget :designer="designer" :form-config="designer.formConfig" :global-dsv="globalDsv" ref="formRef">
            </v-form-widget>
          </el-scrollbar>
        </el-main>
      </el-container>
      
      <!--  右边栏,组件属性设置、表单属性设置 setting-panel  -->
      <el-aside>
        <setting-panel :designer="designer" :selected-widget="designer.selectedWidget"
                       :form-config="designer.formConfig" :global-dsv="globalDsv" />
      </el-aside>
    </el-container>

  </el-container>
</template>

依赖库分析

四大组件:WidgetPanel 左边栏的可拖拽组件;ToolbarPanel 设计器顶部的工具栏组件;SettingPanel 组件属性和表单属性设计组件;VFormWidget 设计器容器组件;组件均共享designer: createDesigner(this) 方法创建的设计器实例,具体实现代码如下:

export function createDesigner(vueInstance) {
  //克隆默认表单属性,后台接口设计:保存默认设置,读取默认设置
  let defaultFormConfig = deepClone( getDefaultFormConfig() )

  return {
    widgetList: [], //          //组件列表
    formConfig: {cssCode: ''},  //表单配置

    selectedId: null,           //选择的组件ID
    selectedWidget: null,       //选中的组件对象实例
    selectedWidgetName: null,   //选中组件名称(唯一)
    vueInstance: vueInstance,   //表单设计器页面的this对象

    formWidget: null,           //表单设计容器

    cssClassList: [],           //自定义样式列表

    historyData: {
      index: -1,  //index: 0,
      maxStep: 20,
      steps: [],
    },
    methods:....此处省略19个(参见下面交互方法分析部分)
  }
}

 

  import WidgetPanel from './widget-panel/index'
  import ToolbarPanel from './toolbar-panel/index'
  import SettingPanel from './setting-panel/index'
  import VFormWidget from './form-widget/index'

  import {createDesigner} from "@/components/form-designer/designer"
  import {
    addWindowResizeHandler,
    deepClone,
    getAllContainerWidgets,
    getAllFieldWidgets,
    getQueryParam, traverseAllWidgets
  } from "@/utils/util"
  import {MOCK_CASE_URL, VARIANT_FORM_VERSION} from "@/utils/config"
  import i18n, { changeLocale } from "@/utils/i18n"
  import axios from "axios"
  import SvgIcon from '@/components/svg-icon'

 

交互方法分析

src/components/form-designer/index.vue

    import {createDesigner} from "@/components/form-designer/designer"

    data() {
      return {
        vFormVersion: VARIANT_FORM_VERSION,
        curLangName: '',

        vsCodeFlag: false,
        caseName: '',

        docUrl: 'https://www.vform666.com/document.html',
        gitUrl: 'https://github.com/vform666/variant-form',
        chatUrl: 'https://www.vform666.com/pages/chat-group/',
        subScribeUrl: 'https://www.vform666.com/pages/pro/',

        scrollerHeight: 0,

        designer: createDesigner(this), //创建设计器对象,最核心的对象

        fieldList: []
      }
    },

方法路径

以下方法均基于designer对象进行功能实现

default.methods.setFormJson 设置表单JSON对象 string/object

default.methods.getFormJson 获取表单JSON对象

default.methods.clearDesigner 清空设计器画布

default.methods.refreshDesigner 刷新设计器画布

方法实现

      setFormJson(formJson) {
        let modifiedFlag = false
        if (!!formJson) {
          if (typeof formJson === 'string') {
            modifiedFlag = this.designer.loadFormJson( JSON.parse(formJson) )
          } else if (formJson.constructor === Object) {
            modifiedFlag = this.designer.loadFormJson(formJson)
          }

          if (modifiedFlag) {
            this.designer.emitHistoryChange()
          }
        }
      },

      getFormJson() {
        return {
          widgetList: deepClone(this.designer.widgetList),
          formConfig: deepClone(this.designer.formConfig)
        }
      },

      clearDesigner() {
        this.$refs.toolbarRef.clearFormWidget()
      },


      /**
       * 刷新表单设计器
       */
      refreshDesigner() {
        //this.designer.loadFormJson( this.getFormJson() )  //只有第一次调用生效??

        let fJson = this.getFormJson()
        this.designer.clearDesigner(true)  //不触发历史记录变更
        this.designer.loadFormJson(fJson)
      },

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部