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


109

是否知道如何使DatePicker显示在关联的文本框的末尾而不是直接出现在其下方?倾向于发生的情况是,文本框位于页面底部,而DatePicker向上移动以解决该问题,并完全覆盖了文本框。如果用户想输入日期而不是选择日期,则不能。我宁愿它出现在文本框之后,所以它如何垂直调整都无关紧要。

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


1
+1不仅是“解决”投诉,您的解决方案不是D_N的解决方案。
Leonidas

Answers:


20

这个问题的公认答案实际上不是jQuery UI Datepicker的答案。要更改jQuery UI Datepicker的位置,只需在css文件中修改.ui-datepicker。Datepicker的大小也可以通过这种方式更改,只需调整字体大小即可。


4
您能告诉我您进行了哪些更改吗?
涡流

1
@gfrizzle-是的,我的回答是如此错误。终于到了装箱。不知道那时候我在想什么:/
Kev

64
我不知道为什么这是公认的答案,因为它几乎完全没有用。
软件工程师

10
给定的答案完全没有用的,因为datepicker将在弹出窗口小部件之前动态修改.ui-datepicker的css。
whaefelinger

4
该答案没有提供任何详细信息,也不应该被接受。
chapeljuice

120

这是我正在使用的:

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

您可能还想在左边距处添加一些内容,以免与输入字段不符。


2
好招 问题是,在显示日期选择器超出屏幕边界的情况下,_showDatepicker将尝试重定位它,因此,顶部和左侧将不同,marginTop,marginLeft可能需要调整。
2011年

1
我使用了类似的方法-我接受了您使用beforeShow的想法,但是我的beforeShow函数使用了JQueryUI的位置效果:($(this).position(my:'left top', at:'left bottom', of:'#altField')因为我使用datepicker的altField选项进行显示)
Isaac Betesh 2014年

这可能可以设置边距,但对于“左”,“上”,“ z索引”和“位置”属性无效。
aaronbauman 2014年

据我了解,这也不起作用,因为jquery在调用beforeShow之后重置了位置。
软件工程师

给定的答案错误的,因为datepicker将在beforeShow()返回之后重置位置。
whaefelinger

40

我直接在CSS中执行此操作:

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

我的日期输入字段均为100px宽。我还添加了z-index,因此日历也显示在AJAX弹出窗口上方。

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


与其他css-trick相同的问题:仅当您现在确切地说日期选择器应在CSS中的位置时才起作用。您不能使用此方法动态放置日期选择器。我不得不使用hack,绑定到inst.input.focus()
aaronbauman

使用Bootstrap为我工作:),但我仅设置z-index属性。
Francisco Goldenstein 2014年

除琐碎的实现外,它无用,因为您将不知道输入字段在页面上的位置。
软件工程师

35

这是我的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的优点。
whaefelinger

这在v1.11.4中仍然有效,但这确实是一个肮脏的技巧,太糟糕的jQuery API不允许我们使用某种afterShow方法来做到这一点。
Skoua '16

29

这是另一个很适合我的变体,调整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“);” 不起作用!
emeraldhieu

通过引入超时来克服程序性问题远非完美。
whaefelinger

谢谢您为我工作,我想知道是否会举办一次AfterShow活动,那太好了!!但是现在这可以帮助我继续
前进

16

这对我有用:

 beforeShow: function(input, inst) {
     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);

6

首先,我认为afterShowingdatepicker对象中应该有一个方法,您可以在jquery在该_showDatepicker方法中完成所有巫毒操作后更改位置。另外,preferedPosition还需要一个名为的参数,因此,如果对话框在视口外呈现,则可以对其进行设置和jquery对其进行修改。

最后一件事情有一个“把戏”。如果您研究此_showDatepicker方法,将会看到使用private变量$.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可能会破坏您的代码。


1
他们应该将其作为可配置项添加到jQuery UI中。
Aleksej Komarov 2014年

3

我需要根据我的无边界输入控件所在的父div定位datepicker。为此,我使用了jQuery UI核心中包含的“ position”实用程序。我在beforeShow事件中做到了。正如上面的其他评论所述,您不能直接在beforeShow中设置位置,因为日期选择器代码将在完成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小部件在可见之后突然出现“重定位”,这明显引起了datepicker小部件的“跳跃”。要不惜一切代价避免。
whaefelinger

2

使用datepicker后绑定focusin更改datepicker的小部件的CSS希望帮助

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

2

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

  1. 给我的datepicker输入字段一个类“ .datepicker2

  2. 从顶部找到其当前位置,然后

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

这是我的代码。

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

这里“ 40”是我期望的像素,您可能会随自己的像素而改变。


1

修复显示位置问题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();
        }
    }

1

一个非常简单的jquery函数。

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

1

我花了很多时间试图在正在开发的新站点的几页页面中找出此问题,但似乎没有任何效果(包括我实施的上述各种解决方案。我猜想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-div{z-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。我知道会很简单。我现在已经完成了这件事。希望其他人可以从此解决方案中受益。


1

他们将类名更改为 ui-datepicker-trigger

所以这适用于 jquery 1.11.x

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


1

或者,您可以在dateSelect对象和position api上一起使用focus事件。您可以将顶部,底部和左侧交换为右侧或中央(或者实际上是您希望从位置api获得的任何内容)。这样,您就不需要间隔或任何复杂的解决方案,并且可以根据输入的位置来配置布局以适合您的需求。

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

最好/最正确的答案!
HirsuteJim

0

还值得注意的是,如果IE进入怪癖模式,则您的jQuery UI组件和其他元素的位置将不正确。

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

<!DOCTYPE html>

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


0

这会将功能放入名为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);
}

0

在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.datepicker,{_checkOffset:function(inst ,offset,isFixed){return {top:mytop,left:myleft };}}); mytop和myleft取决于您的个人喜好,例如从inst派生。
whaefelinger

0
.ui-datepicker {-ms-transform: translate(100px,100px); -webkit-transform: translate(100px,100px); transform: translate(100px,100px);}

为什么投票失败?这不能解决问题吗?codepen.io/coconewty/pen/rajbNj-
詹姆斯·詹姆斯(James)

投票否决?因为您只是在阅读问题的标题,而没有花力气去研究真正的问题。只需假设您将两个日期选择器连接到具有不同宽度的输入字段即可。您的解决方案如何确保每个日期选择器小部件的左侧边缘都与输入字段的右侧边缘相接触?另一方面,答案的独创性至少应得1分。
whaefelinger

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.