V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
wangleineo
V2EX  ›  JavaScript

请教前端达人,知乎的编辑器是怎样实现这个功能的?

  •  1
     
  •   wangleineo · 2016-02-19 13:29:05 +08:00 · 7985 次点击
    这是一个创建于 3185 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在线富文本编辑器里面,做以下操作:

    1. 选中一串文字,点击“ B ”把它加粗。
    2. 把游标移到这串文字的中间,再点“ B ”。
    3. 输入一些文字。

    在大部分其他的编辑器里面,到第二步的时候,刚才加粗的所有文字都回复了正常状态:

    • step1: some bold text
    • step2: some bold text
    • step3: some inserted text bold text

    而知乎的编辑器的效果是这样:

    • step1: some bold text
    • step2: some bold text
    • step3: some inserted text bold text

    从 HTML 上面看,它是把一个<b></b>节点拆成了三个节点:
    <b>some</b>inserted text<b>bold text</b>.

    问题是:在 contentEditable 上的编辑操作只能更新当前节点的文本内容,也就是说如果没有 js 干预,效果是这样:
    <b>some inserted text bold text</b>

    知乎的编辑器是怎样完成分拆动作的?
    监听 keypress 事件?那输入中文怎样实现?
    监听 change ?

    15 条回复    2016-02-24 19:50:56 +08:00
    morethansean
        1
    morethansean  
       2016-02-19 13:45:47 +08:00
    知呼这个不是浏览器的默认处理方式吗……
    wangleineo
        2
    wangleineo  
    OP
       2016-02-19 13:52:11 +08:00
    @morethansean 不是,浏览器本身并不知道已经取消了 Bold 样式。
    EXDestroyer
        3
    EXDestroyer  
       2016-02-19 13:55:45 +08:00
    表示 ueditor 也跟知乎一样
    wangleineo
        5
    wangleineo  
    OP
       2016-02-19 13:59:18 +08:00
    刚刚看了一下 UEditor ,行为和知乎的一样,用了一种很取巧的方法:在步骤 2 的时候,它就把原来的<b></b>分拆成两个,并在中间增加了一个不可见字符节点,<b></b>& 1234 ;<b></b>,这样,接下来插入文字就是在不可见字符的节点上插入的,是没有加粗的。

    但是知乎的编辑器不是这样做的。
    morethansean
        6
    morethansean  
       2016-02-19 14:31:49 +08:00
    @wangleineo 我用 Chrome 试了,浏览器本身的行为就是这样。你明明第二次点了 B ,浏览器怎么可能不知道呢?
    你随便找个 contenteditable 的输入框,打一串文字按 command/ctrl + b , 然后点一个中间的地方,再按下 command/ctrl + b ,然后打字,不就是你所谓的效果吗?明明按了第二次 B 取消了 bold ,为什么叫浏览器不知道呢?还是我理解有问题?

    你要是觉得自己按 bold 和 js 执行的不一样(其实就是一样的),那我给你写了个小 demo : https://jsfiddle.net/cvqzfbb2/
    wangleineo
        7
    wangleineo  
    OP
       2016-02-19 14:39:16 +08:00
    @morethansean
    理解问题,我说的 B 按钮是编辑器自己实现的控件。

    ctrl-B 实现的浏览器的 bold 状态切换, 有 javascript 的接口吗?
    morethansean
        8
    morethansean  
       2016-02-19 14:41:51 +08:00   ❤️ 1
    @wangleineo ……有啊,你看我的 demo

    都有哪些命令的话: https://w3c.github.io/editing/execCommand.html

    editing 相关: https://w3c.github.io/editing/
    wangleineo
        9
    wangleineo  
    OP
       2016-02-19 15:00:36 +08:00
    @morethansean 谢谢。
    zhihu 就是用 execCommand 实现的
    jsq2627
        10
    jsq2627  
       2016-02-19 15:09:21 +08:00
    其实非常简单的

    判断当前光标下是否为粗体
    document.queryCommandState('bold')

    切换当前光标下粗体状态
    document.execCommand('bold')
    wangleineo
        11
    wangleineo  
    OP
       2016-02-19 15:27:02 +08:00
    @morethansean
    那这样的话,写一个富文本编辑器不是很简单吗?只要用 execCommand 做命令映射就好了,所有的 DOM 变更操作都由浏览器实现好了。

    尝试做这个主要是因为看到这个问题:
    https://www.zhihu.com/question/26739121

    那些说很难做的,到底难度在哪里?
    morethansean
        12
    morethansean  
       2016-02-19 16:50:01 +08:00 via iPhone   ❤️ 1
    @wangleineo 看你的富文本编辑器有哪些功能了。如果就是那几个很基本的功能,调调 api 就能实现的那是可能比较简单。

    即便如此实际上你做的时候可能遇到各种各样奇怪的 case ,比如从外部复制粘贴过来的时候。还有就是浏览器兼容性问题。

    不过不管简单还是难,对最终数据的处理比如过滤什么的也是比较麻烦的。安全性也是很重要的呢。
    wangleineo
        13
    wangleineo  
    OP
       2016-02-19 17:13:02 +08:00
    @morethansean 同意。

    也有一些编辑器不是完全利用 execCommand 来实现编辑操作的,比如 Medium 的编辑器实现了一个自定义的 Model ,操作是对这个 Model 的修改,然后再把 Model 映射成 DOM 。

    https://medium.com/medium-eng/why-contenteditable-is-terrible-122d8a40e480#.8ew1h1af2

    W3c 的文档里提到了这篇博客,业界实践也能推动标准。
    jsq2627
        14
    jsq2627  
       2016-02-19 17:35:17 +08:00   ❤️ 1
    @wangleineo 浏览器自带的那一套主要问题是不同浏览器有不少小差异,比如剪切板 API 差异,换行处理的差异,键盘事件差异, executeCommand 行为不一致等等,要完全搞清楚这一套还是得看不少源码好好总结的。

    DOM 模型针对一个编辑器而言过于复杂了,另外 executeCommand 在不同浏览器行为略有差异,所以有些编辑器搞一个自己的文档模型,这样也好保证各种命令行为一致。

    编辑器还有一个难题,是怎么抽象一个可扩展的接口,方便扩充能力。 ckeditor 扩展做得好,生态才比较好,想要什么功能,网上都有插件。

    另外还了解过 quill.js ,开发很活跃,代码很清晰。也是自己搞的一套文档模型,很有学习价值。不过这家伙原来用 coffeescript ,一次推翻重来改用 ES6 重写,现在已经不敢在产品里用它了。。

    另外推荐 tower.im 出的 simditor ,这个是没有自己的文档模型的,但是已经很成熟了,也在不少产品中有使用( teambition 也是用的它,哈哈)。我们产品上个月刚换它,效果还不错的,也很方便自己扩展。
    minggeJS
        15
    minggeJS  
       2016-02-24 19:50:56 +08:00
    我以前写过这种编辑器,就是比较费时间,但是这东西真心不难
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2731 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 12:36 · PVG 20:36 · LAX 04:36 · JFK 07:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.