Есть ли CSS-селектор, когда каретка находится в элементе?

У меня есть contenteditable Элемент, я хочу, чтобы элементы внутри применяли стиль, когда каретка находится внутри них.

В этом примере стиль меняется на :hover:

div{
caret-color: red;
}

span:hover {
  font-weight:bold;
}
<div contenteditable="true">
  <span>Sub element one</span> 
  text node
  <span>sub element two</span>
</div>

Здесь вы можете увидеть каретку, так как я нарисовал ее красным, но над другой span:

пример проблемы

Есть ли способ применить такой стиль, но когда каретка находится внутри элемента? Так что текст в span вокруг красная линия жирная?

Решение будет выглядеть так:

стиль, следующий за каретой

Решение CSS было бы идеальным, но я бы рассмотрел решения JS, если это невозможно.

3 ответа

Решение

С CSS?

Нет, нет css селектор для этого.

С JavaScript?

Да, вы можете сделать это с JavaScript с использованием .getSelection() функция.

С .getSelection() Вы можете получить текущую позицию каретки и element каретка включена.

window.getSelection().focusNode.parentElement // Returns DOM node

window.getSelection ()

Возвращает объект Selection, представляющий диапазон текста, выбранного пользователем, или текущую позицию каретки.

https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection

Таким образом, используя эту информацию, вы можете создать функцию, которая стилизует элемент, на котором находится каретка

var ctl = document.getElementById('contenteditable');
var selection;

function styleNode() {
  // Get selection / caret position
  selection = window.getSelection();
  
  // Check if type is Caret and not Range (selection)
  if(selection.type === 'Caret')
  {
    // Remove styles       
    Array.prototype.forEach.call(selection.focusNode.parentElement.parentElement.getElementsByTagName( "span" ), child => {
      child.style.fontWeight = "normal";
    });
    
    // Only style <span> elements
    if(selection.focusNode.parentElement.tagName === 'SPAN')
    {
      // Set style on element where caret is
      selection.focusNode.parentElement.style.fontWeight = "bold";
    }
  }
}

// Removes styles on focusout
function reset() {
  Array.prototype.forEach.call(ctl.getElementsByTagName( "span" ), child => {
      child.style.fontWeight = "normal";
  });
}

ctl.addEventListener("keyup", styleNode);
ctl.addEventListener("click", styleNode);
ctl.addEventListener("focusout", reset);
<div contenteditable id="contenteditable">
  <span>This is</span> some editable <span>content</span>
</div>

Я думаю, что нужен другой подход. Поскольку редактирование требует нажатия на элемент, я бы просто настроить click обработчик событий на подэлементах для их стилизации.

// Get reference to the contenteditable element
var container = document.querySelector("[contenteditable='true']");

// Set up a click event handler for the container
container.addEventListener("click", function(evt){
  // Loop over child elements and remove the active class
  Array.prototype.slice.call(container.querySelectorAll("*")).forEach(function(el){
    el.classList.remove("active");
  });
  // Apply the active class to the clicked element
  evt.target.classList.add("active");
});
.active {
  font-weight:bold;
}
<div contenteditable="true">
  <span>Sub element one</span> 
  text node
  <span>sub element two</span>
</div>

Слушатель событийselectionchangeвесьма полезно для обнаружения изменения положения каретки (из-за мыши или клавиатуры). Он обнаруживает, что он также должен работать на мобильных устройствах при пролистывании пробела для перемещения каретки.

Другие вопросы по тегам