如何更改 jQuery DatePicker 控件的弹出位置

Posted

技术标签:

【中文标题】如何更改 jQuery DatePicker 控件的弹出位置【英文标题】:How to change the pop-up position of the jQuery DatePicker control 【发布时间】:2010-10-14 07:35:30 【问题描述】:

知道如何让 DatePicker 出现在相关文本框的末尾而不是正下方吗?倾向于发生的是文本框位于页面底部,并且 DatePicker 向上移动以解决它并完全覆盖文本框。如果用户想输入日期而不是选择日期,他们不能。我宁愿让它出现在文本框之后,这样它垂直调整的方式就无关紧要了。

知道如何控制定位吗?我没有看到小部件的任何设置,也没有调整 CSS 设置的运气,但我很容易遗漏一些东西。

【问题讨论】:

+1 不仅仅是“解决”投诉,您的解决方案不是 D_N 的解决方案。 【参考方案1】:

这是我正在使用的:

$('input.date').datepicker(
    beforeShow: function(input, inst) 
        inst.dpDiv.css(
            marginTop: -input.offsetHeight + 'px', 
            marginLeft: input.offsetWidth + 'px'
        );
    
);

您可能还想在左边距添加更多内容,这样它就不会正好在输入字段的正上方。

【讨论】:

好把戏。问题是如果日期选择器显示在屏幕边框之外,_showDatepicker 会尝试重新定位它,因此,顶部和左侧将不同,marginTop、marginLeft 可能需要调整。 我使用了类似的方法——我接受了你使用 beforeShow 的想法,但我的 beforeShow 函数使用了 JQueryUI 的位置效果:$(this).position(my:'left top', at:'left bottom', of:'#altField')(因为我使用 datepicker 的 altField 选项进行显示) 这可以设置边距,但对于“left”、“top”、“z-index”和“position”属性失败。 据我了解,这也不起作用,因为 jquery 在调用 beforeShow 后重置了位置。 给定的答案 is 错误,因为 datepicker 将在 beforeShow() 返回后重置位置。【参考方案2】:

我直接在 CSS 中做:

.ui-datepicker  
  margin-left: 100px;
  z-index: 1000;

我的日期输入字段都是 100 像素宽。我还添加了 z-index,因此日历也出现在 AJAX 弹出窗口上方。

我没有修改 jquery-ui CSS 文件;我在我的主 CSS 文件中重载了该类,因此我可以更改主题或更新小部件,而无需重新输入我的特定模块。

【讨论】:

与其他 css 技巧相同的问题:仅当您现在确切地知道日期选择器在 CSS 中的位置时才有效。您不能使用此方法动态放置日期选择器。我不得不使用 hack,绑定 inst.input.focus() 使用 Bootstrap 为我工作 :) 但我只设置了 z-index 属性。 除了琐碎的实现之外,其他任何东西都无用,因为您不知道输入字段在页面上的位置。【参考方案3】:

这是我对 Datepicker 日历对齐的变体。

我认为这很不错,因为您可以通过 jQuery UI Position util 控制定位。

一个限制:需要jquery.ui.position.js。

代码:

$('input[name=date]').datepicker(
    beforeShow: function(input, inst) 
        // Handle calendar position before showing it.
        // It's not supported by Datepicker itself (for now) so we need to use its internal variables.
        var calendar = inst.dpDiv;

        // Dirty hack, but we can't do anything without it (for now, in jQuery UI 1.8.20)
        setTimeout(function() 
            calendar.position(
                my: 'right top',
                at: 'right bottom',
                collision: 'none',
                of: input
            );
        , 1);
    
)

【讨论】:

谢谢@kottenator,这真的很有用(尤其是position.js)! 这个答案只显示了 position.js 的优点。 这在 v1.11.4 中仍然有效,但这确实是一个肮脏的 hack,太糟糕了 jQuery API 不允许我们在 afterShow 方法中这样做。【参考方案4】:

这是另一个适合我的变体,调整 rect.top + 40、rect.left + 0 以满足您的需要:

$(".datepicker").datepicker(
    changeMonth: true,
    changeYear: true,
    dateFormat: 'mm/dd/yy',
    beforeShow: function (input, inst) 
        var rect = input.getBoundingClientRect();
        setTimeout(function () 
	        inst.dpDiv.css( top: rect.top + 40, left: rect.left + 0 );
        , 0);
    
);
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<form>
<input class="datepicker" name="date1" type="text">
<input class="datepicker" name="date2" type="text">
</form>

【讨论】:

哇它好用。使用“inst.dpDiv.css("top", "40px !important");"不工作! 通过引入超时来克服编程问题远非完美。 谢谢你这对我有用,我想知道是否会有一个 afterShow 活动,那太好了!但是现在这可以帮助我继续进行下去:D 我尝试了许多其他解决方案,这是唯一有效的解决方案【参考方案5】:

这个问题的公认答案实际上不适用于 jQuery UI Datepicker。要更改 jQuery UI Datepicker 的位置,只需修改 css 文件中的 .ui-datepicker。 Datepicker的大小也可以这样改变,调整字体大小即可。

【讨论】:

你能告诉我你做了哪些改变吗? @gfrizzle - 是的,我的回答太错误了。终于有时间把它装箱了。不知道我当时在想什么:/ 我不知道为什么这是公认的答案,因为它几乎完全没用。 给定的答案 is 完全没用,因为 datepicker 会在弹出小部件之前动态修改 .ui-datepicker 的 css。 这个答案没有提供任何细节,不应该是公认的答案。【参考方案6】:

这对我有用:

beforeShow: function(input, inst) 
    var $this = $(this);
    var cal = inst.dpDiv;
    var top = $this.offset().top + $this.outerHeight();
    var left = $this.offset().left;

    setTimeout(function() 
        cal.css(
            'top': top,
            'left': left
        );
    , 10);

【讨论】:

【参考方案7】:

首先我认为在 datepicker 对象中应该有一个 afterShowing 方法,您可以在 jquery 在 _showDatepicker 方法中完成所有巫术之后更改位置。此外,还需要一个名为 preferedPosition 的参数,因此您可以设置它并让 jquery 修改它,以防对话框呈现在视口之外。

有一个“技巧”来做这最后一件事。如果您研究_showDatepicker 方法,您将看到私有变量$.datepikcer._pos 的使用。如果之前没有人设置过该变量,则会设置该变量。如果您在显示对话框之前修改该变量,Jquery 将使用它并尝试在该位置分配对话框,如果它渲染到屏幕外,它将调整它以确保它是可见的。听起来不错吧?

问题是; _pos 是私人的,但如果你不介意的话。你可以:

$('input.date').datepicker(
    beforeShow: function(input, inst)
    
        $.datepicker._pos = $.datepicker._findPos(input); //this is the default position
        $.datepicker._pos[0] = whatever; //left
        $.datepicker._pos[1] = whatever; //top
    
);

但要小心 Jquery-ui 更新,因为更改 _showDatepicker 的内部实现可能会破坏您的代码。

【讨论】:

他们应该在 jQuery UI 中添加这个作为可配置项。【参考方案8】:

我需要根据我的无边界输入控件所在的父 div 来定位日期选择器。为此,我使用了 jquery UI 核心中包含的“位置”实用程序。我在 beforeShow 活动中做到了这一点。正如上面其他人评论的那样,您不能直接在 beforeShow 中设置位置,因为 datepicker 代码将在完成 beforeShow 功能后重置位置。要解决这个问题,只需使用 setInterval 设置位置。当前脚本将完成,显示日期选择器,然后重新定位代码将在日期选择器可见后立即运行。虽然它永远不会发生,但如果日期选择器在 0.5 秒后不可见,则代码具有放弃和清除间隔的故障安全功能。

        beforeShow: function(a, b) 
            var cnt = 0;
            var interval = setInterval(function() 
                cnt++;
                if (b.dpDiv.is(":visible")) 
                    var parent = b.input.closest("div");
                    b.dpDiv.position( my: "left top", at: "left bottom", of: parent );
                    clearInterval(interval);
                 else if (cnt > 50) 
                    clearInterval(interval);
                
            , 10);
        

【讨论】:

非常丑陋的解决方案。最大的问题是 datepicker 小部件在您的“重定位”突然启动后出现明显的“跳跃”。不惜一切代价避免。【参考方案9】:

使用日期选择器后绑定焦点 更改 datepicker 小部件的 css 希望得到帮助

$('input.date').datepicker();
$('input.date').focusin(function()
    $('input.date').datepicker('widget').css(left:"-=127");
);

【讨论】:

【参考方案10】:

我用我的自定义 jquery 代码修复了它。

    给我的日期选择器输入字段一个类“.datepicker2

    从顶部找到它的当前位置并

    定位弹出框,类名为“.ui-datepicker

这是我的代码。

$('.datepicker2').click(function()
    var popup =$(this).offset();
    var popupTop = popup.top - 40;
    $('.ui-datepicker').css(
      'top' : popupTop
     );
);

这里的“40”是我预期的像素,你可以用你的来改变。

【讨论】:

【参考方案11】:

一个非常简单的jquery函数。

$(".datepicker").focus(function(event)
                var dim = $(this).offset();
                $("#ui-datepicker-div").offset(
                    top     :   dim.top - 180,
                    left    :   dim.left + 150
                );
            );

【讨论】:

【参考方案12】:

我花了很多时间试图为我正在开发的一个新网站的几个页面解决这个问题,但似乎没有任何效果(包括上面介绍的我实现的各种解决方案。我猜是 jQuery刚刚改变了很多事情,因为他们被建议解决方案不再起作用。我不知道。老实说,我不明白为什么在 jQuery ui 中没有实现简单的东西来配置它,因为它似乎是一个相当大的问题,日历总是在页面下方的某个位置弹出,距离它所附加的输入很远。

无论如何,我想要一个足够通用的最终解决方案,以便我可以在任何地方使用它并且它会起作用。我似乎终于得出了一个结论,避免了上面一些更复杂和特定于 jQuery 代码的答案:

jsFiddle:http://jsfiddle.net/mu27tLen/

html

<input type="text" class="datePicker" />

JS:

positionDatePicker= function(cssToAdd) 
    /* Remove previous positioner */
    var oldScript= document.getElementById('datePickerPosition');
    if(oldScript) oldScript.parentNode.removeChild(oldScript);
    /* Create new positioner */
    var newStyle= document.createElement("style");
    newStyle.type= 'text/css';
    newStyle.setAttribute('id', 'datePickerPostion');
    if(newStyle.styleSheet) newStyle.styleSheet.cssText= cssToAdd;
    else newStyle.appendChild(document.createTextNode(cssToAdd));
    document.getElementsByTagName("head")[0].appendChild(newStyle);

jQuery(document).ready(function() 
    /* Initialize date picker elements */
    var dateInputs= jQuery('input.datePicker');
    dateInputs.datepicker();
    dateInputs.datepicker('option', 
        'dateFormat' : 'mm/dd/yy',
        'beforeShow' : function(input, inst) 
            var bodyRect= document.body.getBoundingClientRect();
            var rect= input.getBoundingClientRect();
            positionDatePicker('.page #ui-datepicker-divz-index:100 !important;top:' + (rect.top - bodyRect.top + input.offsetHeight + 2) + 'px !important;');
        
    ).datepicker('setDate', new Date());
);

基本上,我在每个日期选择器“显示”事件之前将一个新的样式标签附加到头部(如果存在,则删除前一个)。这种做事方法解决了我在开发过程中遇到的大部分问题。

在 Chrome、Firefox、Safari 和 IE>8 上测试(因为 IE8 不能很好地与 jsFiddle 配合使用,我正在失去关心的热情

我知道这是 jQuery 和 javascript 上下文的混合,但在这一点上,我只是不想花精力将其转换为 jQuery。会很简单,我知道。我现在已经完成了这件事。希望其他人可以从这个解决方案中受益。

【讨论】:

【参考方案13】:

或者你可以在你的 dateSelect 对象和位置 api 上一起使用焦点事件。您可以将顶部和底部和左侧交换为右侧或中心(或者实际上是您想要从位置 api 获得的任何东西)。这样您就不需要间隔或任何极其复杂的解决方案,您可以根据输入的位置配置布局以满足您的需求。

dateSelect.focus(function () 
    $("#ui-datepicker-div").position(
        my: "left top",
        at: "left bottom",
        of: $(this)
    );
);

【讨论】:

最佳/最正确答案!!【参考方案14】:

我从 ((How to control positioning of jQueryUI datepicker))

$.extend($.datepicker,  
    _checkOffset: function(inst, offset, isFixed)  
        return offset 
     
);

有效!!!

【讨论】:

答案是正确的,虽然之前基本上已经回答过了。【参考方案15】:

修复显示位置问题 daterangepicker.jQuery.js

//Original Code
//show, hide, or toggle rangepicker
    function showRP() 
        if (rp.data('state') == 'closed') 
            rp.data('state', 'open');
            rp.fadeIn(300);
            options.onOpen();
        
    


//Fixed
//show, hide, or toggle rangepicker
    function showRP() 
        rp.parent().css('left', rangeInput.offset().left);
        rp.parent().css('top', rangeInput.offset().top + rangeInput.outerHeight());
        if (rp.data('state') == 'closed') 
            rp.data('state', 'open');
            rp.fadeIn(300);
            options.onOpen();
        
    

【讨论】:

【参考方案16】:

他们将班级名称改为ui-datepicker-trigger

所以这适用于jquery 1.11.x

.ui-datepicker-trigger  
margin-top:7px;
  margin-left: -30px;
  margin-bottom:0px;
  position:absolute;
  z-index:1000;

【讨论】:

【参考方案17】:

另外值得注意的是,如果 IE 进入 quirks 模式,您的 jQuery UI 组件和其他元素将被错误定位。

为确保您不会陷入怪癖模式,请确保您将文档类型正确设置为最新的 HTML5。

<!DOCTYPE html>

使用过渡会使事情变得一团糟。希望这会在将来节省一些时间。

【讨论】:

【参考方案18】:

这会将功能放入一个名为 function 的方法中,允许您的代码封装它或使该方法成为 jquery 扩展。刚刚用在我的代码上,效果很好

var nOffsetTop  = /* whatever value, set from wherever */;
var nOffsetLeft = /* whatever value, set from wherever */;

$(input).datepicker
(
   beforeShow : function(oInput, oInst) 
    
      AlterPostion(oInput, oInst, nOffsetTop, nOffsetLeft); 
   
);

/* can be converted to extension, or whatever*/
var AlterPosition = function(oInput, oItst, nOffsetTop, nOffsetLeft)

   var divContainer = oInst.dpDiv;
   var oElem        = $(this);
       oInput       = $(oInput);

   setTimeout(function() 
    
      divContainer.css
      ( 
         top  : (nOffsetTop >= 0 ? "+=" + nOffsetTop : "-=" + (nOffsetTop * -1)), 
         left : (nOffsetTop >= 0 ? "+=" + nOffsetLeft : "-=" + (nOffsetLeft * -1))
      ); 
   , 10);

【讨论】:

【参考方案19】:

在 Jquery.UI 中,只需更新 _checkOffset 函数,以便在返回 offset 之前将 viewHeight 添加到 offset.top。

_checkOffset: function(inst, offset, isFixed) 
    var dpWidth = inst.dpDiv.outerWidth(),
    dpHeight = inst.dpDiv.outerHeight(),
    inputWidth = inst.input ? inst.input.outerWidth() : 0,
    inputHeight = inst.input ? inst.input.outerHeight() : 0,
    viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
            viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : ($(document).scrollTop()||document.body.scrollTop));
        offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
        offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
        offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? ($(document).scrollTop()||document.body.scrollTop) : 0;

        // now check if datepicker is showing outside window viewport - move to a better place if so.
        offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
            Math.abs(offset.left + dpWidth - viewWidth) : 0);
        offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
            Math.abs(dpHeight + inputHeight) : 0);
**offset.top = offset.top + viewHeight;**
        return offset;
    ,

【讨论】:

这个解决方案基本上是正确的:通过jQuery.extend() 注入你自己的_checkOffset() 函数,并返回一个具有数字属性“top”和“left”的任意对象,即jQuery.extend(jQuery.extend()。 datepicker, _checkOffset: function (inst, offset, isFixed) return top: mytop, left: myleft ;);其中 mytop 和 myleft 符合您的个人喜好,例如源自 inst【参考方案20】:
.ui-datepicker -ms-transform: translate(100px,100px); -webkit-transform: translate(100px,100px); transform: translate(100px,100px);

【讨论】:

为什么会被否决?这不解决问题吗? codepen.io/coconewty/pen/rajbNj 投票?因为你只是在阅读问题的标题,并没有花任何精力去挖掘真正的问题。只需假设您有两个日期选择器附加到具有不同宽度的输入字段。您的解决方案如何确保每个日期选择器小部件的左边缘接触输入字段右边缘?另一方面,您的答案的原创性应该至少得到一分。【参考方案21】:
$('.PDatePicker').MdPersianDateTimePicker(
                Placement: 'top',          
            );

【讨论】:

【参考方案22】:

这是另一种解决方案。

    创建函数来固定位置

     function setDatepickerPos(input, inst) 
     var rect = input.getBoundingClientRect();
     // use 'setTimeout' to prevent effect overridden by other scripts
     setTimeout(function () 
         var scrollTop = $("body").scrollTop();
         inst.dpDiv.css( top: rect.top + input.offsetHeight + scrollTop );
     , 0);
    

    将函数添加到日期选择器的“beforeShow”属性中

     $('#MyDatepicker').datepicker(
     dateFormat: "yy-mm-dd",
     changeMonth: true,
     changeYear: true,
     defaultDate: +0,
     inline: true,
     beforeShow: function (input, inst)  setDatepickerPos(input, inst) ,);
    

这里是参考链接:link。所有的学分都应该去Aries.me

【讨论】:

以上是关于如何更改 jQuery DatePicker 控件的弹出位置的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 Silverlight DatePicker 控件中的日期格式?

JQuery datePicker 日期重置

如何更改 jQuery UI datepicker 的主题?

jQuery Datepicker日期控件

使用 jQuery datepicker 从 ASP MVC @Html.TextBoxFor 控件中删除时间

如何更改 jquery datepicker 的输入类型?