Заполнитель в contenteditable - проблема с событием фокуса

Я пытался спросить об этом раньше, но мне не удалось объяснить / доказать рабочий пример, в котором возникает ошибка. Итак, вот еще одна попытка:

Я пытаюсь воспроизвести эффект заполнителя на содержательном DIV. Основная концепция проста:

<div contenteditable><em>Edit me</em></div>

<script>
$('div').focus(function() {
    $(this).empty();
});
</script>

Это может иногда сработать, но если заполнитель содержит HTML, или если выполняется какая-либо другая обработка, каретка редактируемого текста DIV удаляется, и пользователь должен повторно щелкнуть редактируемый DIV, чтобы иметь возможность начать ввод (даже если он все еще в фокусе):

Пример: http://jsfiddle.net/hHLXr/6/.

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


person David Hellsing    schedule 01.02.2012    source источник


Ответы (11)


Возможно, вам придется вручную обновить выбор. В IE событие focus слишком поздно, поэтому я бы предложил вместо этого использовать событие activate. Вот код, который выполняет эту работу во всех основных браузерах, включая IE ‹= 8 (чего нет в альтернативе только CSS):

Живая демонстрация: http://jsfiddle.net/hHLXr/12/

Код:

$('div').on('activate', function() {
    $(this).empty();
    var range, sel;
    if ( (sel = document.selection) && document.body.createTextRange) {
        range = document.body.createTextRange();
        range.moveToElementText(this);
        range.select();
    }
});

$('div').focus(function() {
    if (this.hasChildNodes() && document.createRange && window.getSelection) {
        $(this).empty();
        var range = document.createRange();
        range.selectNodeContents(this);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
});
person Tim Down    schedule 01.02.2012
comment
Еще +1 для RangeMaster. Я думал, что, сохраняя простоту, я смогу избежать проблем с кроссбраузерностью, но это было довольно наивно с моей стороны. - person Andy E; 01.02.2012
comment
Милая! Я надеялся, что вы будете рядом с мистером. RangeMaster! - person David Hellsing; 01.02.2012
comment
@AndyE: Спасибо. Может быть способ попроще. На самом деле должно быть, но я не смог найти его быстро. - person Tim Down; 01.02.2012
comment
Последние два дня я бился головой об этом, пробуя всякие причуды. Я даже добавлял заполнитель с абсолютным позиционированием на затылке, так что это решение для меня достаточно простое! Я согласен, однако, должно быть более простое решение ... - person David Hellsing; 01.02.2012
comment
Потрясающие! Вы избавили меня от головной боли :) - person johnjohn; 13.02.2012

Вот решение только для CSS, дополняющее некоторые другие ответы: -

<div contentEditable=true data-ph="My Placeholder String"></div>
<style>
    [contentEditable=true]:empty:not(:focus)::before{
        content:attr(data-ph)
    }
</style>

РЕДАКТИРОВАТЬ: вот мой фрагмент кода -> http://codepen.io/mrmoje/pen/lkLez

EDIT2: обратите внимание, этот метод не работает на 100% для многострочных приложений из-за остаточных <br> элементов, присутствующих в div после выполнения select-all-cut или select-all-delete во всех строках. Кредиты: - @vsync
Backspace, похоже, работает нормально (по крайней мере, на webkit / blink)

person mrmoje    schedule 21.08.2013
comment
Это было бы исключительно круто, но ... не могу заставить его работать. Можете ли вы опубликовать рабочий jsfiddle? - person ccleve; 25.08.2013
comment
@ccleve Проверить мою правку. Надеюсь, вы не возражаете против моего использования кода. Jsfiddle серьезно повлиял на меня (и я нахожу код с лучшими функциями) - person mrmoje; 27.08.2013
comment
Это должен быть принятый ответ. Это немного сложнее, чем в @amwinter, но он сохраняет заполнитель в html вместо CSS. - person ccleve; 27.08.2013
comment
Правда! Еще одно преимущество компромисса сложности состоит в том, что если у вас есть несколько элементов contentEditable, все, что вам нужно сделать, это указать data-ph заполнитель для каждого, и один и тот же код CSS позаботится обо всех из них. - person mrmoje; 28.08.2013
comment
@ccleve Согласен; это понятнее для читателя html и проще для шаблонов. - person amwinter; 30.09.2013
comment
Выглядит неплохо, но какая поддержка в браузере? Кажется, что это не совсем правильно в IE 9 и 10 (заполнитель исчезает только при начале набора текста) и ничего не показывает в IE ‹= 8. - person Tim Down; 13.11.2013
comment
С IE ‹= 8, HTML5 чужой язык ..... поэтому атрибут data-ph игнорируется. Вы можете исправить это, заменив его атрибутом title. Что касается IE ›8, я сомневаюсь, что мы можем многое сделать ... но ИМХО поведение, которое вы описываете, не сильно отличается от« реальной сделки ». - person mrmoje; 14.11.2013
comment
В Chrome фокус у этого трюка выглядит странным. Я нажимаю, чтобы изменить значение, и начинаю печатать, но ничего не появляется. Это также как-то сломало мой угловой код. Я не понимаю последствий использования содержимого css, но был бы осторожен. - person Jason McCarrell; 11.01.2014
comment
~ Джейсон Маккаррелл использует display: inline-block вместо display: inline, и это должно работать :) - person factoradic; 05.02.2014
comment
@eugene, ты прав. Я ошибочно предположил, что :not и :empty принадлежат CSS2 (моя ошибка). Однако content:attr(title) работает с ie8, если вы укажете <!DOCTYPE>. Таким образом, вы можете (теоретически) изменить пример для обработки :empty с помощью javascript. Холла, если тебе нужен пример. [CC @TimDown] ` - person mrmoje; 22.02.2014
comment
Это НЕ ответ, это неверно и ненадежно. Попробуйте написать двухстрочный текст, затем выберите все и удалите. внутри contentEditable по-прежнему будет мусор HTML, который предотвратит запуск :empty. неудача. - person vsync; 24.02.2014
comment
Вы правы @vsync! Это очень хорошая находка. Спасибо, что поделились. - person mrmoje; 24.02.2014
comment
@ccleve убедитесь, что в вашем теге div нет случайных пробелов. У меня была проблема, когда мой сгенерированный код выглядел как <div> </div> вместо <div></div> - person Dex; 15.01.2015
comment
очень красивое решение. Спасибо - person nicolas; 23.06.2015
comment
элегантный - хорошее решение. Все, что вам нужно, это цвет: # a9a9a9; чтобы еще больше дать ощущение заполнителя. - person MarzSocks; 27.11.2016

Я только что опубликовал для этого плагин.

Он использует комбинацию CSS3 и JavaScript для отображения заполнителя без добавления к содержимому div:

HTML:

<div contenteditable='true' data-placeholder='Enter some text'></div>

CSS:

div[data-placeholder]:not(:focus):not([data-div-placeholder-content]):before {
    content: attr(data-placeholder);
    float: left;
    margin-left: 5px;
    color: gray;
}

JS:

(function ($) {
    $('div[data-placeholder]').on('keydown keypress input', function() {
        if (this.textContent) {
            this.dataset.divPlaceholderContent = 'true';
        }
        else {
            delete(this.dataset.divPlaceholderContent);
        }
    });
})(jQuery);

Вот и все.

person Craig Stuntz    schedule 25.01.2013
comment
NB: Поскольку я написал этот ответ, я обновил плагин для совместимости с IE и элементов, отличных от div. Последнюю версию можно найти в связанном репозитории GitHub. - person Craig Stuntz; 27.03.2013
comment
Это работает, если я устанавливаю div текст из бэкэнда? В моем случае заполнитель и мой текст объединены - person demo; 13.06.2016

просто используйте псевдоклассы css.

span.spanclass:empty:before {content:"placeholder";}
person amwinter    schedule 10.01.2013
comment
Это было здорово. Затем вы можете сделать span.spanclass: active: before {content:}, чтобы удалить его при выборе - person BobtheMagicMoose; 28.05.2021

Я обнаружил, что лучший способ сделать это - использовать атрибут placeholder, как обычно, и добавить несколько строк CSS.

HTML

<div contenteditable placeholder="I am a placeholder"></div>

CSS

[contenteditable][placeholder]:empty:before {
    content: attr(placeholder);
    color: #bababa;
}

Примечание. селектор CSS :empty работает только в том случае, если буквально нет ничего промежуточного между открывающим и закрывающим тегами. Сюда входят новые строки, вкладки, пустое пространство и т. Д.

Codepen

person ramo    schedule 08.12.2013
comment
У этого решения есть проблема в FF. на правой боковой границе, если щелкнуть дважды, курсор висит там. - person mayankcpdixit; 19.06.2015

Все, что вам нужно, это небольшое решение

[contenteditable=true]:empty:before{
  content: attr(placeholder);
  display: block; /* For Firefox */
}

Демо: http://codepen.io/flesler/pen/AEIFc

person wp student    schedule 12.12.2015
comment
Работает. Протестировано в Firefox, Chrome и Safari. - person Joel Caton; 27.03.2016
comment
Глаз, но не Край (в конце появляется курсор) - person cgat; 29.11.2017
comment
По состоянию на август 2020 года это работает в Edge (по крайней мере, в версии для MacOS). - person NetOperator Wibby; 08.08.2020
comment
Обнаружена проблема с этим методом в Chrome, когда вам нужно дважды щелкнуть, чтобы поместить курсор, если вы щелкнете прямо по заполнителю. Исправлено добавлением pointer-events: none; (находится в вашем коде CSS). Упоминание здесь для тех, кто ищет решение этой конкретной проблемы Chrome. - person Guganeshan.T; 03.11.2020

Вот мой способ:

Он использует комбинацию jQuery и CSS3. Работает точно так же, как атрибут заполнителя html5!.

  • Скрывается сразу при вводе первой буквы
  • Показывается снова, когда вы удаляете то, что в него вводите

HTML:

<div class="placeholder" contenteditable="true"></div>

CSS3:

.placeholder:after {
    content: "Your placeholder"; /* this is where you assign the place holder */
    position: absolute;
    top: 10px;
    color: #a9a9a9;
}

jQuery:

$('.placeholder').on('input', function(){
    if ($(this).text().length > 0) {
        $(this).removeClass('placeholder');
    } else {
        $(this).addClass('placeholder');
    }
});

ДЕМО: http://jsfiddle.net/Tomer123/D78X7/

person surfs up    schedule 24.08.2013
comment
Событие input довольно новое в содержании элементов. Например, он вообще не поддерживается в IE. - person Tim Down; 13.11.2013

Вот исправление, которое я использовал.

<div contenteditable><em>Edit me</em></div>
<script>
$('div').focus(function() {
    var target = $(this);
    window.setTimeout(function() { target.empty(); }, 10);
});
</script>

Для этого я разработал плагин jQuery. Взгляните на https://github.com/phitha/editableDiv

person Phitha    schedule 16.04.2015

Это не точное решение вашей проблемы ..

в наборе вариантов летних заметок

airMode: true

заполнитель работает таким образом.

person Ganesh S    schedule 10.07.2017

В .css

.holder:before {
    content: attr(placeholder);
    color: lightgray;
    display: block;
    position:absolute;    
    font-family: "Campton", sans-serif;
}

in js.

clickedOnInput:boolean = false;
charactorCount:number = 0;
let charCount = document.getElementsByClassName('edit-box')[0];

if(charCount){
this.charactorCount = charCount.innerText.length;
}

if(charactorCount > 0 && clickedOnInput){
document.getElementById("MyConteditableElement").classList.add('holder');
}

if(charactorCount == 0 && !clickedOnInput){
document.getElementById("MyConteditableElement").classList.remove('holder');
}

getContent(innerText){
  this.clickedOnInput = false;
}

В формате .html

<div placeholder="Write your message.." id="MyConteditableElement" onclick="clickedOnInput = true;" contenteditable class="form-control edit-box"></div>

это решение сработало для меня в угловом проекте

person Sahil Ralkar    schedule 02.06.2020

person    schedule
comment
Спасибо, но проблема не в том, что я не знаю, как сохранить текст-заполнитель, а в том, что курсор исчезает при очистке текста-заполнителя. - person David Hellsing; 01.02.2012