This article is not a technical guide to getting started. It is a record of how I learned about front-end development techniques and developed a set of tools that I use in my work.

The second version of Markdown editor

As mentioned above, it is difficult to set the font when exporting PDF from existing Markdown, so I made a Markdown editor by myself. After completing the first version and familiarizing themselves with the basics of React, we began to develop the second version for requirements.

The second version (0.2.0) of the Markdown editor supports exporting PDF and setting the editor font with the exported PDF font via CSS. When editing a document with Markdown, it is often necessary to insert images into the document. Markdown supports rendering images by filling in the image address, so it is common to upload images directly from the editor interface and insert them into the edit box, so this version also does upload images and insert them into the edit box at the cursor position. Another feature that we often see in other Markdown editors is interface hiding (hide the edit window, hide the render window), so page hiding has been added to this version.

This version of the Markdown editor is divided into four components:

  • The MD parent is used to organize the layout, and state is used to store data and pass it to the children
  • The MDEditor component contains an edit box for entering document content
  • The MDRender component contains render boxes to display the rendered HTML content
  • The MDHeader component contains buttons for various actions

The technology stack used is as follows:

  • AntD
  • axios
  • markdown-it
  • React
  • webpack

A font change

The font modification function is implemented simply by adding an input box to fill in the CSS font, listening for the Enter click event, and modifying the fontFamily in the MD component state. In the CSS style of edit box and render box, font-family is fontFamily in state.

Hidden interface

Hiding the interface is the same as changing the font. Add viewMode to the state of the MD component. The MD component changes the components needed to render according to the different viewMode.

Image upload

There is a problem that needs to be solved when the picture uploading function is implemented, that is, how to get the cursor position of the edit box. React pairs no longer manipulate DOM elements manually. How do you solve this problem? A search of the React documentation shows that you can give the component an attribute ref that holds the DOM element of the current component. However, as mentioned above, this version is split into several components. The image upload button is in the MDHeader component and the input field is in the MDEditor, so if you use the REF attribute you store the DOM element in the parent component MD and then pass it to the MDHeader. Mardkown does not have any reuse problems, and the coupling of the sub-components does not matter. So I ended up taking the no-frill approach document.getelementByid (‘shizuha-md-editor’).

After obtaining the DOM, it is how to judge the cursor position. After a bit of Google, I found the solution (with little knowledge of the front-end and no knowledge of HTML and front-end JavaScript environment), and the code is as follows:

UploadCustomRequest ({file, onSuccess, onError}) {const self = this; const data = new FormData(); data.append('file', file);
    data.append('dir'.'/shizuha');

    axios.post('http://xxx.com/upload', data)
        .then(function (res) {
            if (1 !== res.data.success) {
                onError(new Error('upload picture failed'));
                return message.error('Uploading picture failed');
            }

            onSuccess(undefined, file);
            self.setState({
                fileList: []
            });
            return self.props.insertImgToMarkdownContent(res.data.path, file.name);
        })
        .catch(function (err) {
            onError(err);
            returnmessage.error(err.message); }); } / / this code in the MD the parent component insertImgToMarkdownContent (url, name) {const mdEditorElement = document. The getElementById ('md-editor'); const insertImg = ` ! [${name}] (${url}) `
    const start = mdEditorElement.selectionStart;
    const end = mdEditorElement.selectionEnd;
    const current = start + insertImg.length;
    const markdownContent = mdEditorElement.value.slice(0, start) +
        insertImg +
        mdEditorElement.value.slice(end);
    this.handleMarkdownContentChange({
        target: {
            value: markdownContent
        }
    });
    message.success('Image address inserted into edit box');
}
Copy the code

After the image is uploaded, it passes the data to the parent component for processing, changes the content of the edit box and triggers the render box to re-render. Since Redux was not introduced at this time, learning should be gradual.

Export PDF

The PDF export function relies on Chrome’s built-in printing function, and there are some issues to consider when developing this function. Knowing that Chrome prints everything in the current HTML body, but there is more to our body than just the render box, this obviously should not be shown in an exported PDF. The solution to this problem is to replace the body content with the render box content just before the PDF is exported, and then undo it after the export.

So we add a field isPrinting in the state of the MD component. The render of the MD component determines whether isPrinting is true. If it is true, only the MDRender component is displayed, otherwise all components are displayed. The corresponding action function of the MDHeader export PDF button is to change isPrinting to true and then call window.print(). After printing, change isPrinting to false as follows:

htmlToPDF() {
    this.setState({
        isPrinting: true
    }, () => {
        window.print();
        this.setState({
            isPrinting: false
        });
    });
}
Copy the code

You can see that at this point in print, the HTML content behind it is just the content of the render box.

conclusion

This version has completed all the functions I need, but the data management in the code depends on the component props pass, the logic is complex and not easy to maintain, so the next learning is how to use the data repository Redux to achieve the management of shared data between components.

The article is too long, separate many records, unfinished to be continued.