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

124
任何想法如何使日期选择器出现在文本框的末尾而不是直接下面?通常发生的情况是,文本框位于页面底部,DatePicker向上移动以进行调整,并完全覆盖文本框。如果用户想要键入日期而不是选择它,则无法实现。我希望它出现在文本框后面,这样无论如何垂直调整都没有问题。
有任何控制位置的想法吗?我没有看到任何小部件的设置,并且我没有调整CSS设置的运气,但我可能很容易忽略某些东西。

1
+1 不仅仅是"解决"投诉,而是确保你的解决方案不是 D_N 的解决方案。 - Leonidas
25个回答

126

这是我正在使用的:

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

你可能还想将左边距留出一些空间,这样它就不会紧贴着输入框了。


2
不错的技巧。问题在于当日期选择器显示超出屏幕边界时,_showDatepicker将尝试重新定位它,因此,顶部和左侧将是不同的,marginTop,marginLeft可能需要调整。 - monzonj
1
我使用了类似的方法 - 我采用了您使用 beforeShow 的想法,但我的 beforeShow 函数使用 JQueryUI 的 position 效果:$(this).position(my:'left top', at:'left bottom', of:'#altField')(因为我正在使用 datepicker 的 altField 选项进行显示)。 - Isaac Betesh
这可能适用于设置边距,但对于“left”、“top”、“z-index”和“position”属性则失败。 - aaronbauman
据我所知,这也不起作用,因为jquery在调用beforeShow之后会重置位置。 - Software Engineer
给出的答案是错误的,因为datepicker会在beforeShow()返回后重置位置。 - wh81752

44

这是我关于日期选择器日历对齐的修改。

我认为它非常好用,因为你可以通过jQuery UI位置实用程序来控制定位。

一个限制:需要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一起使用)! - Sebastian
这个答案仅展示了position.js的优点。 - wh81752
2
这在v1.11.4版本中仍然有效,但这确实是一种肮脏的黑客方式。很遗憾,jQuery API不允许我们在afterShow方法中执行此操作。 - Skoua

43

我直接在CSS中实现:

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

我的日期输入字段宽度都是100像素。我还增加了z-index,这样日历也会显示在AJAX弹出窗口的上面。

我没有修改jquery-ui CSS文件;我在主CSS文件中重载了该类,以便在不重新输入特定修改的情况下更改主题或更新小部件。


与其他CSS技巧相同的问题:仅当您确切地知道CSS中应该放置日期选择器时才起作用。您无法使用此方法动态地放置日期选择器。我不得不使用一个hack,绑定在inst.input.focus()上。 - aaronbauman
使用Bootstrap对我很有效 :) 但我只设置了z-index属性。 - Francisco Goldenstein
除了微不足道的实现,这对于其他任何事情都没有用处,因为您将不知道页面上的输入字段在哪里。 - Software Engineer

35

这里是我觉得很实用的另一种变体,根据您的需求调整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>


1
哇,它起作用了。使用“inst.dpDiv.css(“top”,“40px!important”);”不起作用! - emeraldhieu
通过引入超时机制来解决编程问题,远非完美之策。 - wh81752
谢谢,这对我有用,不知道以后是否会有一个 afterShow 事件,那将会很棒!但现在这可以帮助我继续前进 :D - Rob Branaghan
我尝试了很多其他的解决方案,但只有这个有效。 - Calanus

19

对于这个问题,被接受的答案实际上并不适用于jQuery UI日期选择器。要更改jQuery UI日期选择器的位置,只需在CSS文件中修改.ui-datepicker即可。同样,也可以通过此方式更改日期选择器的大小,只需调整字体大小即可。


4
请问你能告诉我你做了哪些修改吗? - eddy
1
只有在CSS中确切地知道datepicker应该在哪里时,此方法才有效。您无法使用此方法动态放置datepicker。我不得不使用一个hack,在inst.input.focus()上绑定。 - aaronbauman
76
我不知道为什么这个被接受作为答案,因为它几乎完全没有用。 - Software Engineer
15
给出的答案在这里是完全无用的,因为日期选择器在弹出小部件之前会动态地修改 .ui-datepicker 的 CSS。 - wh81752
5
这个回答没有提供任何细节,不应该被接受作为答案。 - chapeljuice
显示剩余2条评论

18

这对我有效:

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);
}

8
首先,我认为应该在日期选择器对象中添加一个名为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内部实现的更改可能会破坏您的代码。


1
他们本应该将这个作为可配置项添加到jQuery UI中。 - Aleksej Komarov

4

我需要根据包含无边框输入控件的父 div 来定位日期选择器。为此,我使用了 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);
        }

非常丑陋的解决方案。最大的问题是在日期选择器小部件刚刚可见时会出现明显的“跳跃”,突然出现您的“重新定位”。必须尽一切可能避免。 - wh81752

3

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

  1. 给我的datepicker输入框添加了一个类 ".datepicker2"

  2. 找到它当前的顶部位置,并定位弹出框,其类名为 ".ui-datepicker"

这是我的代码。

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

这里的“40”是我期望的像素值,你可以根据自己的需求进行更改。


3
一个非常简单的jQuery函数。
$(".datepicker").focus(function(event){
                var dim = $(this).offset();
                $("#ui-datepicker-div").offset({
                    top     :   dim.top - 180,
                    left    :   dim.left + 150
                });
            });

简单而有效。对我有用! - TharakaNirmana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接