最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 基于TS + Webpack实现简易的编辑器

    正文概述 掘金(Gavin__)   2021-03-09   557

    本文主要说下如何从零实现一个简易的编辑器,从webpack环境的搭建,到编辑器的实现都会讲到。 其中会涉及到个人的一些思考和总结。感兴趣的同学可以查看本文的源码仓库:简易编辑器

    技术栈

    • webpack
    • typescript

    环境搭建

    需要装的依赖:

    npm install webpack webpack-cli typescript ts-loader css-loader style-loader clean-webpack-plugin html-webpack-plugin webpack-dev-server -D
    

    webpack 大家都很熟悉,去年发布的5版本,功能有了新的调整,具体可以看下官网:webpack中文官网

    因为该编辑器是基于ts写的,所以针对ts需要进行编译和解析。需要typescript 和 对应的ts-loader配置webpack对.ts文件解析。

    剩下的依赖想必大家都很熟悉了,就不一一介绍了。有想进一步了解的同学可以看对应依赖的npm介绍。

    依赖装完后,为了方便本地开发需要开启服务器,这里就需要用webpack-dev-serve

    创建个空文件夹,运行相应的命令初始化(npm init -y)

    在项目根目录下创建webpack.config.js, 其基本的配置如下, 根据webpack5新的功能,可以利用--config-name字段配置对应的开发或者生产环境。

    module.exports = [
      {
        ...config,
        name: 'dev',
        mode: 'development',
        devtool: "source-map",
        devServer: {
          port: 9000,
          open: true,
          hot: true,
        },
      },
      {
        ...config,
        name: 'prod',
        mode: 'production',
        output: {
          filename: './gavinEditor.js',
          path: path.resolve(__dirname, "./dist")
        },
      },
    ];
    

    调整package.json

      "scripts": {
        "dev": "webpack serve --config-name dev",
        "prod": "webpack --config-name prod"
      },
    

    具体的如何配置config, 不熟悉的同学可以看下webpack官网,比如css的解析,ts的解析等等。下面是一张我配置的截图: 基于TS + Webpack实现简易的编辑器

    到这里,基本的环境已经完成了,为了提高开发效率,我们还配置了热更新和开发环境启动服务。

    写之前的思考

    自我罗列了几个问题,分别如下:

    • 如何让一个容器可以编辑?
    • 如何获取选中的文本信息?
    • 当操作了对应的菜单时,如何响应到选择的文本上?

    带着问题去参考了wangEditor,在参考和查看资料后,上面的问题都得到了答案,接下来就是将想法用代码表达出来。

    如何让一个容器可以编辑:

    • 想要让一个容器是可编辑的状态,只要给容器设置个属性contentEditable = true。下面引用MDN文档的基本语法。
    editable = element.contentEditable
    element.contentEditable = "true"
    
    "true" 表明该元素可编辑。
    "false" 表明该元素不可编辑。
    "inherit" 表明该元素继承了其父元素的可编辑状态。
    

    如何获取选中的文本信息:

    • 获取选中的文本信息,用window.getSelection(),其返回一个Selection对象, Selection表示用户选择的文本范围或插入符号的当前位置。更加具体的说明请移步MDN。
    var selObj = window.getSelection();
    var range  = selObj.getRangeAt(0);
    
    selObj 被赋予一个 Selection对象
    range 被赋予一个 Range 对象
    

    当操作了对应的菜单时,如何响应到选中的文本上:

    • 使用document.execCommand去执行对应的命令,那相应的命令怎么来,可以有很多的方法,在本编辑器中的做法是使用标签的data-自定义属性,记录对应菜单项的命令和值。

    • 关于document.execCommanddata-不了解的可以查看MDN

    编译器部分源码实现和展示效果

    下面会讲解下部分代码的实现,完整的代码可以看这里github。

    初始化编辑器

    经过webpack打包出一个.js,页面引入之后new就行了,这里的写法参照的是wangEditor。传入一个编辑器挂载的节点。

    // 这里是打包后的部分代码,因为Editor挂到了全局,用new Editor() 创建实例
    
    <!doctype html>
    <html lang="en">
      <head>
        <title>Document</title>
        <link rel="stylesheet" href="xx.icon.com">
        <script src="./gavinEditor.js"></script>
      </head>
      <body>
        <div id="editor"></div>
    
        <script>
          const editor = new Editor('editor')
          editor.create()
        </script>
      </body>
    </html>
    

    初始化的效果图

    基于TS + Webpack实现简易的编辑器

    编辑器内部实现

    这里讲解下,编辑器内部如何实例化,然后如何去挂载。

    初始化对应的容器

    constructor(id: string) {
       const containerDom: HTMLElement = document.getElementById(id)
    
       if(!containerDom) {
           throw new Error('请传入编辑器挂载的容器id')
        }
    
        this.id = `Editor_${UNI_ID}`
        this.$containerDom = containerDom
        this.$menuDom = new Menu(this)
        this.$textDom = new Text(this)
    }
    

    调用create()发生的事情

    this.initDom(this)
    
    this.$menuDom.init()
    
    this.$textDom.init()
    
    分别是:
    初始化了编辑器的容器,设置样式等等
    初始化菜单项
    初始化编辑区
    

    缓存选区的操作 考虑到一种操作,可能是用户在选择内容后,误点击了编辑器外部的其他内容,这时用户回来想直接点击菜单进行操作。如果没有做选区的缓存,就会导致用户需要再次的选择后才能设置, 无形就增加了用户的操作工作。

    解决的办法就是,想办法缓存用户选中的内容,最简单的办法就是给编辑区绑定 鼠标弹起事件,然后利用window.getSelection获取对应的select对象,然后根据select.getRangeAt(0)获取选区内容,然后就是缓存起来。思路有了,来看下代码的实现

    public init() {
       this.initSelect()
    }
    
    public initSelect():void {
      this.TextContainer.addEventListener("mouseup", e => {
          this.editor.$rangeCache = window.getSelection().getRangeAt(0)
      })
    }
      
      在初始化编辑区,同时绑定事件, 进行缓存。
      
      this.editor.$rangeCache是定义在editor上的一个变量,用来缓存选区。
    

    缓存内容已经有了,当触发菜单项时,就需要做一些处理,先获取select对象,然后将对象的的选区内容清空用:select.removeAllRanges(),在添加被缓存起来的选区,添加使用:select.addRange(), 下面是部分实现过程:

    let select = window.getSelection()
    
    select.removeAllRanges()
    
    if (this.editor.$rangeCache) {
      select.addRange(this.editor.$rangeCache)
    }
    

    上面体现了一些编辑器的实现,关于菜单的初始化$menuDom.init()和编辑区初始化this.$textDom.init()的其他实现细节,可以详细的看下源码

    需要注意的是,菜单项根据配置生产,以及事件的绑定逻辑。

    编辑器实现效果图

    基于TS + Webpack实现简易的编辑器

    总结

    到这里,基于ts + webpack实现的简易编辑器已经有点雏形了,有感兴趣的同学可以自行去源码仓库查看,喜欢的可以点? start。


    起源地下载网 » 基于TS + Webpack实现简易的编辑器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元