Вопрос по watermark, knockout.js – текстовый ввод водяного знака с использованием пользовательского bindingHandler

5

Я пытался создать пользовательский bindingHandler, который я мог бы использовать, чтобы задать поведение водяного знака для полей ввода текста.

Отwatermark я имею в виду: добавить значения по умолчанию в текстовые поля, которые удаляются в фокусе, и заменяются на размытие, если текстовое поле еще пусто

Мне удалось заставить это работать, как показано в этом jsfiddle:http://jsfiddle.net/rpallas/nvxuw/

У меня есть 3 вопроса об этом решении:

Is there any way to change it so that I only have to declare the watermark value once? Currently I have to put it on the place where I declare the binding and I also have to initialise the observable with the same value in the viewModel - as it will otherwise have no initial value. Is there a better way of getting to the underlying observable that the elements value is bound to. I'm currently grabbing it using the allBindingsAccessor, but this feels wrong to me. Originally I was just setting the value using jquery $(element).val('') but this also felt wrong. Which is best, or is there a better way? Does any one have or know of an existing solution to this this problem? Am I re-inventing the wheel?

Ваш Ответ

2   ответа
14

что вы не используете все привязки. Фактически, я не думаю, что водяной знак должен быть осведомлен о наблюдаемом вообще, поскольку это то, что водяной знак обычно делает, т.е.placeholder приписывать.

Будет ли это работать для вас?

ko.bindingHandlers.watermark = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor(), allBindings = allBindingsAccessor();
        var defaultWatermark = ko.utils.unwrapObservable(value);
        var $element = $(element);

        setTimeout(function() {
            $element.val(defaultWatermark);}, 0);

        $element.focus(
            function () {
                if ($element.val() === defaultWatermark) {
                    $element.val("");
                }
            }).blur(function () {
                if ($element.val() === '') {
                    $element.val(defaultWatermark)
                }
            });
    }
};

http://jsfiddle.net/madcapnmckay/Q5yME/1/

Надеюсь это поможет.

Ого. Я не ожидал найти полное решение для этого. Спасибо!
Большое спасибо за объяснение и помощь. Robbie
да, это почти то же самое, что я имел до того, как изменил его, чтобы использовать allBindingsAccessor. Мне не хваталоsetTimeout при попытке установить начальное значение. Не могли бы вы вкратце объяснить, почему это требуется? Кроме того, вы знаете, есть ли лучший способ? или вы думаете, что это хороший (достаточный) способ (с точки зрения всего решения)? Например, я заметил, что есть привязка hasfocus (встроенная). Может ли это быть лучшим подходом? Robbie
Очень интересно относительно setTimeout, я не осознавал, что это требовалось до сих пор. Благодарю.
Я думаю, что этот подход хорош, если вы хотите поддерживать старые браузеры. Для новых просто используйте атрибут placeholder. SetTimeout необходим, потому что внутри KO использует setTimeout перед установкой значения ввода. Это означает, что ваш код был запущен до того, как код KO установил значение, поэтому вам нужно установить setTimeout, чтобы снова убедиться, что ваш код последним в выполнении.
1

если логика вашего приложения очень проста, имейте в виду, что решение работает со значениями вашей модели представления, эти значения могут быть наблюдаемыми, и они могут иметь подписки или вычисления, связанные с ним, поэтому путем изменения значения Вы меняете свою модель просмотра. Вот другое решение без обновления вашей View Model

ko.bindingHandlers.fakePlaceHolderWhenNeedIt = {
    init: function (element, valueAccessor, allBindings, vm) {
     if (!Modernizr.input.placeholder) {
        var placeHolderVal = $(element).attr("placeholder");

        if (placeHolderVal != null || placeHolderVal != '') {

            var $element = $(element);
            var value = valueAccessor()
            var valueUnwrapped = ko.utils.unwrapObservable(value);


            $element.keyup(function () {
                var inputValue = $(this).val();
                var $watermark = $(this).prev('.ie-placeholder');
                if (inputValue == null || inputValue == '') {
                    $watermark.show();
                }
                else {
                    $watermark.hide();
                }
            });

            var display = valueUnwrapped != null || valueUnwrapped != '' ? "block" : "none";
            var left = $element.position().left;
            var top = $element.position().top;
            var paddingLeft = $element.css('padding-left');
            var paddingRight = $element.css('padding-right');
            var paddingTop = $element.css('padding-top');
            var paddingBottom = $element.css('padding-bottom');

            var height = $element.css('height');
            var placeHolder = '<div class="ie-placeholder" style="position:absolute;left:' + left + ';top:' + top + ';padding-top: ' + paddingTop + ';padding-bottom: ' + paddingBottom + ';padding-left: ' + paddingLeft + ';padding-right: ' + paddingRight + ';height: ' + height + ';line-height:' + height + ';display:' + display + ';">' + placeHolderVal + '</div>';

            $(placeHolder).click(function () { $element.focus(); }).insertBefore(element);
        }
    }
},
update: function (element, valueAccessor, allBindings, vm) {
    if (!Modernizr.input.placeholder) {
        var placeHolderVal = $(element).attr("placeholder");

        if (placeHolderVal != null || placeHolderVal != '') {
            var $element = $(element);
            var value = valueAccessor()
            var valueUnwrapped = ko.utils.unwrapObservable(value);

            var $watermark = $element.prev('.ie-placeholder');
            if (valueUnwrapped == null || valueUnwrapped == '') {
                $watermark.show();
            }
            else {
                $watermark.hide();
            }
        }
    }
}

Похожие вопросы