How to design a highly extensible online web production platform

This article mainly introduces how to design a highly extensible online web page production platform, will explain some background and the final effect and the core design scheme. Experience: godspen.ymm56.com

Series Of articles

  • Opening: the correct way to open the code
  • How did Ma Liang design a highly scalable online web production platform
  • The magic brush has been opened. How can I use it

background

Began in March 2018, as the fast development, the full activities began to frequent iteration, that time is the fastest way to copy the old event project, and then according to the demand change, then online, however this way soon encountered bottleneck, forcing operations team will go to find some third party platform to meet their operational requirements, However, due to the weak customization and user information did not get through, it can not be used in large amounts, or can only wait for front-end resource scheduling, two more prominent problems.

  1. Every activity of the product requires front end personnel to intervene, and even replacing a simple icon and simple layout requires scheduling and waiting, which eats up 50% of the front end resources.
  2. Some online production promotion platform can be used on the market and the page can not be well combined with their own business process.
    • If you use a third-party platform for rotary lottery, you need to export the lottery list after the event, and then import it into your own platform for matching, and then filter the list of winners, which is very inconvenient.
    • Pull new to send red envelopes, using a third-party platform if the user has submitted a pull new phone number. Need to regularly synchronize data and then send red packets, can not be connected to their own platform real-time.

In response to these issues, the team urgently needed a platform to provide operational rapid creation activities, and development could do some extensions on the platform. It is best to meet the following requirements:

  1. Rich components provide operations that can create pages independently.
  2. Each done page can be set as a template page, providing the next operation quickly through the template to create the page simple modification and then released.
  3. Provide common animations and run activities that create cool effects.
  4. Provides complete data analysis for each activity for easy operation viewing effects, regular PV, UV, as well as custom page elements click dot and statistical functions.
  5. Provide flexible page management, convenient operation according to the group according to the project dimension to other colleagues assigned authority unified management.
  6. Developers can add scripts to components to flexibly extend the functionality of this activity for operational convenience.
  7. Provide unified component development specifications to facilitate the development of new business components and provide a more user-friendly way for operations.

In response to these requirements, we have made the Codegood platform, codegood is an online H5 editor for quick production of H5 pages. Users do not need to master complex programming techniques, through simple drag and drop, a small number of configurations can make beautiful pages, can be used in marketing scenarios page production. At the same time, it also provides developers with complete programming access ability, through the form of scripts and components to obtain powerful component behavior and interaction control ability.

The core design

The following will share our core design, this time the main focus of the following aspects

  1. We will introduce the overall architecture to understand the general idea of editing to generate pages, based on data programming.
  2. We will introduce how the core components are designed to ensure that they can be freely extended
  3. We will describe how to design the editor to achieve the control panel remarks of customizable properties. (Since the overall project implementation uses VUE, the following section will describe the specific technology implementation in terms of VUE. Self-imaginings in other frames)

The overall architecture

  1. Overall Architecture The overall architecture is relatively simple. The core of the overall architecture is to define a set of standard data specifications, provide an editor to edit the data, and provide a parser to parse the data, and then render the page, as follows.
  2. As you can see from the figure above, each page is made up of many nodes, each of which can be nested with child nodes. Each node contains the following basic information. Note that the nodeInfo mentioned later in this article refers to the following data for this node
{
  "id": "truck/button1l"."type": "truck/button"."label": "Button 1 l"."version": "0.1.4"."visible": true."style": {
      "position": "absolute"."width": "100px"."height": "40px"
  },
  "animate": []."props": {
      "text": "Input text"."type": "danger"."click": []},"path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/button/0.1.4/index.js"."script": ""."events": []}Copy the code

The core element of each component comparison consists of the following parts

  1. Id The unique number of the element. Easy code access and operation
  2. Type Indicates the type of the component. Running the loaded script creates a VUE Component, which is then mounted globally to VUE, since each Component node is a dynamic Component. At this point, you only need to change the dynamic component’s: IS data to replace the content.
  3. Label Specifies the alias of the component. Convenient operation to understand the use
  4. Version Component version. Each component has its own version.
  5. Style Component style
  6. Props component parameter. Each component has some initialization parameters that the marketer fills in the editor. These parameters are stored here and are explained in detail in the Extended Editor Properties capabilities
  7. Script Extension script. Each component can insert some script code that extends the functionality of the component. The objects created by these scripts are mixin into the component object, which is described in detail in the component design
  8. Event Indicates the event that the component binds to. Common DOM events can be bound to each component.
  9. Child Child node.
  10. Path Script path. This path is used to load scripts to create component objects.

The page above contains an image, two text below the image, and a button element in the sibling of the image. The detailed data structure of the corresponding page is shown below to get a sense of the complete structure.

{
  "id": "node"."type": "node"."visible": true."style": {},"props": {},
  "child": [{"id": "truck/image15j"."type": "truck/image"."label": "Picture 15 j"."version": "0.1.4"."visible": true."style": {
              "position": "absolute"."width": "320px"
          },
          "animate": []."props": {
              "url": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/ymm-maliang/access/ymm_1533366999689.png"."click": []},"path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/image/0.1.4/index.js"."script": ""."events": []."child": [{"id": "truck/text3l"."type": "truck/text"."label": Text "3 l"."version": "0.1.4"."visible": true."style": {
                      "position": "absolute"
                  },
                  "animate": []."props": {
                      "text": "Text Content 1"."click": []},"path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/text/0.1.4/index.js"."script": ""."events": []}, {"id": "truck/text3l5g"."type": "truck/text"."label": Text "3 l"."version": "0.1.4"."visible": true."style": {
                      "position": "absolute"."width": "114px"
                  },
                  "animate": []."props": {
                      "text": "Text Content 2"."click": []},"path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/text/0.1.4/index.js"."script": ""."events"[]}]}, {"id": "truck/button1l"."type": "truck/button"."label": "Button 1 l"."version": "0.1.4"."visible": true."style": {},"animate": []."props": {
              "text": "Input text"."type": "danger"."click": []},"path": "https://ymm-maliang.oss-cn-hangzhou.aliyuncs.com/truck/button/0.1.4/index.js"."script": ""."events": []}],"script": []."animate": []."version": "0.1.0 from"."events": []}Copy the code

A one-sentence summary: pages are generated recursively by a number of nodes, each containing information about layouts, events, scripts, parameters, versions, etc., which are then edited by an editor and parsed by a parser.

Component design

A page is composed of recursively nested components, and components are the core part of the whole project. In order to make the components have the ability to extend, we use mixin method for the functions of the components, and generate the components in the form of basic component logic + custom script. The overall component structure and initialization process are described below to help you understand how we implemented it.

  • In the left part of the figure above, you can see that the whole page is composed of nodes, which is a tree structure. Under each node, there is a component object for function display. Below is the DOM structure of node node, and you can see that each node is a recursive node and each node contains a dynamic component. Each dynamic component is rendered by a component with nodeinfo.id as the key.
<div class="node" v-show="visible"  :style="nodeInfo.style">
    <component :is="nodeInfo.id" v-bind="nodeInfo.props" :ref="nodeInfo.id" :style="componentStyle"></component>
    <node v-if="nodeInfo.child" :info="item" v-for="item in nodeInfo.child " :key="item.id"></node>
  </div>
Copy the code
  • The rendering process can be seen on the right of the image above. In order to achieve high scalability of components, the function of each component consists of two main parts
    1. Component code. Each component is a script implementation with specific parameters and specific functions, such as image, rich text, share, grid, etc. The component code loads the script to obtain the object by using the type and path parameters for.
    2. Components add scripts through an editor that dynamically adds scripts for each component to enhance the ability to operate on the component. You can see that multiple scripts can be added to a component by doing the following. Each script is essentially a VUE component, and the code inside creates mixins of objects into the final VUE component, so you can extend the functionality of the component to support your particular business.

Logical function of a node = Component logic + script 1+ Script 2+ Script 3… After each component loads the corresponding JS script according to its type, it mixins the logic in the nodeinfo.script of the component. Then create a final component and register it in Vue.com Ponent for later use. The core code is as follows

Window ['image_1.0.3'] Load the vue object generated when the component script is run
var component = Vue.extend( window['image_1. 0.3']) 
// Iterate through all the added script mixed component objects
nodeInfo.script.forEach((value) = >{
    component =component.extent(value)
})
// Register the final component object with the node ID as key
Vue.component(nodeInfo.id,component)
// Modify the dynamic component of the node: the is parameter is the id of the node
// done
Copy the code

One sentence summary: Extend component capabilities with new custom scripts coming in from mixins

Component property edit design

The main purpose of property editing is that component developers expose configurable parameters for operations to fill in and modify in the editor. For example, after selecting a component, you can set some properties of the component in the right property panel.

  1. The editor provides basic property editing
  2. Editor can provide extended editing capabilities, mainly for easy operation, characteristic development component attributes of the editing function, to provide user-friendly operation experience

The following is a description of how we do these two core contents.

Editor basic properties editing ability

For the developer of a component, one is to define which parameters the component needs to expose to the editor to operate on, and the other is to define what controls to operate on the value of the property. As mentioned in the architecture data structure above, every node has props property. This property holds the final configuration values of the component’s configurable parameters. This property is passed to the component to initialize it. The function of the editor is to get props for each object definition and then provide different editing controls based on the type of each parameter. For example, we will provide a toggle button. Image, we’ll have a control to select the image and so on. Extension scripts can also extend the editable properties of components. Here is an example of an extension script. Mainly describes the supported types, definable formats. The overall process is as follows.

Let’s look at some examples of props that each component can define.

/** ** @param type: Field type, support native type and [code good input type] ** Code good input type: * Input Single-line input box * text multi-line input box * enum List Option Field defaultList, Support array, map structure * image * audio * video * RichText * number * function method setting * Data JSON data * Date time selection * Checkbox The same as multiple boxes enum If defaultList is not provided, the value is a Boolean type. * Radio the same as enum * */

return {
  props: {
    // Native type
    foo: {
      type: String
    },
    // Image input
    fooImage: {
      type: String.editer: {
        type: 'image'}},/ / date
    fooDate: {
      editer: {
        type: 'date'}},/ / the checkbox multi-select
    fooCheckbox: {
      type: Array.// This must be Array
      default: (a)= > { // Provide an initial value
        return [] // ['day', 'hour', 'min', 'sec']
      },
      editer: {
        label: 'Display accuracy'.type: 'checkbox'.defaultList: [ // Array options
          'day'.'hour'.'min'.'sec',]}},/ / the checkbox Boolean
    fooCheckboxBool: {
      type: Boolean.// This must be Boolean
      editer: {
        type: 'checkbox'}},// enum Contains options
    fooEnum: {
      default: 'value1'.type: String.editer: {
        label: 'I am the field name'.// Displays the field name as more readable text. If this item is not provided, displays the field name
        desc: 'I'm the help text'.// Provide prompts for fields to help you understand their meanings
        type: 'enum'.defaultList: { // Map structure option key is the value, value is the display text
          'value1': Conditions of '1'.'value2': Conditions of '2'.'value3': Conditions of '3',}}},// Conditional attribute
    ifFoo1: {
      type: [Number].default: 0.editer: {
        work: function () {
          return this.fooEnum == 'value1' // This item is displayed only when the value of 'fooEnum' is 'value1'
        },
        label: 'Conditional attribute 1'.type: 'number',}},ifFoo2: {
      type: [Date.String].default: null.editer: {
        work: function () {
          return this.fooEnum == 'value2' // This item is displayed only when the value of 'fooEnum' is 'value2'
        },
        label: 'Conditional attribute 2'.type: 'date',}}},mounted: function () {
    console.log('hello ' + this.foo)
    console.log('hello ' + this.fooImage)
    // ...}}Copy the code

The added configurable properties of the components extended by the above script are shown below.

The main design here is to add an editer field to each props property to determine what component the field provides in the editor environment to edit the property. The fields of editer are as follows.

{
        
    label: 'I am the field name'.// Displays the field name as more readable text. If this item is not provided, displays the field name
    desc: 'I'm the help text'.// Provide prompts for fields to help you understand their meanings
    type: 'enum'.ignore: true.// Not displayed in the editor
    work:function(){
        // What conditions will be displayed if met
    },
    defaultList: { // Map structure option key is the value, value is the display text
     'value1': Conditions of '1'.'value2': Conditions of '2'.'value3': Conditions of '3',}}Copy the code
  1. Label Indicates the name displayed in the editor
  2. Desc This field is described in detail in the editor
  3. Type Edits the component type of the property
  4. Ignore negative slightly displayed in the editor, generally in this property provides advanced editing mode needs to hide the default mode.
  5. Work a method that returns true to display the property in the editor, once used to hide and show some edit properties in the linkage
  6. DefaultList Specifies the default values, usually available in radio or drop-down lists.

The editor gets props for each component, walks through each attribute, provides different action controls by type, and edits the resulting data onto nodeinfo.props.

Extended edit properties capability

Many times a component’s configurable properties fall into one of the following categories according to our plan.

/** ** @param type: Field type, support native type and [code good input type] ** Code good input type: * Input Single-line input box * text multi-line input box * enum List Option Field defaultList, Support array, map structure * image * audio * video * RichText * number * function method setting * Data JSON data * Date time selection * Checkbox The same as multiple boxes enum If defaultList is not provided, the value is a Boolean type. * Radio the same as enum * */
Copy the code

Providing a basic editing component per type can accomplish 90% of the requirements, but as the complexity of components increases, the properties that can be configured for each component become more varied and various requirements are possible. For example, a simple multiple selection, the original option can only write dead, now need to request their own interface to get. However, these logic cannot be implemented in the unified editor, nor in the component, so we can only provide a mechanism for the component development students to develop a component at the same time, but also to develop a custom editor for the component, which can be integrated into our property editing panel. The overall architecture is as follows, and the final effect can be seen in the custom panel section of the figure above

When a component is packaged, there are usually two necessary scripts. One is the js for the component. One is the js script for the component’s editor. The editor’s functionality extends across the platform, by loading scripts, creating objects, registering with Vue, and then rendering through dynamic components. The same goes for extensions to editor properties. The editor script for the corresponding component is loaded and then implanted in the same way. I won’t go into the details here. Here is a brief share of the results of our development of a component. The following figure

  1. Interfaces during component development
  2. What the component looks like in the code editor after it is published

Component animation display

The operation provides support for simple animations to facilitate entry and exit animations and enhance the interaction of the event, using animate. CSS. A brief demonstration is provided below

Synthetic component Thinking

Composition component is to select the existing node to save as a general component, convenient for the next direct use

  1. Using composite Components
  2. Export composite components.

The template page

The purpose of a page template is similar to that of a composite component. It is to provide content that has already been created, and operations can quickly choose to use it for the purpose of a quick launch campaign. Here is a simple demonstration

conclusion

In order to provide an operational friendly and highly scalable PLATFORM for h5 activities, we built this platform. Now the platform of Ma Lian supports Yunmanman to add 5-10 new activity pages every day. 95% of the activities with existing activity templates can be created by marketers through the template, modify some styles or pictures, and then post them online. The whole process only takes a few minutes. Activity template and component template are also constantly precipitation, I believe precipitation after a period of time as the template is more and more complete, the rapid production of marketing activities and selectivity will be stronger.

To be continued

We will continue to update the content

  1. Component Event Design
  2. Statistical design of data
  3. Open source project juejin. Im /post/684490…

In the follow-up, we will do some thinking and optimization in coordination with the marketing to share, at the same time, we are also preparing for the code of good open source, there are a lot of need to improve, hope to meet you sooner.

Authors and contributors

Wang Kun Ming Yunmanman Shanghai front-end Leader Code liang core architecture design Wei Ming yuan code liang project mainly developed Pan Aru core template contributor Liu Gang code background service code major contributor Peng Hui form, step bar and other component contributors

Contact:

Nailing group

Wechat group (QR code may expire) recommended to add the above nail group