Typescript + HTML 实现简易版本富文本编辑器

1,076 阅读4分钟

一个偶然的机会知道了一些关于富文本编辑器是如何实现的,就来落地一下,自己鼓捣一下,试试写一个最简单的富文本编辑器,说干就干,走起~

题外话:本人是一名应届毕业生,最近也在进行如火如荼的秋招面试,面试中有一个体会就是,原来大厂不怎么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 以及对应的loader

    npm 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.execCommandAPI 实现相应的指令,比如加粗、颜色等等,最核心的问题解决了,就来设计一下组件吧:参考掘金的富文本编辑器的表现形式,我将其分为两个组件,功能栏(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):相比较功能栏,内容区的较为简单,就不详细展开了。。

这个是本文所对应的代码仓库 ,可能存在代码不规范以及思维不周全的地方,欢迎大家指正!

写在最后,不知道是我思维受限制,还是说想得太简单,,总觉得自己哪里还没考虑到,欢迎大家批评和指正~