Vị trí quan tâm và chiều cao lựa chọn cho các thành phần nội tuyến trong Chrome


8

Tôi đang xem xét việc xây dựng trình chỉnh sửa với Slate hoặc ProseMirror và thấy một số hành vi lạ với Chrome xung quanh vị trí lựa chọn và vùng chọn khi sử dụng phần tử nội tuyến. Vấn đề 1 được hiển thị trong hình đầu tiên bên dưới. Khi vị trí con trỏ văn bản nằm phía sau "f", dấu mũ được hiển thị ở trên cùng của hình ảnh. Vấn đề 2 nằm ở hình ảnh thứ hai - chọn văn bản hiển thị vùng được tô sáng cao như trong phần tử được gạch chân. Có cách nào để kiểm soát hành vi này và thay vào đó hãy hiển thị dấu mũ ở vị trí của văn bản và chỉ làm nổi bật không gian xung quanh văn bản (ngay cả khi hình ảnh nội tuyến đang làm cho chiều cao của dòng lớn hơn) vị trí caret quá cao vùng chọn quá lớn

Tôi muốn bắt chước hành vi ở đây, từ firefox: nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Hình ảnh ví dụ được tạo ra bằng bản demo ProseMirror tại đây: https://prosemirror.net/examples/basic/

Một ví dụ tối thiểu (cảm ơn @Kaiido) với JSBin :

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

Không chắc cách thức hoạt động trên các hệ điều hành khác, nhưng tôi đang sử dụng macOS Catalina.


2
... Bạn có thể tạo một ví dụ tái tạo tối thiểu chỉ với <div contenteditable>Test text<img src="https://upload.wikimedia.org/wikipedia/en/9/9b/Yoda_Empire_Strikes_Back.png">Testing</div>. Bây giờ, đó là cách họ làm điều đó, hiện tại không có thông số kỹ thuật nào xung quanh đó, vì vậy họ khá tự do để làm những gì họ nghĩ là tốt nhất. Bạn có thực sự cần những thư viện này, hoặc một giải pháp thô là đủ cho bạn?
Kaiido

1
Chỉ là một nhận xét: TinyMCE dường như hoạt động khá giống nhau trong Chrome, ngoại trừ việc nó kéo dài dấu mũ đến chiều cao hình ảnh.
V.Volkov

cảm ơn @Kaiido, sẽ bao gồm trong câu hỏi.
mowwwalker

Tôi nghĩ nó liên quan đến os. Tôi thấy hành vi tương tự @ V.Volkov vừa được mô tả bằng chrome trên mac.
Dekel

Câu trả lời:


4

Bạn có thể khắc phục sự cố lựa chọn bằng cách sử dụng flexbox. Ban đầu tôi đã thử sử dụng align-items: flex-endnhưng tôi nhận được một số hành vi phím mũi tên kỳ lạ. align-items: baselinedường như làm việc như bây giờ

Vấn đề hình ảnh rất lạ. Tôi nhận thấy rằng Chrome bước qua các yếu tố SVG khác với các yếu tố IMG. Đến bây giờ, phiên bản mới nhất của Chrome "chờ" trước khi bỏ qua IMG, nhưng cho phép người dùng bỏ qua một SVG giống như bất kỳ nhân vật nào khác (mũi tên trái bỏ qua ký tự gần nhất với Svg). Điều này có thể được gây ra bởi các kiểu mặc định cơ bản, nhưng tôi không biết.

Tôi chuẩn bị đăng những phát hiện của mình, nhưng tôi nhận ra rằng Firefox không hoạt động như vậy. Firefox có một số hành vi phím mũi tên thực sự kỳ lạ khi sử dụng SVG và / hoặc Flexbox. Con trỏ đi phía trên hình ảnh, nhưng chỉ khi nhấn phím mũi tên phải.

Tuy nhiên, Firefox chỉ hoạt động tốt với một yếu tố IMG bình thường.

Tóm lại, bạn sẽ phải kết xuất các yếu tố hình ảnh khác nhau dựa trên trình duyệt.

// 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 Rất nhiều trình chỉnh sửa tôi đã sử dụng mặc định cho hình ảnh toàn chiều rộng.

Chỉnh sửa: Tôi mới nhận ra rằng nó xuất hiện giải pháp Firefox của tôi cũng hoạt động trong Chrome mới nhất. Tôi nghĩ rằng điều này hoạt động bởi vì tôi bọc các nút văn bản trong các yếu tố SPAN. Phần tử SVG vẫn hoạt động khác nhau trong Chrome, nhưng gói văn bản trong SPAN dường như giải quyết hầu hết các vấn đề.


Công việc tuyệt vời !! Xây dựng ra điều đó, tôi đã cố gắng đặt svg trong một spanvới contenteditable="false"và điều đó dường như làm việc trên chrome và firefox! jsbin.com/xosasuruni/edit?html,output
mowwwalker

À tôi không nghĩ display: flex sẽ hoạt động vì bây giờ văn bản trong mỗi thành phần không phải là một phần của cùng một dòng. Nếu văn bản trong bất kỳ thành phần nào quá dài, nó không đẩy văn bản khác, nó sẽ chuyển sang dòng tiếp theo
mowwwalker

@mowwwalker bạn có thể tạo các phần tử bao bọc cho dòng tiếp theo sử dụngflex-wrap: wrap;
wizardzeb

0

Đầu tiên, đừng thao túng DOM ProseMirror như trong ví dụ JQuery. Trong thực tế, rất có thể bạn sẽ gặp vấn đề về DOM hoặc nội dung. ProseMirror sử dụng lược đồ đánh dấu và nút DOM riêng. Nếu bạn muốn thao tác với ProseMirror DOM hoặc thêm plugin thì hãy xem Markup, Plugin & Node Apis. Ive đính kèm một ví dụ đơn giản về căn chỉnh mã Markup. Lưu ý bên lề, lý do Grammarly và những người khác không có plugin ProseMirror là do cách tiếp cận / mô hình DOM. Tôi nên thêm ProseMirror là rất tốt, nhưng thành thật mà nói, nó là một giải pháp phát triển tiên tiến hơn.

Ngoài ra, tin tốt là các vấn đề bạn có CSS ​​hoàn toàn. ProseMirror loại bỏ tất cả các lớp và đặt lại DOM / CSS để nếu bạn nhập tài liệu hoặc cắt và dán tất cả / hầu hết các lớp của bạn sẽ biến mất.

Cách tiếp cận đơn giản nhất để giải quyết đó là bọc trình soạn thảo trong div và gán một lớp cho div sau đó thêm kiểu và kiểu con vào lớp đó. Lý do để gói nó là các bộ chọn css như img, p, h, v.v. sẽ chỉ áp dụng cho các thẻ bên trong lớp trình soạn thảo. Không có điều đó, bạn kết thúc với các xung đột CSS rõ ràng.

CSS

  1. Không sử dụng flexbox cho hình ảnh nội tuyến vì flexbox không phải là một hệ thống lưới. Trong thực tế, nếu tôi nhớ bạn không thể nội tuyến trực tiếp con của container flex.
  2. nội tuyến trên thẻ p và img sẽ không bao bọc văn bản và bạn sẽ kết thúc với các vấn đề được liệt kê ở trên.
  3. nếu bạn muốn thực sự bao bọc và loại bỏ vấn đề con trỏ của bạn thì bạn cần sử dụng float, ví dụ float: left;(phương pháp được khuyến nghị)
  4. thêm phần đệm nhỏ hoặc lớn và đóng hộp viền để giúp thu gọn các cạnh và cũng giúp phân tách hình ảnh và văn bản
  5. vấn đề con trỏ bạn gặp phải là vì khi bạn ở trong khối hình ảnh, nó được căn chỉnh theo chiều dọc lên trên cùng, mà bạn có thể khắc phục bằng vertical-align: baseline; nhưng không có hình nổi, bạn vẫn sẽ có một con trỏ khớp với chiều cao của hình ảnh chứ không phải văn bản. Ngoài ra, nếu bạn không sử dụng float, con trỏ sẽ được kéo dài vì chiều cao của đường có hiệu quả tương đương với chiều cao của hình ảnh. Màu xanh chỉ là bộ chọn, bạn cũng thay đổi bằng 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>

Ví dụ mở rộng nút

Ví dụ về phần mở rộng Node cho căn chỉnh văn bản có thể được thêm dưới dạng thanh công cụ. Bài đăng dài hơn nhiều, nhưng ngay cả khi bạn đã tạo Node / plugin cho hình ảnh, bạn phải xử lý theo cách mà nó hiển thị, ví dụ như base64 so với url, v.v. btw, có ý nghĩa hoàn hảo về lý do tại sao họ làm vậy, nhưng chỉ cần thêm sự phức tạp đối với các nhà phát triển đang tìm kiếm SEO, v.v.

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)
    }
}

-2

Tôi đã cố gắng thực hiện một chút hack với HTML và 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;
}

Đây là jsfiddle https://jsfiddle.net/wtekxavm/1/


Hmm, không thực sự giải quyết vấn đề vì nó chỉ làm cứng định vị của các yếu tố. Ty cho câu trả lời mặc dù
mowwwalker

Hãy chấp nhận điều này như câu trả lời nếu bạn thích công việc của tôi.
Rishabh dev Tyagi

Đây là quá cứng nhắc của một cách tiếp cận là thực tế.
mowwwalker

Hãy bỏ phiếu ít nhất
Rishabh dev Tyagi

1
fyi, tôi đã đánh giá thấp bởi vì đã đưa ra câu trả lời của bạn, điều này có vẻ không phải là một nỗ lực để giúp đỡ hoặc trả lời câu hỏi mà chỉ để thu hút một số upvote.
mowwwalker
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.