Author: Orange

preface

Speaking of the page visual construction, many students must have some understanding, the industry has a lot of articles introduced, specific can see the bottom portal, this article only from how to build an easy to use, extensible general visual construction tools, explore the technical ideas, and thinking in practical practice, welcome to discuss each other.

There are many open source and commercial tools in the industry, but it is difficult to find general tools that meet the needs of customized business for many reasons:

  • With different users, the operation students and the R&D students have different demands for components with the same function. The operation students hope to be simple, while the R&D students hope to develop secondary capabilities
  • The components used for operational activities and process forms are almost entirely different depending on the scenario.
  • Designers have different requirements, and different systems have different requirements for designer interfaces and panel capabilities.
  • Developers have different preferences, some prefer React development, some prefer VUE, and use different component libraries.
  • .

Due to some of the above reasons, some open source tools can not be well implemented in the actual business, most of the time, they can only be developed by themselves, or based on open source secondary transformation.

Why try to make a generic visual scaffolding tool?

Visual configuration tool as an efficiency improvement tool, if only to meet their own business to build a set, from a larger range of view, is the efficiency of improvement or reduction? Even if a team or a department can achieve universal, the whole company may not, and will encounter the “repetitive wheel” often DISS, which basically means that it has its own customized needs, which cannot be met by other tools. Therefore, it is difficult to form a unified visual configuration components and specifications.

There are a lot of customization scenarios and preferences, but technically there are a lot of similarities:

1. Designers are required to add, drag and configure components. 2

Assuming designers can be customized, visual components implemented by different component libraries can run in different designers, constrained by an underlying set of Schema or DSL specifications. This solves the component sharing problem to a large extent, resulting in a significant reduction in repetitive development costs. It is not difficult to implement a designer and custom components, but to achieve such a specification while supporting extensions. Components and designers are just upper-level implementations.

To borrow a phrase from MAO:

The road is tortuous and the future is bright

Here are my thoughts on trying to implement the process

One, division

1. By scene

Typical service visualization configuration scenarios are as follows:

scenario The user The characteristics of use
Operating activities Operating classmates Large quantity, strong customization, need to quickly online General configuration operation activities, landing page, lottery, etc
The process form The process to implement High requirements for form ability, form linkage, formula calculation, etc Cooperate with process design to realize business flow
The business report Products, operations, etc Represented by the query form + table and chart configurations for customizable columns Presentation of process and business results
Personalized page The average user Configuration should be simpler with high interaction requirements Personalized appeal. Such as user home page, customized workbench, etc
Middle background page Research and development of the front-end Need to be able to extend code and be professional Front-end efficiency improvement. Solve tedious and repetitive development

Of course, the above is only a few typical scenarios of visual configuration, if the configuration ability is strong enough, perhaps based on this, it is not impossible to solve most of the front-end development work.

2, according to the user professional points

From designer development to final use, involving users in different roles:

  1. Designer developer: ensure designer independence and business decoupling, pay attention to underlying capabilities, versatility and flexibility of designer
  2. Component developer: General component, business component development. Focus on component utility, business customization, and so on
  3. Configurator: add, drag and drop configuration, publish, etc. Focus on configuration difficulty, flexibility, and component richness.
  4. End user: Use the final published page. Pay attention to the user experience, whether it opens quickly, whether the function is normal, etc

In terms of configuration difficulty, visualization tools usually have the following types:

  • NoCode: As the name implies, no coding capability is required, such as operation activity configuration, user personalized home page, process forms, business reports, etc. Components often need to be customized for a particular scenario
  • LowCode: Most of the interface and functionality can be configured visually, but full functionality requires a small amount of code. Such as custom form association, form submission logic, etc.
  • ProCode: Professional front-end code capability is required, corresponding to traditional r&d. It is characterized by long interaction cycle and high r&d cost

You can take a look at “Visual Building Tools and pages”.

As you can see, LowCode, NoCode, and ProCode all implement the final page (blue). ProCode is the most powerful and can realize all the scene functions, as well as LowCode and NoCode platforms or tools themselves

3. According to typical interaction

  • Form interaction: involves form verification, linkage, submission, value echo, etc
  • Display page: less or no user input, mainly for display, some personalized configuration. Such as business reports, user personalized homepage, operation activities and so on.

The above categories visual configuration tools in different ways, not necessarily accurate, but generally covered. Starting from technology, combining characteristics and demands, how to realize such a universal tool is a problem worth exploring.

Second, problem exploration

The following is a brief list of some form problems, custom appeals, common ability of three typical problems

  • The form issue
  1. Form validation, form rule definition exploration and how to customize rules?
  2. Form linkage. How are fields in a form linked? How to change values or trigger events outside the form? How do out-of-form events correlate with in-form components?
  • Custom appeal
  1. Custom components, how to customize a common component? How do I customize container components? Redevelop or extend the component configuration if the basic configuration is not met?
  2. Custom designers, when designers are embedded in business systems, what open capabilities should designers have to achieve low-cost, seamless connectivity?
  • General ability
  1. Internationalization, designer internationalization, translation expectation management
  2. Custom styles
  3. PC and H5 are configured simultaneously

These are just a few of the typical problems you might encounter when providing power in the form of tools, but of course there are far more problems, and upgrading to a platform involves many more. Space is limited. The following focuses on the typical problems of the form scenario, leaving the rest for further exploration.

1. What parts should a typical component have

Take the multicast graph component as an example, users with different professional levels want to configure different attributes.

  • For NoCode users, you may only need to configure the following properties: number of multicast images, drag to add images, configure image jump links, enter the multicast time interval, select the animation of the multicast switch, etc
  • In addition to the above configuration, LowCode users can also configure the image upload interface, request mode, upload request parameters, interface return conversion script, etc., which makes it more reusable and difficult to use.

The end result is the same, but the configuration is different. Is it possible to make a component in this case? Personally, I think it is possible, for example, to put more property configuration in the advanced level, or to make components inherit from each other, etc.

So what parts should a component have?

As you can see from the examples, you need a final presentation section first, a configuration section second, and you need to define configuration items. The final section shown here is called View, the configuration section is called Setting, and the definition configuration is called Schema. The relationship is roughly as follows:

Setting and View are associated with Schema. After Schema is instantiated, json data can be saved to the server. The Setting form modifies the Schema. Schema changes affect View changes.

2. Typical problems of form scenarios

1) Form verification

Form rule definition exploration and how to customize rules?

From the view of the mainstream component library, without considering the linkage verification rules, the input box is more complicated than the drop-down box, radio, time and other components. The latter only needs to make a choice, generally add a mandatory rule can be, while the former in addition to mandatory, there are special verification of characters. Components that can be entered by users are generally more complex in their rules than components that provide options.

Form components generally have at least one rule, such as mandatory, but there are exceptions, such as switch components, for which the true or false mandatory is meaningless

Therefore, the required field can be defined in the component schema to indicate that it is mandatory, for example:

{
  "name": "firstName"."required": true."errorMessage": "This is a required field."
}
Copy the code

This does not seem to be a problem for components that require only mandatory rules. However, a component often has multiple rules that take effect at the same time. For example, if the field is required to be filled in, the corresponding error message can be configured, and the string length is limited. If the string length is too long or too short, the corresponding error message can be displayed. This definition is less satisfying, so you can upgrade it:

{
  "name": "firstName"."rules": [{"required": true."message": "This is a required field." },
    { "min": 3."message": "The minimum length cannot be less than 3." },
    { "max": 10."message": "Maximum length cannot exceed 10"}}]Copy the code

This makes it much clearer and supports multiple rule combinations simultaneously. This is also the form validation Async-Validator that the mainstream UI component libraries use. The rules field should be consistent with the Async-Validator field so that third-party libraries can be used to validate rules.

Because forms have one mandatory rule, you can specify the first rule in the rules field as mandatory, and other rules can be dynamically added by configuration personnel based on actual conditions.

Note that each rule field type in schema.rules does not correspond exactly to the Async-Validator. The reason is that our schema will be stored locally or as JSON on the server, so special fields such as custom validators or regulars must be converted to the corresponding string.

  • async-validatorField rule Description:
{
  "type": "string"."validator": (rule, value) = > value === 'test'."message": "Please enter test"
}
Copy the code
  • schema.rulesDescription of a single rule in
{
  "type": "string"."validator": "(rule, value) => value === 'test'"."message": "Please enter test"
}
Copy the code

Therefore, the bottom layer of the designer needs to provide resolution modules (rules) for form rules. This is only for the implementation rule level. For the configuration level, it is a bit difficult for the configuration staff to write this code, but it is necessary to provide a visual way to select or simply fill in the code, as shown below:

Common rules can be built into the designer bottom layer. In actual services, complex custom rules or asynchronous verification may occur. Then:

How can you configure rules and extend rules according to different business scenarios?

This is where the designer’s ability to extend form rules is required. One possibility is to implement the rules directly from a script at configuration time, only for front-end development. The second is component development, which is to develop the rules in advance, then expand the rules when creating the designer, and finally select the rules when configuring them. The second implementation is discussed here.

  • Example of implementing mobile phone number rules
// ./PhoneRule.js
export default class PhoneRule {
  static get type () {
    return 'phone'
  }
  static get name () {
    return 'Mobile phone Number'  // For visual display
  }
  constructor (rule = {}) {
    const defaultRule = {
      type: 'pattern'.pattern: ' '.message: 'Incorrect mobile number'
    }
    this.origin = Object.assign({}, defaultRule, rule)
    this.rule = {
      type: 'pattern'.trigger: 'blur'.pattern: /^1[3-9]\d{9}$/g,
      message: ' '
    }
    this.update(this.origin)
  }

  update (rule) {
    if (rule) {
      this.rule.message = rule.message
      Object.assign(this.origin, rule)
    }
  }
}

Copy the code
  • Apply rules and pass rule examples
import { Rule } from 'epage-core'
import PhoneRule from './PhoneRule.js'

Rule.set({ PhoneRule })
// Application rule: The type static property of PhoneRule corresponds to phone
helper.setValidators(widgets, { input: ['phone']})// Pass in the rule
new Epage({
  Rule,
  // ...
})
Copy the code
  • The final configurationinputComponent, you can see the increaseMobile phone no.The rules

2) Form linkage

Here is a personal definition of linkage

Form linkage generally refers to the interaction in which the values or attributes of one or more form fields change and the values or attributes of other form fields change.

There are a few key points: one or more form fields, values or attributes, changes.

I. Linkage example

For example, it can be any linkage relationship as follows:

  • One to one:
No. Affect the field Relationship between value Affected field attribute
1 city Belong to China –> The school Optional school
  • A couple more:
No. Affect the field Relationship between value Affected field attribute
1 city Belong to China –> The school Optional school
professional Optional professional
  • For one more:
No. Affect the field Relationship between value Affected field attribute
1 city Belong to China –> The school Optional school
2 School enrollments Is greater than 10000

The relationship between 1 and 2 May be and may be or

  • Many-to-many:
No. Affect the field Relationship between value Affected field attribute
1 city Belong to China –> The school Optional school
2 School enrollments Is greater than 10000 professional Optional professional

The relationship between 1 and 2 May be and may be or

Note:

  • It may be between multiple impact fieldsandMay also beorRelationship between
  • The impact field canIs equal to the,Belong toEqual number relations and value establishment conditions
  • Generally, the affected fields do not existandwithorThe relationship between
  • Multi-level association, for exampleaField effectbFields,bField effectcFields can be configured through multiple two-level associations

The above is based on the impact field perspective. Of course, the association can also be considered from the perspective of the affected field, which is more intuitive in some cases, such as:

{
  "widget": "input"."name": "c"."hidden": "$a.hidden === false && $b.hiden === true"
}
Copy the code

The above schema description has the following disadvantages:

1. Causes hidden, which is a Boolean type, to become a string expression. 2. If hidden is a string field, how do you distinguish between a concrete value and an expression? Of course, it can also be used in the extended field. 3. The attribute logic of different fields is scattered, which is not convenient for unified management

In the above example linkage, the influence field triggers the linkage logic by changing its own form value. The values here can be equal, inclusive, less than, and so on, depending on the value type. Such as:

  • BooleanCan beIs equal to the,Is not equal to
  • stringCan beIs equal to the,Is not equal to,contains,Does not contain
  • digitalCan beIs equal to the,Is not equal to,Is greater than,Less than,Greater than or equal to,Less than or equal to

Since different form component value types may be different, they can be defined as static properties in the component’s Schema, for example:

class InputSchema extends FormSchema {}

Object.assign(InputSchema, {
  logic: {
    value: ['='.'! = '.'< >'.'> <'] // [equal to, not equal to, include, exclude]}})Copy the code

If we treat the form field as an object, the form value as a special attribute, and some common attributes, such as hidden and disabled, we will find that linkage isa logical binding between attributes. How do you listen for value changes as well as general property changes?

Value is considered a special attribute for the following reasons:

Changes to this property trigger the onchange event. The corresponding common attributes such as hidden and disabled do not exist. In theory, there should also be corresponding events of ONHidden and ONDISABLED.

If you define all the properties of a form field as reactive, you can easily be notified when any properties change. You can also implement your own subscription publishing to modify the form properties.

  • One is that after the form field attributes meet certain conditions, the linkage changes the other form field attributes, which is called hereValue linkage
  • The other is when an event occurs in the form component (e.gonchange), associated with other form field attribute changes, called hereEvent linkage

To some extent, both methods can solve the linkage of some of the same functions. For example, if the value of component A changes, it can also be regarded as the onchange event of component A

Ii. Linkage realization

The following is an example of developing a partial implementation of the EPAGE (many-to-one, many-to-many association logic is not yet implemented)

First, logical definition

Define the logical structure that should be saved on the schema. The specific logic can be set in the Schema of a single component or the outermost Schema. It can be defined in a unified place for easy management.

It mainly defines the affected components and the affected components, including linkage type, the value of the affected form components meets certain conditions, which attributes of the affected form components are linked, and what events are triggered by the affected form, etc

{
  // schema Other fields
  logics: [{"key": "kB1mKTnek".// Affects component keys
      "type": "value".// Association type, value linkage or event linkage
      "action": "=".// Value linkage is an equality relation, where different symbols are defined, symbol parsing should be provided
      "value": "show"./ / the specific value
      "effects": [        // List of affected components
        {
          "key": "kASJAJwRB".// Key of the affected component
          "properties": [{"key": "hidden"."value": true },   // The affected component is hidden
            { "key": "disabled"."value": true }  // The affected component is disabled, and other properties should also be possible]}]}Copy the code

Second, logical analysis

  • The logical management

Based on the above analysis, you should have value logic and event logic. Executes at render or preview time

import EventLogic from './EventLogic'
import ValueLogic from './ValueLogic'

class Logic {
  // Check whether the value logic configuration is valid, whether there is duplicate logic, etc
  // Return {patches, scripts} corresponding to the comparison results and possible custom scripts
  diffValueLogics(){}
  / / same as above
  diffEventLogics(){}
  // Based on the above comparison results, finally modify the component Schema attribute
  applyPatches(){}
  // Check whether the affected component is valid
  checkEffect(){}}Copy the code
  • Example value logic part implementation

Parse the logic relationships generated above. For example, the action field in value linkage has many comparison relationships (=(equal to),! =(not equal to), >(greater than), <(less than), <>(included), etc.), take = as an example:

class ValueLogic{
  constructor () {
    this.map = {
      '=': {
        key: '='.value: 'equal to'.// Left and right are both strings, and valueType is the correct data type
        // If the left and right value types are inconsistent with valueType, the values are converted and compared according to the actual situation
        validator: (left, right, { valueType }) = > {
          const booleanMap = { true: true.false: false }
          let leftValue = left
          let rightValue = right

          if (valueType === 'number') {
            leftValue = parseFloat(left)
            rightValue = parseFloat(right)

            return (isNaN(leftValue) || isNaN(leftValue)) ? false : leftValue === rightValue
          } else if (valueType === 'boolean') {
            if (right in booleanMap) {
              rightValue = booleanMap[right]
            }
          }
          return leftValue === rightValue
        }
      },
      // ...}}}Copy the code

To make the designer more versatile, logical relationship definition and resolution should also support component developer extension.

Some implementations of specific value Logic or event Logic can be referred to page#Logic

Third, summary

It’s not hard to create a visual configuration tool, but it’s not easy to make it universal, extensible, and standardized. It is necessary to establish a unified Schema or DSL that different developers can agree on, and can be extended and customized as needed to achieve the business delivery goals quickly.

Portal:

  • epage
  • awesome-lowcode

About the author Team

Drops efficiency platform front team EFE, calling on through technology continues to improve organizational effectiveness of organization’s mission, is committed to building technology ahead of the front end of the technical team, deep tillage in performance monitoring, quality control, low code configuration, document collaboration, micro front-end, webIDE, and other fields, technology direction, explore the space and the growth space is great.

We are a team full of passion and dreams, looking forward to your joining us. Those interested can contact [email protected]