xử lý giao lộ giữa các dấu hiệu lựa chọn


9

Tôi có một nút đánh dấu trên UI, nhấp vào đó, bất kỳ lựa chọn người dùng nào được đánh dấu màu đỏ. Không có vấn đề ở đây. Tôi đạt được điều này bằng cáchdocument.execCommand("insertHTML")

Nhưng tôi có một yêu cầu bổ sung rằng nếu lựa chọn mới được tạo là giao điểm của các đánh dấu lựa chọn cũ, thì dấu đỏ của lựa chọn cũ sẽ biến mất.

Ví dụ:

Trong hình ảnh sau đây: điều nàythử nghiệm được đánh dấu. Bây giờ nếu tôi chọn dấu của anh ấy từ dấu bắt đầu và dấu nhấp chuột, các dấu cũ của việc nàykiểm tra sẽ biến mất và chỉ có dấu của anh ấy là được đánh dấu vì có một giao lộ.

nhập mô tả hình ảnh ở đây

mã:

const button = document.getElementById("button");

button.addEventListener('click', ()=>{
	const s = window.getSelection();
  const selectionStr = s.toString();
  document.execCommand("insertHTML", false, `<span class="bg-red">${selectionStr}<span>`);
})
.bg-red {  
background: red;
}
<div contenteditable="true">
 this is testing  this is testing  this is testing
</div>

<button id="button">mark</button>

Câu trả lời:


4

Bạn có thể tìm thấy startContainer& endContainercủa văn bản đã chọn getRangeAtvà so sánh chúng với contentContainer. Và nếu chúng không bằng contentContainer, thì loại bỏ bg-redlớp.

const button = document.getElementById("button");

button.addEventListener('click', ()=>{
  let contentContainer = document.getElementById("contentContainer");
  const selection = window.getSelection();
  if (selection.rangeCount > 0){
    let startContainer =  selection.getRangeAt(0).startContainer.parentNode;
    let endContainer =  selection.getRangeAt(0).endContainer.parentNode;
    if(startContainer != contentContainer)
      startContainer.classList.remove('bg-red')
    if(endContainer != contentContainer)
      endContainer.classList.remove('bg-red')
  }
  const selectionStr = selection.toString();
  document.execCommand("insertHTML", false, `<span class="bg-red">${selectionStr}<span>`); 
})
.bg-red {  
  background: red;
}
<div id="contentContainer" contenteditable="true">
 this is testing  this is testing  this is testing
</div>

<button id="button">mark</button>


4

Nếu bạn không cần hỗ trợ IE, bạn có thể sử dụng select.containsNode : https://developer.mozilla.org/en-US/docs/Web/API/Selection/containsNode

Điều này cho phép bạn gắn cờ các nút có trong vùng chọn. Bạn cần đặt cờ partContainment thành true, vì vậy nó sẽ phát hiện các nút chỉ được chọn một phần.

Vì vậy, trong lần đầu tiên bạn gắn cờ các nút được chứa bằng cách chọn với một tên lớp cụ thể. Sau đó, bạn thực hiện execCommand để áp dụng phong cách của bạn. Sau đó, bạn đã xóa các thẻ đã được gắn cờ trước đó bằng cách đặt bên ngoàiHTML bằng các nút để innerHTML . Bạn sẽ giữ phong cách bạn vừa áp dụng, nhưng sẽ loại bỏ các kiểu trước đó. Như thế này:

const button = document.getElementById("button");

button.addEventListener('click', () => {
  const s = window.getSelection();
  const selectionStr = s.toString();

  tagIntersection(s)
  document.execCommand("insertHTML", false, `<span class="bg-red">${selectionStr}<span>`);
  removeIntersection(s)
})

function tagIntersection(s) {
  const redSpans = document.getElementsByClassName('bg-red')
  for (let i = 0; i < redSpans.length; i++) {
    if (s.containsNode(redSpans[i], true)) {
      redSpans[i].classList.add('to-remove');
    }
  }
}

function removeIntersection(s) {
  // using querySelector because getElements returns a live nodelist 
  // which is a problem when you manipulate the nodes
  const toRemovespans = document.querySelectorAll('.to-remove')
  for (let i = 0; i < toRemovespans.length; i++) {
    toRemovespans[i].outerHTML = toRemovespans[i].innerHTML;
  }
}
.bg-red {
  background: red;
}
<div contenteditable="true" id="editableDiv">
  this is testing this is testing this is testing
</div>

<button id="button">mark</button>


0

Tôi đã cố gắng phát hiện nếu 'getSelection'.anchorNode.parentNode có lớp bg-red và thay thế nó, nhưng xuất hiện quá nhiều tác dụng phụ.

Vì vậy, giải pháp với regrec ...

(* 1) - Nếu bạn kiểm tra mã của phần tử có thể chỉnh sửa nội dung, bạn sẽ thấy cấu trúc của nó: Mỗi dòng mới là một div riêng biệt. Bạn phải thay thế từng biểu tượng dòng mới\n dòng mới bằng HTML "ngắt dòng", để cho phép lựa chọn nhiều dòng.

(* 2) - Trình duyệt chèn các chỉnh sửa của riêng nó vào HTML và ngăn các thay thế chính xác. Tôi đã buộc phải chèn bất kỳ chuỗi Non-HTML nào không có khả năng xuất hiện trong văn bản. Và sau tất cả các thay thế - chèn HTML hợp lệ.

(* 3) - Tôi khuyên bạn nên phân tích tất cả các biểu thức chính quy ở đây → https://regex101.com/r/j88wc0/1 Ý tưởng chính là thay thế tất cả các lần xuất hiện kép của <span class="bg-red"> anything instead of closing span <span class="bg-red">hoặc </span> anything instead of starting span tag </span>.

Lưu ý rằng mã này làm mới tất cả bên trongHTML, mỗi lần bạn nhấn nút. Nó sẽ không hoạt động tốt với văn bản từ vài nghìn dòng)

let button = document.getElementById("button");
let block = document.getElementById("block");

button.addEventListener('click', function(){
  let s = window.getSelection();
  let str = s.toString().replace(/\n/g,'</span></div><div><span class="bg-red">'); // (*1)

  document.execCommand("insertHTML", false, `bubufication`); // (*2)

  block.innerHTML = block.innerHTML
    .replace(/bubufication/, `<span class="bg-red">${str}</span>`)
    .replace(/<span class="bg-red">(.*?)<\/span><span class="bg-red">/g,'$1<span class="bg-red">')
    .replace(/<span class="bg-red">(((?!<\/span>).)*?<span class="bg-red">)/g,"$1")
    .replace(/(<\/span>((?!<span class="bg-red">).)*)<\/span>/g,"$1"); // (*3)
});
.bg-red {
  background-color: red;
}
<div id="block" contenteditable="true">
  <div>this is testing  this is testing  this is testing</div>
  <div>this is testing  this is testing  this is testing</div>
</div>

<button id="button">mark</button>

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.