一个偶然的机会知道了一些关于富文本编辑器是如何实现的,就来落地一下,自己鼓捣一下,试试写一个最简单的富文本编辑器,说干就干,走起~
题外话:本人是一名应届毕业生,最近也在进行如火如荼的秋招面试,面试中有一个体会就是,原来大厂不怎么care你会不会使用框架(Vue、React等),相反非常注重基础,面试题虽然有涉及框架,但都是直接让说原理,甚至手写。。我自身也是熟悉框架开发,发现一只基于框架开发,好像好点傻瓜式的开发...所以在本次的demo中,不使用任何的框架,使用Typescript和Webpack进行工程构建和业务逻辑编码。
开发环境搭建
Webpack构建工程
-
npm初始化项目工程,安装webpack、webpack-cli、webpack-dev-server等依赖,安装babel、css、typescript等的loader
npm init -y npm i webpack webpack-cli --save-dev npm i webpack-dev-server --save
-
编写可维护的规范的webpack配置文件,对于可维护这个概念,就是将公共配置抽取并独立成一个模块,使用webpack的webpack-merge进行合并选项,开发环境和生产环境进行独立配置,比较基础,就不详细展开了...,需要注意的是,在配置关于
typescript
的loader时,相关配置如下:resolve: { extensions: ['.ts', '.js', '.json', '.module.css'], }, module: { rules: [ { test: /\.tsx?$/, use: [ { loader: 'ts-loader', options: { // 指定特定的ts编译配置 configFile: path.resolve(__dirname, '../tsconfig.json'), }, }, ], exclude: /node_modules/, }, ], },
Typescript环境搭建
-
首先当然是安装
typescript
以及对应的loadernpm i typescript ts-loader --save-dev
-
编写typescript的配置文件,内容如下:
{ "compilerOptions": { "target": "ES5", "module": "ES6", "noImplicitThis": false, "noImplicitAny": false, "strict": true, "importHelpers": true, "moduleResolution": "node", "experimentalDecorators": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "sourceMap": true, "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["src/**/*.ts"], "exclude": ["node_modules"] }
至此,开发环境搭建完毕---
开发
富文本编辑器的核心在于一个可编辑的div,也就是div的
contenteditable
属性为true,然后利用document.execCommand
API 实现相应的指令,比如加粗、颜色等等,最核心的问题解决了,就来设计一下组件吧:参考掘金的富文本编辑器的表现形式,我将其分为两个组件,功能栏(toolbar
)和内容区(content
),显而易见,功能栏就是上部分的功能部分,内容区就是可编辑的区域。利用ts编写两个组件。
-
对于组件,都有自己的
template
,初始化init
,以及事件处理handle
,所以将其封装成一个接口Icomponent
:export interface Icomponent { tempContainer: HTMLElement init: () => void template: () => void handle: () => void }
-
功能栏(
toolbar
):这个demo中的功能暂时写的比较简单,文字加粗、更改颜色、设置h1标题这三个功能。功能栏(toolbar
)有默认宽高,初始化时创建节点,向其中填充具体内容,最后将节点放入html中,注册鼠标事件和功能栏各个事件:- 从鼠标事件中获取当前鼠标选择的文本,将其状态保存,方便后续在功能栏的操作。
- 对于加粗和设置h1标题功能,在功能栏中是一个button,响应点击事件通过事件委托获取其id去注册其点击事件,根据id去执行对应的指令。
- 对于颜色设置功能,使用h5中input的
type="color"
设置完成,给其注册点击事件,通过事件模型获取选中的颜色,继而执行指令。 - 对于事件绑定,封装了一个通用的事件绑定函数
bindEvent
,适应事件绑定和事件委托。 - 对于组件的参数,除了宽高之外,还接收一个函数,用于将这个组件对节点传出去,方便后续其他操作。
- 对于组件的样式,也使用模块化的操作,这个在webpack中要特殊配置:将处理css的loader配置中排除component,对于component中单独处理,将其options中的module设置为true
-
内容区(
content
):相比较功能栏,内容区的较为简单,就不详细展开了。。
这个是本文所对应的代码仓库 ,可能存在代码不规范以及思维不周全的地方,欢迎大家指正!
写在最后,不知道是我思维受限制,还是说想得太简单,,总觉得自己哪里还没考虑到,欢迎大家批评和指正~