8

我正在研究使用SlateProseMirror构建一个编辑器,并在使用内联元素时在插入符号位置和选择区域周围看到 Chrome 的一些奇怪行为。问题 1 如下图第一张所示。当文本光标位置在“f”后面时,插入符号显示在图像顶部。问题 2 在第二张图片中 - 选择文本会显示一个与内联元素一样高的突出显示区域。有没有办法控制这种行为,而是在文本位置显示插入符号,只突出显示文本周围的空间(即使内联图像使行高变大) 插入符号位置太高 选择区域太大

我想从 Firefox 模仿这里的行为: 在此处输入图像描述 在此处输入图像描述

示例图像是使用此处的 ProseMirror 演示生成的:https ://prosemirror.net/examples/basic/

JSBin的最小示例(感谢@Kaiido):

<div contenteditable>Test text<img src="https://upload.wikimedia.org/wikipedia/en/9/9b/Yoda_Empire_Strikes_Back.png">Testing</div>

不确定这在其他操作系统上的表现如何,但我使用的是 macOS Catalina。

4

3 回答 3

4

您可以使用 flexbox 解决选择问题。我最初尝试使用align-items: flex-end,但我得到了一些奇怪的箭头键行为。align-items: baseline似乎到目前为止工作。

图像问题很奇怪。我注意到 Chrome 对 SVG 元素的处理不同于 IMG 元素。截至目前,最新版本的 Chrome 在跳过 IMG 之前“等待”,但允许用户像跳过任何其他字符一样跳过 SVG(左箭头跳过最接近 svg 的字符)。这可能是由底层默认样式引起的,但我不知道。

我正要发布我的发现,但我意识到 Firefox 的工作方式不同。Firefox 在使用 SVG 和/或 Flexbox 时有一些非常奇怪的箭头键行为。光标移到图像上方,但仅在按下右箭头键时。

但是,Firefox 与普通的 IMG 元素一起工作得很好。

长话短说,您将不得不根据浏览器渲染不同的图像元素。

// chrome contenteditable ads spaces between spans.
// firefox does not, so you have to add them manually.
if (navigator.userAgent.indexOf("Firefox") > 0) {
  Array.from(document.querySelectorAll('#editable span')).forEach(el => {
    el.innerHTML += " "
  })
}
.flexit {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
}

span {
 display: inline-block;
 white-space: pre;
}

.img-wrapper, .img-wrapper + span {
display: inline;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <h1>chrome</h1>
  <div contenteditable="true" class="flexit">
    <span>test</span><svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">       
  <image href="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200" width="200"/>
    </svg><span>Here</span><span>is</span><span>a</span><span>longer</span><span>sentence.</span><span>Notice</span><span>I</span><span>wrapped</span><span>each</span><span>word</span><span>in</span><span>a</span><span>span.</span><span>This</span><span>makes</span><span>the</span><span>text</span><span>appear</span><span>like</span><span>it</span><span>is</span><span>inline.</span>
  </div>

  <h1>firefox</h1>
  <div contenteditable="true" id="editable">
    <span>test</span><span class="img-wrapper"><img src="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200" width="200" /></span><span>test</span><span>Here</span><span>is</span><span>a</span><span>longer</span><span>sentence.</span><span>Notice</span><span>I</span><span>wrapped</span><span>each</span><span>word</span><span>in</span><span>a</span><span>span.</span><span>This</span><span>makes</span><span>the</span><span>text</span><span>appear</span><span>like</span><span>it</span><span>is</span><span>inline.</span>


  </div>
</body>

</html>

PS 我使用的很多编辑器默认为全角图像。

编辑:我刚刚意识到我的 Firefox 解决方案似乎也适用于最新的 Chrome。我认为这很有效,因为我将文本节点包装在 SPAN 元素中。SVG 元素在 Chrome 中的工作方式仍然不同,但在 SPAN 中换行似乎可以解决大部分问题。

于 2020-04-25T06:26:51.803 回答
1

首先,不要像 JQuery 示例中所示操作 ProseMirror DOM。事实上,您很可能会遇到 DOM 或内容问题。ProseMirror 使用自己的 DOM 节点和标记模式。如果您想操作 ProseMirror DOM 或添加插件,请查看标记、插件和节点 API。我附上了一个文本对齐标记代码的简单示例。旁注,Grammarly 和其他人没有 ProseMirror 插件的原因是因为 DOM 方法/模型。我应该补充一下 ProseMirror 非常好,但老实说它更像是一个高级开发人员解决方案。

除此之外,好消息是你有一个纯 CSS 的问题。ProseMirror 删除所有类并重置 DOM / CSS,因此如果您导入文档或剪切和粘贴所有/大多数类,您的类将消失。

解决这个问题的最简单方法是将编辑器包装在 div 中并为 div 分配一个类,然后向该类添加样式和子样式。包装它的原因是诸如 img、p、h 等 css 选择器将仅适用于编辑器类内部的标签。否则,您最终会出现明显的 CSS 冲突。

CSS

  1. 不要将 flexbox 用于内联图像,因为 flexbox 不是网格系统。事实上,如果我记得你不能内联 flex 容器的直接子级。
  2. p 标签和 img 上的 inline 不会换行文本,您最终会遇到上面列出的问题。
  3. 如果您想真正包装并删除您拥有的光标问题,那么您需要使用浮点数,例如float: left;(推荐的方法)
  4. 添加小的或大的填充和边框框以帮助折叠边缘,还有助于分离图像和文本
  5. 您遇到的光标问题是因为当您在图像块内时它垂直对齐到顶部,您可以使用vertical-align: baseline;但没有浮动来修复它,您仍然会有一个与图像高度而不是文本匹配的光标。此外,如果您不使用浮点数,则光标将被拉长,因为行高实际上与图像的高度相同。蓝色只是选择器,您也可以使用 CSS 进行更改。
<html>
    <div class="editor">
        <!--        <editor></editor>-->
    </div>
</html>

<style>
    .editor {
        position: relative;
        display: block;
        padding: 10px;
    }

    .editor p {
        font-weight: 400;
        font-size: 1rem;
        font-family: Roboto, Arial, serif;
        color: #777777;
        display: inline;
        vertical-align: baseline;
    }

    .editor img {
        width: 50px;
        float: left;
        padding: 20px;
    }

</style>

节点扩展示例

可以添加为工具栏的文本对齐节点扩展示例。更长的帖子,但即使你确实为图像创建了一个节点/插件,你也必须处理它的呈现方式,即 base64 与 url 等。顺便说一句,这对于他们为什么这样做是很有意义的,但只需添加对寻找 SEO 等的开发人员的复杂性。

export default class Paragraph extends Node {
    get name() {
        return 'paragraph';
    }

    get defaultOptions() {
        return {
            textAlign: ['left', 'center', 'right'],
        }
    }

    inputRules({ type }) {
        return [
            markInputRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)$/, type),
        ]
    }

    get schema() {
        return {
            attrs: {
                textAlign: {
                    default: 'left'
                }
            },
            content: 'inline*',
            group: 'block',
            draggable: false,
            inclusive: false,
            defining : true,
            parseDOM: [
                {
                    tag: 'p',
                    style: 'text-align',
                    getAttrs: value => value
                }
            ],

            toDOM: (node) => [ 'p', {
                style: 'text-align:' + node.attrs.textAlign,
                class: `type--base type--std text-` + node.attrs.textAlign
            }, 0 ]

        };
    }

    commands ({ type }) {
        return (attrs) => updateMark(type, attrs)
    }
}

于 2020-04-26T09:48:42.830 回答
-2

我试着用 HTML 和 css 做一些小技巧。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>

<div contenteditable><p class="new1" contenteditable>Hello</p><div contenteditable> 
<img src="https://upload.wikimedia.org/wikipedia/en/9/9b/Yoda_Empire_Strikes_Back.png"></div> 
<p class="new2">Testing</p>
</div>
</body>
</html>

//css

.new2{


font-size:30px;
margin-top:-35px;
margin-left:252px;
padding-left:79px;
}


img{
margin-left:75px;
padding-left:5px;
padding-right:5px;
margin-top:-300px;
}

.new1{
text-overflow:hidden;
padding-top:260px;
margin-bottom:-20px;
font-size:30px;
padding-right:10px;
}

这是 jsfiddle https://jsfiddle.net/wtekxavm/1/

于 2020-04-25T08:20:15.107 回答