1 introduction
Drag and drop editors are nothing new, and there are many products and open source projects available today. The author got to know the drag editor for the first time many years ago when he just learned the front end. After learning the basics of HTML and CSS, he got to know a drag editor developed by using jquery and Bootstrap, which shocked me greatly. At one point, I thought, since there is something so convenient, we need to learn the use of the front end. While this may seem like a bit of a naive thing to do at the time, a proper drag-and-drop editor can be a huge productivity boost when used properly on a project.
In the development process of the company’s Web side project, due to the unity of the output style of enterprise products and the consistency of the style of the underlying UI library, the design style of most pages (especially the middle and background pages) is very similar. Also, in the project development process, after the designer has finished the prototype/visual, the front-end developer often develops the static page first and then adds the logic up. After the project is proposed and tested, the designer also needs to track the restoration degree of the design draft, which consumes a lot of time and energy and brings a lot of communication costs to both parties. Is there a way to avoid repetitive development of static/typical pages?
Driven by the optimization of the front-end development process of the company’s projects, we designed and developed a drag editor with strong applicability and high experience, which can realize the integration of development and design of WHAT you see is what you get, and save a lot of time for the front-end staff to restore the design draft and project development. Here are the design ideas for the editor.
2 Product Positioning
Drag-and-drop editor is a project based on typical front page system of the company. It is used to change the traditional product design and development mode, reduce the cost waste in the middle link of design and page restoration, and truly achieve the integration of design and development.
In the process of use, user experience designers are the mainstream user group of the product, that is, the first user group, the main source of the core JDC of the product, and the proportion of user focus is 70%. Front-end development is the second user group of the product, and the proportion of design focus is 30%. Therefore, as far as possible in the design, under the premise of retaining the DOM element structure of the page, close to the daily work habits of designers.
3 Product Architecture
The core function of the editor is to use drag and drop or other visual editing methods to generate the static file code available in the front end. Since most of the projects and UI libraries in the front end of the company use VUE technical framework, the editor does not consider generating code results of other frameworks.
The editor project does not contain its own database and all data/code is stored as files on the company’s GitLab servers. The editor calls the Gitlab API to retrieve and store data. In order to facilitate the retrieval, pulling and use of the code in the front-end development process, the editor will save the page code in a single.vue file in the corresponding project repository of GitLab when saving the product. Also, the editor supports secondary editing by reading the Gitlab address of a.vue file via the Gitlab API to retrieve the corresponding page code.
Mentions of editor inputs and outputs have to elaborate on the concepts of components, materials, and pages.
element
Component is the smallest component unit of the page, it can be div, SPAN, IMG and other source tag elements; It can be a basic component in the UI library, such as ElementUI, el-Input, el-Button, etc. You can also customize business components, such as a layout component page-Container.
The drag and drop editor requires access to the component library. The component library is used to record and store information about all components of a page, and each component information is stored separately in a package.json file. The structure of the component library is as follows:
# element database structure. ├ ─ ─ Div │ └ ─ ─ package. The json ├ ─ ─ span │ └ ─ ─ package. The json ├ ─ ─ ElButton │ └ ─ ─ package. The json └ ─ ─ ElInput └ ─ ─ package.jsonCopy the code
Take ElButton’s package.json as an example (only some attributes are listed as examples) :
{
"name": "el-button"."label": "Button"."description": "ElementUI Components -- Buttons"."dependencies": {
"scriptUrl": "https://unpkg.com/element-ui/lib/index.js"."linkUrl": "https://unpkg.com/element-ui/lib/theme-chalk/index.css"
},
"slots": []."props": [{"name": "type"."label": "Style"."description": "Type"."type": "string"."options": [{"label": ""."value": "Default" },
{ "label": "Theme color"."value": "primary" },
{ "label": "Success (green)"."value": "success" },
{ "label": "Warning (yellow)"."value": "warning" },
{ "label": "Danger (red)"."value": "danger" },
{ "label": "Information (blue)"."value": "info" },
{ "label": "Text button"."value": "text"}]."defaultValue": ""
},
{
"name": "icon"."label": "Icon"."description": "Icon, name of an existing icon library or introduce a new icon library"."type": "string"."defaultValue": ""
},
{
"name": "disabled"."label": "Disabled or not"."description": "Disabled or not"."type": "boolean"."defaultValue": false}}]Copy the code
As you can see from json, in addition to the basic tag name and description of the component, the attributes of slots, props, and slots are also recorded. This will be covered in a later design article.
Note the Dependencies field, which contains scriptUrl and linkUrl. A common way to use a component in vUE project development is to install the component dependencies and then import the retooling. However, the editor uses umD dynamic introduction. Component can input component information in component library, scriptUrl is js file address, linkUrl is CSS file address, editor will read component library according to umD information dynamic file, and then the editor can be used normally.
material
A material is a combination of one or more components and is the drag material provided to the editor.
The story store, decoupled from the editor itself, is a repository of files hosted on the GitLab server.
# the structure of the material library. └ ─ ─ packages ├ ─ ─ base │ └ ─ ─ base element │ ├ ─ ─ div. Vue │ ├ ─ ─ span. The vue │ └ ─ ─ img. Vue └ ─ ─ component ├ ─ ─ button │ ├ ─ ─ base button. Vue │ └ ─ ─ Theme color button. Vue ├── ├─ basic. Vue ├── Basic. Vue ├── text field. VueCopy the code
An asset is a.vue file. Material files do not matter whether the code is complex, the number of internal components, as long as you want to drag as a page, reusable materials can be saved as a material file. The following two.vue files are materials:
// div.vue
<template>
<div></div>
</template>
Copy the code
Vue <template> <el-select> <el-option label=" male "value="1"></el-option> <el-option label=" female" Value = "2" > < / el - option > < el - option label = "unknown" value = "0" > < / el - option > < / el - select > < / template >Copy the code
The editor can read one or more story libraries as the base material for page drag editing. The edit page saves the edited content as material for reuse the next time you drag it (similar to the use of Sketch).
page
A page is easy to understand. It is a code product that can be provided directly to the front-end developer after the page is edited using the editor. The editor saves the page as a.vue file in the corresponding project repository on GitLab. When developing a project, front-end staff can directly pull the code of the whole project through Git Clone, or obtain the code file of a single page through the internal tools of the company to the local project, eliminating the link of static page development, which is very convenient.
We can organize the component library, material library, page library (project file library) to get the following product architecture:
4 Product Design
4.1 Effect Demonstration
Before getting into the overall design, let’s take a look at a demo of how the drag-and-drop editor works on a page.
The following is a drag editor to make a simple “Baidu” home page, in order to facilitate the demonstration, we will be some material to make good.
4.2 Design Idea
There are many visual editing tools or low Code products out there. Before designing, we researched some products available online:
- Magicalcoder is an excellent drag-and-drop editor, it has a very strong versatility, is powerful, but it is more applicable personnel product manager, the back-end development, results of output on the page style and page code iterative requirements, and can’t keep the front end staff good for secondary late edit and maintenance, custom function is weak, And the operation is slightly complicated;
- Yunfengdie is alibaba’s mobile website building platform. It can quickly build mobile pages by dragging and dropping, but the pages it builds are basically up-down flow layout, and there is no reference for the complex page building of PC.
- Flyice is also a product for building front-end applications. Flyice can install plug-ins in vscode and then drag and drop building materials and blocks. Flying ice provided some good inspiration for our early design, but our design team unanimously reported that it was too complicated to use after actually building the page with flying ice.
After summarizing some advantages and disadvantages of the products on the market and designing ideas, we made a preliminary conception of the products, and then determined the design direction after many internal reviews and discussions. This drag-and-drop editor follows the practical, easy-to-use, professional design idea, and truly creates a front-end tool that can effectively optimize the development process and improve the development efficiency.
practical
The editor’s first goal is to produce code that developers can use directly. If the output code needs to be heavily modified by the developer, it’s not a good product.
Easy to use
As the first user group of the product, designers have limited understanding of front-end knowledge, and there is a difference in understanding between designers and front-end developers (such as component attribute setting) when building a lot of structured and style-based pages. How to reduce learning cost, reduce operation complexity, improve user experience, guide users to output the correct page code is the second goal of the editor.
professional
Most products on the market can only support a basic streaming layout, so it is obvious that a company with so many middle and back pages is not suitable. The editor fully investigates the code characteristics of the company’s front-end projects and designs around the internal UI component library and layout system.
4.3 Page Design
Because the product module design involves many and complicated contents, here only introduces the design ideas of several core modules
Like many visual editing tools, the editor page is divided into actions and views.
- The action module is responsible for business interaction and information collation, and passes dragged element information to the view;
- The view module is responsible for parsing element information to generate code strings and rendering them to the page.
4.4 Drag Design
In the early stages of designing drag-and-drop editors, it is often a mistake to think that drag-and-drop is to bind a material element in the action bar to a drag-and-drop event, but it is not. The page we want to generate is a streaming layout rather than an absolute location. The view render page is rendered by code generated by the code parser, so there is no need to pass the entire material element DOM to the view module, just tell it the path of the control code snippet and where to release it. So, you’re not dragging DOM elements, you’re just dragging information.
As shown in the figure above, the editor’s left action bar displays a list of all available stories, where the stories node contains only the story’s name and the GitLab path where the code file resides. After the user drags an asset into the view and releases it, the editor retrieves the snippet based on the asset’s code file address.
Here’s a detailed explanation of how to determine which component container the dragged element falls into.
We have abstracted this design into a “position resolver”, which is divided into two parts: the artboard is a layer of manipulation over the view, where all drag-and-drop operations are done, so that features of the view components (such as mouseover events) are not negatively affected. Each view element has a unique identity, and a virtual element block is generated on the artboard. In other words, each block of virtual elements on the artboard corresponds to a component on the view. A virtual element block is a div that is absolutely positioned relative to the artboard container and has the same top, left, width, and height values as the corresponding control element. In this way, we can just bind mouse in and out events to each virtual element block to listen for drags and know which component container the user has released.
4.5 Code parsing design
After the drag is complete, the view module calls the GitLab API to get the code snippet based on the gitLab file address where the story is located, and passes it to the code parser along with the identity of the release container.
The code parser converts the incoming code snippets into AST number snippets, which are then inserted into the specified nodes according to the parent container’s identity to assemble a complete AST tree. For example, here’s what the code looks like after dragging a button into a div:
Code processing part, we selected some core processing logic.
Vue template-compiler can be used to convert vUE template strings into AST trees
import { compile, parseComponent } from 'vue-template-compiler'
let ast = {
// Suppose there is a div node here
}
// nodeMap stores global variables of all AST tree nodes as a map for easy retrieval
let nodeMap = {
// Suppose there is a div node here
}
// Code strings are converted into ast trees
function stringToAst (str) {
const parse = parseComponent(str)
const code = compile(parse.template.content)
return code.ast
}
// Recursively process the AST tree
function joinAst (node) {
if (node.type === 1) {
for (const key in node.attrsMap) {
const value = node.attrsMap[key]
if (key === 'id') {
this.nodeMap[value] = node
}
}
str += ` <${node.tag}> `
for (let i = 0; i < node.children.length; i++) {
joinAst(node.children[i])
}
str += ` < /${node.tag}> `
} else if (node.type === 3) {
str += node.text
}
}
// The AST tree is converted to a code string
function astToString (ast) {
const TMP_START = '<template>'
const TMP_END = '</template>'
let str = TMP_START
nodeMap = {}
joinAst(ast)
return str + TMP_END
}
function insertCode (code, parentId) {
const codeAst = stringToAst(code)
const parent = nodeMap[parentId]
if (parent) {
parent.children.push(codeAst)
} else {
ast = codeAst
}
return astToString(ast)
}
insertCode('< template > < el - button > confirm < / el - button > < / template >')
// => <template><div><el-button></el-button></div></template>
Copy the code
4.6 View rendering design
Once we have the code string, we parse it into SFC (single file component) and render it on the page. Here we use rollup and rollup-plugin-vue at the server layer to handle it and then return it to the client via the interface.
// app/service/dragTool.js
'use strict';
const egg = require('egg');
const tmpdir = require('os').tmpdir;
const path = require('path');
const writeFile = require('fs-extra').writeFile
const readFileSync = require('fs-extra').readFileSync
const remove = require('fs-extra').remove
const rollup = require('rollup').rollup
const VuePlugin = require('rollup-plugin-vue');
module.exports = class DragToolService extends egg.Service {
/** * Compile vue single file *@param Content Vue Single file content */
async compileSFC(content) {
const filePath = path.resolve(tmpdir(), `sfc_compile_The ${Math.random()}.vue`);
await writeFile(filePath, content);
const bundle = await rollup({
input: filePath,
external: 'vue'.onwarn: message= > {
if (message.code === 'UNUSED_EXTERNAL_IMPORT') return;
console.warn(message);
},
plugins: [
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
VuePlugin({}),
],
});
const { output } = await bundle.generate({
name: 'myComponent'.exports: 'named'.globals: {
vue: 'Vue',},format: 'commonjs'});await remove(filePath);
return output[0].code; }};Copy the code
The front-end calls the interface, sends the code string to the server, gets the returned SFC string, parses it through the Eval function, and dynamically renders the page as < Component />.
async codeRender (code) {
const { data } = await legoApi.getCompileSFC({ content }) // Call the interface
const exports = {}
eval(data)
this.activeComponent = exports.default
return Promise.resolve()
}
Copy the code
<div class="view-container">
<component :is="activeComponent" />
</div>
Copy the code
4.7 Modifying Attributes
Drag -> code parsing -> View rendering to get the basic structure of the page, but obviously that alone won’t do the job we want. When the material is finished dragging through the code parsing design, you can see that the material breaks up into individual components. Component supports selection, deletion, copying, property modification, and style modification. Most components on a page have their own properties (especially components in the UI component library), and changing these properties can affect the presentation, style, or layout structure of the page.
When we introduced the component, we mentioned that the component properties (props fields) are pre-recorded in package.json, which stores the component information. When the symbol is selected, the editor displays the property edit panel. The panel displays a form with a list of props properties for the component, which you can configure.
Taking the el-Button button component as an example, we pre-input three attributes of Type, icon and disabled, corresponding to the type, icon and whether to disable the button respectively. Now we want to change a default style button to a theme color button. In the code, we just need to add type=”primary” to the el-button tag. In the editor design process:
4.8 Modifying Styles
In the process of page making, in order to ensure the rationality of the output code, it is necessary to follow the principle of modifying attributes >> modifying styles. The modification that can be achieved by modifying attributes should not modify styles as far as possible. For example, the modification of theme color described in the previous chapter is essentially to modify the background color, border and font color of button elements. But the code that achieves the effect through attributes is what we’re looking for.
However, when making some pages with high degrees of freedom, we often change the style of the component. The editor’s style panel has a built-in style sheet that selects common CSS styles for your project. It can be roughly divided into the following four categories:
- Size layout: Width, height, Maximum width, Minimum width, Maximum height, minimum height, transform (
transform
), alignment, display (display
), float, positioning mode, offset distance, inner margin, outer margin; - Shape styles: Transparency, rounded corners, background fill, border, shadow
- Text: Font, size, weight, spacing, line height, color, alignment, decorative line, text shadow, beyond display (
overflow
) - Others: Area cursor (
cursor
)
This style sheet uses visualization, graphics, text semantics for designers to understand as much as possible, and provides some quick operations as far as possible to conform to the operation habits of designers. Margins, for example, can be graphically used to more intuitively see the effect position of the property to be changed.
The process for modifying styles is similar to that for modifying properties, except that in the code, we put the style list in
For example, if we want to set width: 600px for a div, the user can set the width item to 600px in the styles panel.
4.9 Other Functions
In addition to some of the designs described above, the editor does the following, which will not be explained in detail due to similarities with the previous design flow.
- Supports secondary drag and drop
- Supports selecting, copying, and deleting components
- Support AST tree display and node operations (copy, delete)
- You can view and operate real pages
- Support for viewing generated code
- Support for modifying text nodes
- Support for previous and next steps (undo and redo)
- Keyboard shortcuts are supported
- Supports simultaneous editing of multiple pages
- Support for rulers and grids
- Page resolution can be modified
- Support for zooming pages
- Intelligent spacing measurement is supported
- Support automatic saving against power failure
In future releases, we also hope to add more features to make development more efficient, including:
- Support for Mock data
- Supports adding pop-up boxes and prompts
- Support for simple logical processing
- Support for manual modification/adjustment of code (and rendering back to the page)
- Support interface debugging
5. Optimization of project development process
The drag-and-drop editor is positioned as a capability tool that can be packaged up into a platform. In order to facilitate the use and management of designers, we are developing an online page design platform based on the editor (no open source plan at present), supporting the output, display and secondary development of design drafts and other functions.
As the title suggests, “the design draft as code”, editor of platform is a static page to set up work shifting from the front to the designer, do interactive visual integration at the same time, reduce the workload of the designer already, also greatly saves developer time costs, the future designers to participate in the project design process into:
We plan to develop a set of vscode plug-ins that will allow front-end developers to graphically access code files directly from the project library or run the project library directly. Completely saves the static page development time, also avoids the early page restore and design draft inconsistent situation.
6 summarizes
If you are interested in how to generate pages using a visual tool platform or want to develop a drag-and-drop editor, I hope that some of the design ideas in this article will help you.
This article focuses on a drag-and-drop editor that outputs vue pages. The same approach can be used to create pages for technical frameworks like React and Angular.
We want to get smarter by collecting big data on product pages and build processes. The final implementation can generate usable static pages by reading design images or resource files. “Design draft is code”, we believe that the final product form will no longer be limited to the online visual construction platform, but can provide intelligent analysis of design draft.
7 the recruitment
We are the front end team of Hikvision, a team that can do something if you are not limited to the mechanical work day in and day out, you want to make some impact in the whole company if you are a technical person, you always feel that you lack some vision and interesting idea if you have new ideas and you want to put them into practice, Need to discuss the landing plan with your partner if you and the current job do not have to talk, then welcome you to come to us to talk about sending resume contact: [email protected]