为了账号安全,请及时绑定邮箱和手机立即绑定

Chrome 中内联元素的插入符位置和选择高度

Chrome 中内联元素的插入符位置和选择高度

30秒到达战场 2024-01-22 20:03:02
我正在考虑使用Slate或ProseMirror构建一个编辑器,并在使用内联元素时在插入符号位置和选择区域周围看到 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。
查看完整描述

3 回答

?
qq_笑_17

TA贡献1818条经验 获得超7个赞

您可以使用 Flexbox 解决选择问题。我最初尝试使用,align-items: flex-end但我得到了一些奇怪的箭头键行为。align-items: baseline目前看来有效。


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


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


然而,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 中换行文本似乎解决了大部分问题。


查看完整回答
反对 回复 2024-01-22
?
慕工程0101907

TA贡献1887条经验 获得超5个赞

首先,不要像 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 不是网格系统。事实上,如果我记得你不能内联弹性容器的直接子级。

  2. p 标签和 img 上的内联不会自动换行,您最终会遇到上面列出的问题。

  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)

    }

}


查看完整回答
反对 回复 2024-01-22
?
慕哥9229398

TA贡献1877条经验 获得超6个赞

我尝试用 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/


查看完整回答
反对 回复 2024-01-22
  • 3 回答
  • 0 关注
  • 43 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信