Recently received news, Github open source project github.com/wangeditor-… In the recruitment team, as a front-end development pupil for many years ready to move, so decisively signed up. So how do you build a Web rich text editor from scratch? Aman takes you into science……

First of all, to develop a rich text editor, we need to understand the knowledge points needed by the rich text editor. This article is based on Webpack +typescript development, the preliminary preparations are as follows:

  1. webpack www.webpackjs.com/concepts/
  2. typescript www.tslang.cn/
  3. Sass sass.bootcss.com/documentati…
  4. Document. ExecCommand developer.mozilla.org/zh-CN/docs/…
  5. Selection developer.mozilla.org/en-US/docs/…

Project Address of this articleGithub.com/lnimpossibl…

Body:

1. Create a directory lnEditor

Initialize package.json

npm init

3. Install dependencies

npm install webpack webpack-cli webpack-dev-server

npm install ts-loader source-map-loader

npm install css-loader node-sass sass-loader

4. The project structure is as follows

dist--

--index.html (Project entry)

--bundle.js (packaged file)

src--

-- Plugin (store JS plugins, such as color selection)

--styles (stores style documents.scss)

--index.ts (Script main entry)

5. Webpack.config. js is configured as follows

const path = require('path');

module.exports = {

entry: "./src/index.ts",

output: {

path: path.resolve(__dirname, 'dist'),

filename: 'bundle.js'

},

// Enable sourcemaps for debugging webpack's output.

devtool: "source-map",

resolve: {

// Add `.ts` and `.tsx` as a resolvable extension.

extensions: [".ts", ".tsx", ".js"]

},

// Create a new development server and refresh the browser automatically when the code is updated.

devServer: {

contentBase: path.join(__dirname, "dist"),

compress: true,

port: 9000

}, // module.loaders is the most critical piece of configuration. It tells WebPack what loader to use for each type of file:

module: {

rules: [

// Parse the.css file

{

test: /\.scss$/,

use: [{

Loader: "style-loader" // generate JS string into style node

}, {

Loader: "csS-loader" // convert CSS to CommonJS module

}, {

Loader: "sass-loader" // Compiles Sass to CSS

}]

}, { test: /\.js$/, loader: "source-map-loader" },

{ test: /\.tsx? $/, loader: "ts-loader" },

]

},

// Other solution configurations

Resolve: {extensions: ['.ts', '.js', '.html', '.css', '.scss'], //

Alias: {// Module alias definition

"@": path.join(__dirname, "src")

},

}

// Other options...

};

6. Core code

1. Package Document. ExecComman as follows:

const exec = (command: string, value: any = null) => {
  document.execCommand(command, false, value);
};
  1. Rich text editor top button data
const actions = {
  bold: {
    icon: 'B',
    title: 'Bold',
    result: () => exec('bold')
  },
  italic: {
    icon: 'I', title: 'Italic', result: () => exec('italic') }, underline: { icon: 'U', title: 'Underline', result: () = > exec (' underline ')}, link: {icon: '🔗, title:' the link, the result: () => { const url = window.prompt('Enter the link URL') if (url) exec('createLink', url) } }, color: { icon: '', title: 'color, the result: () = > {/ / exec (' foreColor', 'red') (because of the color selection is not a simple click event, it is necessary to change the color board when operating the exec)}} / /... others button } for (let k in actions) { const v: any = actions[k]; // Create a new button element const button = document.createElement('button') // add CSS styles to the button // Assign the result attribute to the button as the click event button.onclick = v.ult // Add the created button to the toolbar actionbar.appendChild(button)}

7. Color picker jsColor

Github.com/EastDesire/…

const myPicker: void = new wid.jscolor('#colorButton', { onChange: function () { const rgba: String = this.torgBaString () // Change the color of the text exec('foreColor', rgba)}})

8. Supplement: Click the outer margin, and then click the top button, you can still edit the last selected text

Here’s the idea:

  1. Determine if range is selected in Selection before execCommand is executed. If not, use the last range
  2. Add the onMouseleave event to the editor and save lastRange every time you leave as long as there is a selected range
  3. The offset from isCollapsed is not the same as that from the end, so false indicates that the collapsed has been selected

Specific code

let lastRange: any = null document.getElementById("inputBody").onmouseleave = function() { var selObj = window.getSelection(); If (selobj. isCollapsed === false) {var range = selobj. getRangeAt(0);  Range lastRange = Range}} const exec = (command: string, value: string | null = null) => { var selObj = window.getSelection(); Selobj. isCollapsed === true {selobj. removeAllRanges() // Range selobj. addRange(lastRange)}  document.execCommand(command, false, value); };

A simple rich text editor is done here. Project Address of this articleGithub.com/lnimpossibl…