background

In recent years, low code, no code, Pro code and other more and more appeared in our vision. With a no-roll mentality 🐶, I decided to explore.

I work in the Marketing Department. Every day/month carries a large number of marketing activities, this article is also my experience in the process of exploring visual construction

All of these nouns are related to construction. One of the most widely used scenarios is marketing. We know that both e-commerce giants like Taobao and JD.com and otAs like Ctrip and Qunar are hosting countless activity pages on their apps every day.

A brief overview of some characteristics of the marketing campaign:

  • Similar pages: The page layout and business logic are fixed
  • High frequency of requests: Multiple requests per week or even per day
  • Fast iteration: short development time and tight rollout time
  • Development time: Development tasks are repeated, consuming communication time and manpower of all parties

Different from regular business development, marketing activities are often affected by many factors: holiday promotion, policy rules and so on, so often may be said this morning, tomorrow will be on this activity. If only rely on the front-end students to maintain, that is not to add countless classes (such as my 😭 before)

Every time there is a new activity, it depends on the front students to draw the page, obviously this efficiency is extremely low. If the schedule is generous point ok, if encounter 618, double 11 afraid not to drive us crazy.

Floor structures,

In view of this scenario, there was a lot of internal discussion. The conclusion is that the development students provide the background of marketing construction, the page can be configured, and the configuration work is handed over to the product/operation students. In this way, building a marketing page based on the floor of the scheme came into being.

Actually,Floor structures,In the construction of the marketing page is a more common way.The above picture is an activity page of JINGdong, which is mainly composed of three parts: the floor of head picture, the floor of discount coupons and the floor of hot sales. Because just like the building in life, so in the early marketing construction, there isfloorThe concept of. Each floor corresponds to a specific component.And then on the specific floorEdit contentThe region can upload the corresponding data.

But this approach has one big drawback: it’s not intuitive. As the business iterates rapidly, some feedback is coming in. It turns out that what the operations students really need is something that can be dragged and dropped directly into a page, which is a visual build

Visual construction

On the basis of the building of the floor to further transform into a visual building, the complexity has increased a lot. Simply looking at the different renderings of the page might just be adding a drag and drop operation. But really ready to go to the landing, found that the details are particularly much, but also contains a lot of design concepts in it.

Let’s take a look at the prototype and then break down what we need to do:Most of the marketing visualization building systems on the market are basically page rendering like the picture above. The component area corresponds to the left, the canvas area is in the middle, and the properties area is on the right.

The general process is to drag the component on the left to the middle canvas, select the component, and the properties panel on the right shows the properties associated with that component. Edit the properties on the right, and the corresponding component style in the canvas is updated synchronously. After the page splicing is complete, you can preview the page by similar operations. Preview without error, you can publish the activity through the publish button.

With the process sorted out, let’s look at the infrastructure of the project:

Here I laid out the features of the project design based on the prototype, which is actually around the components, canvas and property panel.

At this point, let’s consider a few questions:

  • How does the canvas area render the components that have been added to the canvas (there are many components in the component library, you may only need to add a few components to the canvas, and consider how to do dynamic rendering)?
  • Drag a component into the canvas area from the left, select the component, and you know the properties associated with the component. How is the component Schema designed?
  • Can the rendering of the canvas area and the preview component share the same rendering logic?
  • How component data is maintained (consider adding components, removing components, component render/preview scenarios, etc.)
  • How to maintain component libraries (consider scenarios where new components meet business needs)

Let’s start with the first one, which boils down to dynamically loading components.

Dynamically loading components

If you’ve used Vue a lot, you’re familiar with the dynamic components in VUE:

<! Component changes when currentView changes --><component :is="currentView"></component>
Copy the code

Most editors on the market also take advantage of this feature, and the general idea is:

  • With an arraycomponentDataMaintain the data in the editor
  • Data for a component when you drag it onto the canvaspushInto thecomponentData
  • Editor traversal (v-forComponent datacomponentData, rendering the components into the canvas in turn

Since my team including myself have been using React all the time, I would like to highlight the implementation of dynamic loading of React components here. Umi is used as the framework.

When I implement this part of the function, inumitheapiFound in thedynamic:Encapsulate an asynchronous component:

const DynamicComponent = (type, componentsType) = > {
  return dynamic({
    loader: async function () {
      const { default: Component } = await import(
        `@/libs/${componentsType}/${type}`
      );
      return (props) = > {
        return <Component {. props} / >; }; }}); };Copy the code

Then, on the call, pass in the component array:

const Editor = memo((props) = > {
  const {
    componentData,
  } = props;
  return (
    <div>
      {componentData.map((value) => (
        <div
          key={value.id}
        >
          <DynamicComponent {. value} / >
        </div>
      ))}
    </div>
  );
});
Copy the code

With the first problem solved, let’s look at the second, which is: How should the component Schema be designed?

Component Schema Design

This involves the linkage of the component, canvas, and property area. This consists mainly of form properties that are strongly related to the component, as well as initial values.

Because of the field restrictions and validation involved in component properties, it is recommended that projects use TS for specification and error avoidance purposes

Here’s an example of a TabList component’s Schema:

const TabList = {
  formData: [{key: 'tabs'.name: 'the name of the Tab'.type: 'TitleList'}, {key: 'layout'.name: 'Layout mode'.type: 'Select'.options: [{key: 'single'.text: 'single'}, {key: 'double'.text: 'double row',},],}, {key: 'activeColor'.name: 'Activate color'.type: 'Color'}, {key: 'color'.name: 'Text Color'.type: 'Color'}, {key: 'fontSize'.name: 'Text size'.type: 'Number'],},initialData: {
    tabs: [{id: uuid(6),
        title: 'north China'.list: [{icon:
              ' '.goCity: 'yantai'.backCity: 'Beijing'.goDate: '08-18'.goWeek: 'on Wednesday'.airline: 'China United Airlines'.price: 357.disCount: '4',},],},],layout: 'single'.color: 'rgba(153,153,153,1)'.activeColor: 'rgba(0,102,204,1)'.fontSize: 16,}};Copy the code

The structure of the component is defined when it is initialized. When the component is dragged into the canvas area, we can get the data of the currently selected component, and then the properties panel on the right renders the corresponding editable form items. Look at the code in the form area on the right:

const FormEditor = (props) = > {
  const { formData, defaultValue } = props;
  console.log('FormEditor props', props);
  const [form] = Form.useForm();

  const handleFormChange = () = > {
    console.log('Form Update',form.getFieldsValue());
  };

  return (
    <Form
      form={form}
      initialValues={defaultValue}
      onValuesChange={handleFormChange}
    >
      {formData.map((item, i) => {
        return (
          <React.Fragment key={i}>
            {item.type === 'Number' && (
              <Form.Item label={item.name} name={item.key}>
                <InputNumber max={item.range && item.range[1]} / >
              </Form.Item>
            )}
            {item.type === 'Text' && (
              <Form.Item label={item.name} name={item.key}>
                <Input />
              </Form.Item>
            )}
            {item.type === 'TitleList' && (
              <Form.Item label={item.name} name={item.key}>
                <TitleList />
              </Form.Item>
            )}
            {item.type === 'Select' && (
              <Form.Item label={item.name} name={item.key}>
                <Select placeholder="Please select">
                  {item.options.map((v: any, i: number) => {
                    return (
                      <Option value={v.key} key={i}>
                        {v.text}
                      </Option>
                    );
                  })}
                </Select>
              </Form.Item>
            )}
          </React.Fragment>
        );
      })}
    </Form>
  );
};
Copy the code

The onValuesChange event is triggered when a specific form item in the form area is changed, which is the callback event that is triggered when the field values of the Ant Design form are updated. The data is then updated to the Store. The data source of the canvas is componentData in the Store and then the page will be updated in real time. Look at the overall data flow diagram:

That solves the second problem.

Moving on to the third question: can the render of the canvas area and the preview component share the same render logic?

Component sharing

We can think of the preview component as the static or snapshot version of the canvas area. There is not much difference in the rendering of the page, so in terms of code design, of course, the two parts can share a component. Let’s call this shared component renderComponent. TSX, use the data source componentData in the Store, and combine it with DynamicComponent to get the following code:

const RenderComponent = memo((props) = > {
  const {
    componentData,
  } = props;
  return (
    <>
      {componentData.map((value) => (
        <div
          key={value.id}
        >
          <DynamicComponent {. value} / >
        </div>
      ))}
    </>
  );
});
Copy the code

Data storage/distribution

As for the fourth question: how to maintain the component data (consider adding components, removing components, component rendering/preview scenarios, etc.), it has already been mentioned in the answer to the second question above. A store is maintained globally:

state:{
  // All component data added to the canvas
  componentData: [].// The currently edited component data
  curComponent: {}}reducers: {// Add components to componentData
  addComponentData(){},
  // Edit component and update componentData and curComponent
  editComponentData(){},
  // Delete the component
  delComponentData(){}}Copy the code

For large front-end projects such as visual editors, a global state management mechanism is required to store and distribute data. This is also useful for sharing and synchronizing data states.

Component development/maintenance

Let’s look at the last issue mentioned above: how the component library is maintained (consider the scenario where the new component meets the business needs).

There are two common ways to do this:

  • Directly into the project
  • Extract the NPM package to form an independent third-party component library

If it is the early stage of the project, I feel that the first method is not impossible, convenient debugging. However, in the long run, there will be no less components precipitatingout of the marketing scenario, so it is wise to extract third-party NPM packages. At the same time, it should cooperate with a management system similar to component management background to do unified management of components.

Going back to the components themselves, there must be strict development specifications. Each component is different in principle only in presentation, and the established component development specifications must be followed. As for how to restrict this, you can do it through documentation (weak) or CLI (strong).

The template

In addition to the above questions, there is one more point not mentioned: templates. We know that marketing campaigns typically feature similar pages. If operations/products students from zero to generate a page is also quite time consuming, and most of the activities fall under a category, we can draw these similar activities into a template. Creating based on a template saves a lot of time and effort. Since this part is still under development and migration, I will not elaborate on it for the time being.

At this point, I feel I have solved the most complicated parts of the visual editor implementation in the form of questions. In fact, whether it is dynamic component loading, component schema design, data structure design, component library maintenance, etc., each team can develop a set of specifications suitable for their own, there is no absolute right or wrong.

In the implementation of this editor, there are many low-level implementation details that cannot be ignored. Include:

  • Drag and drop
  • Component Layer Hierarchy
  • Zoom in/out
  • Undo/redo
  • The adsorption
  • Bind events/animations

I will not expand on these details, recommend an article: visual drag-and-drop component library technical essentials analysis. The technical points mentioned above are explained in great detail.

low code/no code/pro code

Having said all that, let’s go back to the low code/no code/pro code mentioned at the beginning of this article. I’ll illustrate all three in conjunction with our visual editor.

First, let’s look at the general flow of operations/Development students using the editor to create activities:

no code

First, a quick explanation of what no code is: literally no code, meaning no code.

From the flowchart above, it can be seen that operations/products students can build a fully functional activity page through the visual editor without writing a single line of code. This corresponds to no code.

low code

The definition of low code is low code, write less code.

In the above flowchart, more on the front end of the student development component library. You need to write part of the code, and the whole thing is generated in a drag-and-drop way. That corresponds to low code.

pro code

Pro Code is defined as pure code, that is, the development of written code without any visual tools. Before the advent of Low Code and No Code, this was the most common method of development.

In the flowchart above, this part is not represented. But in real business development, this scenario is often present. Perhaps a current marketing campaign, with complex interactions and long links, is difficult to customize through a visual editor like this one. Business needs can only be met by development to manually write code.

The visual editor is more about page development that meets similar rules, and its primary responsibility is to reduce repetitive business development

Looking forward to

So far, the construction of a marketing system to explore the evolution of the process I roughly combed through.

But this is just the beginning. This article is more of a front-end exploration, and it’s just a first step toward a visual editor, but it’s a more purely front-end project with a lot of logic left out. Here’s what to do:

  • Template market
  • The data center
  • Buried point
  • Component debugging/preview
  • The cache
  • Open API capability
  • CDN
  • Across the
  • .

❤️ Love three

1. If you think this article is good, please share, like and read it again, so that more people can see it

2. Pay attention to the public front forest, regularly push fresh dry goods for you.

3. In special stages, wear a mask and take personal protection.