大数跨境

文本编辑器的前生与今世

文本编辑器的前生与今世 秘塔科技
2018-09-04
3
导读:5分钟写一个富文本编辑器

文本编辑想必大家都不陌生,从记事本,Word,到浏览器里面的富文本编辑器(Rich Text Editor,简称RTE),都是大家在工作中和上网的时候会不断接触和使用的.


富文本之所以称之为“富”,是相较于没有复杂格式的纯文本(Plain Text)而言的.虽然目前大家对能够所见即所得(WYSIWYG,what you see is what you get)的对文本进行加粗,居中,修改字体,字号等功能习以为常,很难想象这样的功能曾经也算是技术创新,代表先进的生产力?


我们看看,在不太遥远的1991年,大家日常用的文本编辑软件WPS是这个模样:


惊不惊喜?意不意外?

从这个“古典”的界面,大家应该能感受到时代的发展了.目前哪怕是在浏览器里运行使用的在线编辑器,除了能正常编辑以外,还可以显示文字加粗、颜色、链接、嵌入的图像等更多的功能.实现了所见即所得,整个编辑界面简洁美观。


实际上整个所见即所得的编辑器发源于施乐(Xerox)公司.从上世纪80年代提出这个概念,到1981年发行 Xerox 8010 Star 附带的第一款商用所见即所得编辑器 Bravo,施乐公司都走在了时代的最前面,具有极强的先锋性(堪比赵丽华女士的诗歌).但真正将这发扬光大的,还是著名的乔布斯,以及最近市值已经迈入历史性的1.1万亿美元的苹果公司.

施乐公司Xerox 8010 Star的图形编辑界面


苹果公司1984年发行的MacWrite 1.0


历史上,之所以实现一个所见即所得的编辑器如此之困难,一方面是受限于当年的硬件能力,另一方面早期的非图形操作系统(如DOS)并未提供方便图形API,使得开发人员必须从零开始绘制每一个像素


到如今的网络时代,浏览器的功能愈发的强大,我们甚至可以将自己几乎所有的工作都放在浏览器内部完成.在现代浏览器中开发一个富文本编辑器的难度如何呢?


答案是令人惊异的简单.最核心的是对浏览器自带的 execCommand 函数的使用,目前主流浏览器都对其有所支持.


原理

在浏览器展示出来的界面上,要去给某些内容添加类似于加粗、斜体等效果时,浏览器中所显示的文档直接去调用上述函数就可以实现,即调用函数document.execCommand,而这个函数起作用是基于包含所选内容的标签自带的contentEditable属性的值等于true


举个例子,假如我有一个标签 div,我想让这个 div 标签内部的一个词语背景色为红色,完成这个功能的前提是,这个 div 标签必须是可编辑的,我们可以设置这个 div 标签的属性contentEditable="true"(其值为 bool,表示元素能被编辑),相当于此时这个 div 标签就是一个 textarea 的文本域,然后再去调用浏览器的

document.execCommand(aCommandName, aShowDefaultUI, aValueArgument) 函数,这个函数有三个参数,第一个参数为命令,例如:粗体,斜体,背景色等;第二个参数为是否展示用户界面,一般为 false;第三个参数为一些命令的额外参数,例如:insertImage 需要提供插入 image 的 url,默认值为 null。


案例


我们来看看如何采用几行代码,通过 Vue 框架来实现一个富文本编辑器.


首先是 Html 部分,创建 Vue 项目,为了方便,引入 element-ui 相关的文件,整个功能由两部分组成,一部分是按钮组,另一部分是一个可编辑的 div。

<el-button-group id="tools-wrap">
    <el-button v-for="item in tools" :key="item.index" :lable="item.name" @click="changeSelf(item)"><img :src="item.src"/></el-button>
</el-button-group>
<div contenteditable="true" id="editor" v-html="content"></div>
<!--发布文章按钮-->
<div class="seditor-footer"><el-button class="submitbtn" type="primary" @click="submitArticle">发布文章</el-button></div>



至于 CSS 样式部分,大家可根据自己的喜好去调节.下边是我简单写的样式

     #editor {
        height200px;
        border1px solid #ccc;
        padding10px;
        border-radius4px;
    }
    #editor:active#editor:focus{
        outline: none;
    }
    #tools-wrap .el-button {
        border: none;
        border-radius0px;
    }
    #tools-wrap .el-button:hover {
        background#ccc;
    }
    #tools-wrap .el-button:focus#tools-wrap .el-button:active {
        background#ccc;
    }
    #tools-wrap .el-button img {
        width20px;
    }


为了方便操作代码的书写,在 Vue 中直接定义了一个数组变量来装所有的操作:

export default {
    data () {
        return {
            content'Click to Editor...'
            tools: [
                {
                    index1,
                    name'加粗',
                    property'bold',
                    valuenull,
                    srcrequire('../../static/img/icon/bold.png')
                },
                {
                    index2,
                    name'倾斜',
                    property'italic',
                    valuenull,
                    srcrequire('../../static/img/icon/italic.png')
                },
                {
                    index3,
                    name'下划线',
                    property'underline',
                    valuenull,
                    srcrequire('../../static/img/icon/underline.png')
                },
            ]
        }
    }
}


下边才是整个富文本编辑器的关键函数,可怜的几行代码,直接调用函数,传入相应的参数即可.最后将获取到的 Html 参数传递给后台数据库,进行储存就可以啦.

methods: {
    changeSelffunction(param{
        document.execCommand(param.property, false, param.value)
    },
    submitArticlefunction({
        let editor = document.getElementById('editor')
        let html = editor.innerHTML
        document.write(html)
    }
}


这样,一个简单的富文本编辑器就出现了.是不是很简单,我们来看看最终的效果.


结语

实际上,这个富文本编辑器是一种最简单的实现,仅仅是对浏览器自带的 document.execCommand 函数进行的一层封装,所有的样式实现都调用了同一个函数.而在当今流行的富文本编辑器中,基本都是将其重写(对浏览器已有函数进行修改完成自己的需求).整个过程很繁琐和复杂,而且要兼容各个浏览器,难度会大大的提高.有兴趣的小伙伴们,来尝试一下重造轮子的成就感吧!

 • end • 

往期文章:关于机器学习的前尘往事

近20年令联合国深表遗憾的33个事件

One-shot Learning的损失函数以及背后的几何直观

招人啦

前面都是前言,这里才是正文!

我们是一个来自牛津大学、哥伦比亚大学、UIUC、北京大学等的团队.我们刚诞生不久,每一个毛孔都是新的,等着和你一起来建设.


技术产品总监

  希望你有在知名互联网/软件公司有带领技术团队完成产品开发的经验,能够有兴趣和我们一起设计AI落地的产品,切实提高行业效率.

高级前端工程师

  希望你能在前端与UI交互方面有丰富的经验与产品思维,精通JS,能与团队一起落地实用的数据产品.

机器学习工程师

  希望你对机器学习有热情有基础,对算法原理而不仅仅是调用库有所了解,希望真正作出有用的AI产品.


简历投递邮箱:hr@metasota.ai

MetaSOTA

谈谈技术,和其他

【声明】内容源于网络
0
0
秘塔科技
谈谈技术,和其他
内容 14
粉丝 0
秘塔科技 谈谈技术,和其他
总阅读32
粉丝0
内容14