在本机不支持它的浏览器中模拟“占位符”属性的最准确方法是啥?

Posted

技术标签:

【中文标题】在本机不支持它的浏览器中模拟“占位符”属性的最准确方法是啥?【英文标题】:What is the most accurate way to emulate the "placeholder" attribute in browsers that don't support it natively?在本机不支持它的浏览器中模拟“占位符”属性的最准确方法是什么? 【发布时间】:2011-07-31 08:14:35 【问题描述】:

最近我一直在研究 jquery/javascript 解决方案来模拟 placeholder 属性,但似乎没有一个是正确的。常见问题有:

不首先使用原生浏览器支持 表单实际上可能会发布占位符文本的值 如果值相同,则无法识别占位符文本和用户输入“但它不会让我!) 难以设置样式或区分常规文本和占位符文本 突兀的实现(几乎总是这样。我不想为每个输入添加 2 个 div 和一个样式表来做到这一点) 只是不起作用。至少有 2 个在 jQuery 网站上。

我已经尝试了一些尝试让它正常工作(从我已经看到的一些代码中获得一些提示),但它仍然需要工作。特别是,表单可能会发布占位符的值。 Comments and mods to the jsfiddle are welcome。 (注意:必须在不支持占位符的浏览器中查看演示) 我见过的大多数代码都采用 placeholder 的值并将其填充到输入本身中,这导致了这个问题,我觉得好像一定有​​更好的方法。

有没有一个很好的干净的解决方案确实有效

编辑:我想强调这一点:它的行为方式应该与您在尽可能原生支持它的浏览器中看到的一样,并且尽可能突兀,正如我目前所展示的那样代码,除了包含脚本和使用 placeholder 之外不需要任何其他内容,就像通常支持它的浏览器一样。

更新:@DA 的当前解决方案是一些错误修复,离完美(参见 cmets)很遥远,希望看到这 100% 结合在一起,并将所有糟糕和错误的代码放在网上感到羞耻。

更新:对 DA 的代码进行了一些修改,但它仍然不完美,主要是关于动态添加的输入字段和现有的 submit() 绑定。感谢所有的帮助,我现在决定不值得。我知道一些人肯定会使用它。这是一个很好的技巧,但对我来说,即使有 1% 的可能性提交表单做一些它不打算做的事情,或者不正确地读取用户输入。这个小功能根本不值得头疼,IE和朋友可以处理它,或者如果确实需要它可以根据具体情况实现,例如客户需要它。 @DA 再次感谢,这是我见过的最好的实现。

结论:我认为克服所有这些问题的唯一方法是这样的:

将占位符值复制到新的块级元素 将新元素添加到输入中 计算输入的高度边框和填充,并将新元素移动到尽可能靠近文本出现的位置 当输入有值或被聚焦时,使用标准的模糊/更改/焦点事件隐藏元素

这样,您无需在提交时执行任何操作或处理可能发生的任何其他问题。抱歉,还没有演示,我得回去工作了 - 但我会保存最后的编辑,以备不时之需。

【问题讨论】:

如果您真的想要符合所有这些要点的内容,编写起来很容易:只需创建以下结构:<div style="position:relative;"><span style="position:absolute;top:0px;left:0px;"/><input style="background:transparent;" /></div> 并在输入为空时将 span 内容设置为您的“占位符”文本。跨度> @cwolves:类似的东西现在开始看起来是最好的解决方案了。 一个小问题是我们发现在某些移动设备上很难将焦点从覆盖的文本传递到输入字段。发生的情况是您可以传递焦点,但键盘并不总是触发,因为在某些不受焦点事件控制的设备上,特别是来自实际的触摸事件(如果您单击了不会发生)顶部的文本,而不是实际的输入字段)。 @DA: 嗯.. 可以将触摸事件设为trigger() 焦点事件吗?移动开发对我来说是一个完全未知的领域,所以我相信你已经想到了这一点。顺便说一句,我将您的代码放入我的 CMS 中进行测试,这是由于各种其他提交绑定和“ajax”生成的表单控件而导致的问题,但用户输入的识别确实有效。 好吧,公平地说,处理黑莓浏览器就像处理 IE。它们很烂,所以在某些方面,当有代码在其他地方都可以使用时,我讨厌不得不容纳它们。从好的方面来说,我认为大多数触控设备(Windows 7 可能是一个很大的例外)将正确支持 html5 占位符,所以这可能不是什么大问题。 【参考方案1】:

“我见过的大多数代码都采用占位符的值并将其填充到输入本身中,这导致了这个问题”

嗯,这几乎就是占位符文本在幕后所做的事情(尽管它并不是真正更新输入的值)。

一个选项类似于这样:

http://fuelyourcoding.com/scripts/infield/

这里的概念是您使用 CSS 移动 LABEL,使其位于字段顶部并且看起来像占位符文本。请注意,标签不一定与占位符文本相同。拥有一个 LABEL 很重要,尤其是对于可访问性而言,而占位符文本可以更多地被视为除标签之外的“帮助文本”。

另一个选项是你一直在做的,取占位符属性的内容并通过 JS 将其移动到输入本身的值中。

你被挂断的地方是你在检查假占位符文本是否仍然存在之前提交表单。

为了解决这个问题,您希望在提交表单时附加一个事件,在提交表单之前,将首先查看所有输入字段,获取它们的值,将其与它们的占位符属性进行比较,如果它匹配,将值设置为空白。

更新:

要解决您在评论中提到的用户输入值与占位符文本匹配的问题,您可以执行以下操作:

$('input[placeholder]').each(function()

 if($(this).val() === $(this).attr('placeholder'))
      // in the odd situation where the field is prepopulated with
      // a value and the value just happens to match the placeholder,
      // then we need to flag it
      $(this).data('skipCompare','true');
      

// move the placeholder text into the field for the rest of the blank inputs
   if($(this).val().length===0)
       $(this).val($(this).attr('placeholder'))
   

// move the placeholder text into the field for the rest of the blank inputs
  if($(this).val().length===0)
      $(this).val() = $(this).attr('placeholder');
  


  $(this)
     .focus(function()
           // remove placeholder text on focus
           if($(this).val()==$(this).attr('placeholder'))
               $(this).val('')
           
     )
     .blur(function()
         // flag fields that the user edits
         if( $(this).val().length>0 && $(this).val()==$(this).attr('placeholder'))
             $(this).data('skipCompare','true');
         
         if ( $(this).val().length==0)
             // put the placeholder text back
             $(this).val($(this).attr('placeholder'));
         
     )


 )

 $('#submitButton').click(function()
   $('input[placeholder]').each(function()
     if( !($(this).data('skipCompare')) && $(this).val() == $(this).attr('placeholder')     )
         $(this).val('');
     ;
     alert($(this).val());
   )
)

已经很晚了,我很累,所以这一切可能完全是错误的。不提供任何保证。 ;)

【讨论】:

从用户的角度来看,这非常好,但它与您的标签相混淆,这在很多方面都很糟糕。我希望看到这个的修改版本,它可能会克隆标签。我得仔细看看,谢谢。 你的标签“乱七八糟”是什么意思? 我的意思是它会删除您的<label> 标签以将它们用作占位符。我仍在阅读,所以这可能只是默认行为,并且可以选择禁用它。 对不起,也许我把事情弄糊涂了。我的回答是谈论两件不同的事情。一种是使用标签标签并将其放置在字段的顶部。它仍然是标签标签,您只是通过 CSS 移动它。另一个几乎是您一直在构建的,您使用 JS 将占位符属性值移动到输入值中。我认为两者都有优点,并且在略有不同的情况下很有用。 目标是模拟本机浏览器实现(例如,您会在 FF4 或 Chrome 中看到),但这段代码做得不太好。【参考方案2】:

前段时间写的jquery插件:

(function()
    $.fn.inactiveText = function(inactiveClass, defaultValue)
        var a, b;
        this
            .data    ('defaultValue', defaultValue)
            .addClass('inactive')
            .focus(a=function()
                var $this = $(this);
                if($this.hasClass(inactiveClass))
                    (valFn.apply($this) == defaultValue) && $this.val('');
                    (valFn.apply($this) != defaultValue) && $this.removeClass(inactiveClass);
                
    //            $this.hasClass(inactiveClass) && $this.valueIs(defaultValue).val('').end().valueIsNot(defaultValue).removeClass(inactiveClass);
            )
            .blur(b=function()
                var $this = $(this);
                this.value || $this.addClass(inactiveClass).val(defaultValue);
            );
        this.each(a);
        this.each(b);

        this.setDefaultValue = function(d)
            this.each(a);
            defaultValue = d;
            this.each(b);
        ;

        return this;
    ;

    var valFn = $.fn.val;

    $.fn.val = function(v)
        if(typeof(v) == 'undefined')
            var val = valFn.apply(this, arguments);
            return val == this.data('defaultValue') ? '' : val;
        

        return valFn.apply(this, arguments);
    ;
)();

为非活动样式(例如灰色文本)定义一个 css 类,一切顺利。

更新小提琴:http://jsfiddle.net/cwolves/At8cu/1/

【讨论】:

无法正常工作,请尝试填充其中一个字段,将其清空,然后失去焦点。使用“您的姓名”作为名称字段的默认value,手动清除名称字段并失去焦点,它将电子邮件占位符复制到名称字段。我发布了一个小提琴,但它没有保存我的更新,还在学习如何小提琴:) 那只是因为我没有更改选择器,它仍然使用$('[placeholder]')。改成$('[name=email]')就好了,抱歉:) 如果我必须为每个字段定义它,这属于 obtrusive 类别。关闭但没有雪茄。 然后将其修改为.attr('placeholder'),并不难 :) 无论如何,您必须为每个字段定义它,我只是选择在 JS 中而不是内联 HTML 中进行,主要是因为项目我写这个是为了有 JS 语言切换。 对不起,我不会为你做任何事!此外,您可能更喜欢我在回复您原始问题时描述的方法,我没有写那个:)【参考方案3】:

假设 jQuery 已定义。

$(document).ready(function() 
    // Use native functionality if possible
    if (document.createElement('input').placeholder !== undefined) return;
    // Fallback code
    $('form').each(function(i, form) 
        var submitted = false;
        $(form).find('input[placeholder]').each(function(j, input) 
            addPlaceholder.call(input);
            $(input)
                .focus(removePlaceholder)
                .blur(addPlaceholder)
                ;
        );
        $(form).submit(function() 
            submitted = true;
            $(this).find('input[placeholder]').each(function(j, input) 
                removePlaceholder.call(input);
            );
        );
        function addPlaceholder() 
            if (!submitted && '' === $(this).val()) 
                $(this).val($(this).attr('placeholder')).addClass('placeholder');
            
        
        function removePlaceholder() 
            if ( $(this).hasClass('placeholder') &&
                 $(this).attr('placeholder') === $(this).val()
                 ) 
                $(this).val('').removeClass('placeholder');
            
        
    );
);

使用 CSS 为您的占位符设置样式,使其在所有浏览器中看起来都一样:

            :-moz-placeholder  color: #bbb; opacity: 1; 
           ::-moz-placeholder  color: #bbb; opacity: 1; 
       :-ms-input-placeholder  color: #bbb; 
  ::-webkit-input-placeholder  color: #bbb; 
                 .placeholder  color: #bbb; 

【讨论】:

【参考方案4】:

试过这些链接吗?


HTML5 Forms Placeholder FallbackjQuery Placeholder TextPlaceholder Attribute Support in ALL browsers

【讨论】:

我只是简单地浏览了所有这些,它们都会(我相信)在 field.val() 上失败,给你占位符文本而不是 ''。 无论浏览器是否对它进行任何操作,placeholder 属性都可以存在。因此,当您运行验证时,请根据该字段的占位符属性的值检查该字段的值。如果它们匹配,那么您可以假设该字段为“空白”。 我检查了这些链接,它们在某些时候都失败了。 @DA:严格来说,请参阅我的问题中的第 3 点,这种方法也属于 obtrusive 类别。 您的占位符文本也是用户输入的文本,这似乎是一种极为罕见的极端情况。也就是说,你可以解决这个问题。 Onblur,检查字段的值。如果有,则将该字段标记为“用户数据”,然后在提交时忽略与占位符的比较。 @DA,我已经在我的问题中发布的小提琴中控制了这个,请看一下。

以上是关于在本机不支持它的浏览器中模拟“占位符”属性的最准确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Javascript 检查 IE8 中的原生占位符支持

如何删除焦点上的占位符[重复]

HTML5“占位符”支持

Internet Explorer 缺乏占位符支持,特别是密码字段

检查是不是支持占位符的简单方法?

IE9 RTW 是不是支持输入元素的占位符属性?