Cách thay đổi vị trí cửa sổ bật lên của điều khiển jQuery DatePicker


109

Bất kỳ ý tưởng nào về cách để DatePicker xuất hiện ở cuối hộp văn bản được liên kết thay vì ngay bên dưới nó? Điều có xu hướng xảy ra là hộp văn bản nằm ở cuối trang và DatePicker chuyển lên để tính đến nó và bao phủ hoàn toàn hộp văn bản. Nếu người dùng muốn nhập ngày thay vì chọn, họ không thể. Tôi muốn nó xuất hiện ngay sau hộp văn bản để nó điều chỉnh theo chiều dọc không quan trọng.

Bất kỳ ý tưởng làm thế nào để kiểm soát định vị? Tôi không thấy bất kỳ cài đặt nào cho tiện ích con và tôi chưa gặp may khi chỉnh sửa cài đặt CSS, nhưng tôi có thể dễ dàng thiếu một thứ gì đó.


1
+1 vì không chỉ "giải quyết" khiếu nại, rằng giải pháp của bạn không phải là giải pháp cho D_N.
Leonidas

Câu trả lời:


20

Câu trả lời được chấp nhận cho câu hỏi này thực sự không dành cho Người chọn ngày giao diện người dùng jQuery. Để thay đổi vị trí của jQuery UI Datepicker chỉ cần sửa đổi .ui-datepicker trong tệp css. Kích thước của Datepicker cũng có thể được thay đổi theo cách này, chỉ cần điều chỉnh kích thước phông chữ.


4
Bạn có thể vui lòng cho tôi biết bạn đã thực hiện những thay đổi nào không?
xoáy

1
@gfrizzle - vâng, câu trả lời của tôi quá sai. Cuối cùng đã đi được khoảng để binning nó. Không biết lúc đó tôi đang nghĩ gì: /
Kev

64
Tôi không biết tại sao đây là câu trả lời được chấp nhận vì nó gần như hoàn toàn vô dụng.
Kỹ sư phần mềm

10
Câu trả lời được đưa ra hoàn toàn vô dụng như datepicker sẽ tự động css Sửa .ui-datepicker trước khi nảy lên widget.
whaefelinger

4
Câu trả lời này không đưa ra bất kỳ chi tiết nào, và không nên là câu trả lời được chấp nhận.
rượu chapeljuice

120

Đây là những gì tôi đang sử dụng:

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

Bạn cũng có thể muốn thêm một chút vào lề trái để nó không nằm ngay trên trường nhập.


2
Mẹo hay. Vấn đề là trong trường hợp trình chọn ngày được hiển thị bên ngoài đường viền màn hình, _showDatepicker sẽ cố gắng di chuyển nó, do đó, trên cùng và bên trái sẽ khác nhau và marginTop, marginLeft có thể cần điều chỉnh.
monzonj

1
Tôi sử dụng một cách tiếp cận tương tự - Tôi lấy ý tưởng của bạn sử dụng beforeShow, nhưng chức năng beforeShow tôi sử dụng hiệu ứng vị trí jQueryUI của: $(this).position(my:'left top', at:'left bottom', of:'#altField')(kể từ khi tôi đang sử dụng datepicker của altFieldtùy chọn để trưng bày)
Isaac Betesh

Điều này có thể hoạt động để đặt lề, nhưng không thành công đối với các thuộc tính "left", "top", "z-index" và "position".
aaronbauman

Theo tôi hiểu, điều này cũng không hoạt động, vì jquery đặt lại vị trí sau khi beforeShow được gọi.
Kỹ sư phần mềm

Câu trả lời đã cho sai vì datepicker sẽ đặt lại vị trí sau khi beforeShow () trả về.
whaefelinger

40

Tôi làm điều đó trực tiếp trong CSS:

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

Các trường nhập ngày tháng của tôi đều rộng 100px. Tôi cũng đã thêm chỉ số z để lịch cũng xuất hiện phía trên cửa sổ bật lên AJAX.

Tôi không sửa đổi tệp CSS jquery-ui; Tôi quá tải lớp trong tệp CSS chính của mình, vì vậy tôi có thể thay đổi chủ đề hoặc cập nhật tiện ích mà không cần phải nhập lại các mod cụ thể của mình.


Vấn đề tương tự như css-trick khác: Chỉ hoạt động nếu bạn hiện chính xác vị trí của trình chọn ngày trong CSS. Bạn không thể sử dụng phương pháp này để đặt bộ chọn ngày tự động. Tôi đã phải sử dụng một hack, bắt buộc đối với inst.input.focus ()
aaronbauman

Làm việc cho tôi bằng Bootstrap :) nhưng tôi chỉ đặt thuộc tính z-index.
Francisco Goldenstein

Vô ích đối với bất kỳ điều gì khác ngoài các triển khai tầm thường vì bạn sẽ không biết trường nhập ở đâu trên trang.
Kỹ sư phần mềm

35

Đây là biến thể của tôi về căn chỉnh lịch Datepicker.

Tôi nghĩ rằng nó khá hay, vì bạn có thể kiểm soát vị trí thông qua jQuery UI Position tận dụng.

Một hạn chế: yêu cầu jquery.ui.position.js.

Mã:

$('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);
    }
})

Cảm ơn bạn @kottenator, điều này thực sự hữu ích (đặc biệt là với position.js)!
Sebastian

Câu trả lời này không cho thấy gì hơn ngoài giá trị của position.js.
whaefelinger

Điều này vẫn hoạt động trong v1.11.4 nhưng đây thực sự là một vụ hack bẩn, API jQuery quá tệ không cho phép chúng tôi thực hiện điều này trong một afterShowphương pháp.
Skoua

29

Dưới đây là một biến thể khác hoạt động tốt đối với tôi, hãy điều chỉnh trực tràng.top + 40, direct.left + 0 để phù hợp với nhu cầu của bạn:

$(".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>


Wow nó hoạt động. Sử dụng "inst.dpDiv.css (" top "," 40px! Important ");" không hoạt động!
emeraldhieu

Không hoàn hảo trong việc khắc phục một sự cố chương trình bằng cách đưa ra thời gian chờ.
whaefelinger

Cảm ơn vì điều này đã làm việc cho tôi, tôi tự hỏi liệu có bao giờ có một sự kiện afterShow hay không, điều đó thật tuyệt !! Nhưng bây giờ điều này giúp tôi tiếp tục bất kể: D
Rob Branaghan

16

Điều này phù hợp với tôi:

 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

Đầu tiên, tôi nghĩ rằng nên có một afterShowingphương thức trong đối tượng datepicker, nơi bạn có thể thay đổi vị trí sau khi jquery đã thực hiện tất cả những điều tốt đẹp của nó trong _showDatepickerphương thức. Ngoài ra, một tham số được gọi làpreferedPosition cũng sẽ được mong muốn, vì vậy bạn có thể đặt nó và jquery sửa đổi nó trong trường hợp hộp thoại được hiển thị bên ngoài khung nhìn.

Có một "mẹo" để làm điều cuối cùng này. Nếu bạn nghiên cứu _showDatepickerphương pháp này, bạn sẽ thấy việc sử dụng một biến private$.datepikcer._pos . Biến đó sẽ được thiết lập nếu chưa có ai thiết lập nó trước đó. Nếu bạn sửa đổi biến đó trước khi hiển thị hộp thoại, Jquery sẽ lấy nó và sẽ cố gắng phân bổ hộp thoại ở vị trí đó, và nếu nó hiển thị ra ngoài màn hình, nó sẽ điều chỉnh để đảm bảo rằng nó được hiển thị. Nghe hay đấy, hả?

Vấn đề là; _poslà riêng tư, nhưng nếu bạn không phiền. Bạn có thể:

$('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
    }
});

Nhưng hãy cẩn thận với các bản cập nhật Jquery-ui, vì một sự thay đổi trong việc triển khai nội bộ _showDatepickercó thể làm hỏng mã của bạn.


1
Họ nên thêm điều này vào giao diện người dùng jQuery dưới dạng mục có thể định cấu hình.
Aleksej Komarov

3

Tôi cần định vị bộ chọn ngày theo một dấu chia gốc mà trong đó điều khiển đầu vào không biên giới của tôi nằm trong đó. Để làm điều đó, tôi đã sử dụng tiện ích "vị trí" có trong lõi giao diện người dùng jquery. Tôi đã làm điều này trong sự kiện beforeShow. Như những người khác đã nhận xét ở trên, bạn không thể đặt vị trí trực tiếp trong beforeShow, vì mã datepicker sẽ đặt lại vị trí sau khi kết thúc chức năng beforeShow. Để giải quyết vấn đề đó, chỉ cần đặt vị trí bằng setInterval. Tập lệnh hiện tại sẽ hoàn tất, hiển thị trình chọn ngày và sau đó mã định vị lại sẽ chạy ngay sau khi trình chọn ngày hiển thị. Mặc dù điều đó sẽ không bao giờ xảy ra, nhưng nếu bộ chọn ngày không hiển thị sau 0,5 giây, thì mã có một lỗi an toàn để từ bỏ và xóa khoảng thời gian.

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

Giải pháp rất xấu xí. Vấn đề lớn nhất sẽ là một "bước nhảy" đáng chú ý của tiện ích chọn ngày ngay sau khi nó hiển thị ở nơi đột nhiên "tái định cư" của bạn bắt đầu. Bạn phải tránh bằng mọi giá.
whaefelinger

2

ràng buộc focusin sau khi sử dụng datepicker thay đổi css của tiện ích con datepicker mong giúp đỡ

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

2

tôi đã sửa nó bằng mã jquery tùy chỉnh của mình.

  1. đã cấp cho trường nhập datepicker của tôi một lớp " .datepicker2 "

  2. tìm vị trí hiện tại của nó từ trên xuống và

  3. định vị hộp bật lên, tên lớp là " .ui-datepicker "

đây là mã của tôi.

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

ở đây "40" là pixel dự kiến ​​của tôi, bạn có thể thay đổi theo pixel của mình.


1

khắc phục sự cố vị trí hiển thị 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

Một hàm jquery rất đơn giản.

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

1

Tôi đã dành một khoảng thời gian vô lý để tìm ra vấn đề này đối với một số trang của một trang web mới mà tôi đang phát triển và dường như không có gì hoạt động (bao gồm bất kỳ giải pháp nào được trình bày ở trên mà tôi đã triển khai. Tôi đoán jQuery vừa thay đổi mọi thứ đã đủ vì họ được đề xuất rằng các giải pháp không còn hoạt động nữa. Tôi không biết nữa. Thành thật mà nói, tôi không hiểu tại sao không có thứ gì đó đơn giản được triển khai vào jQuery ui để định cấu hình điều này, vì có vẻ như một vấn đề khá lớn với lịch luôn xuất hiện ở một số vị trí rất xa trên trang từ đầu vào mà nó được đính kèm.

Nhưng dù sao, tôi muốn một giải pháp cuối cùng đủ chung để tôi có thể sử dụng nó ở bất cứ đâu và nó sẽ hoạt động. Dường như cuối cùng tôi đã đi đến kết luận tránh một số câu trả lời phức tạp hơn và phức tạp hơn về mã jQuery ở trên:

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

Về cơ bản, tôi đính kèm một thẻ kiểu mới vào phần đầu trước mỗi sự kiện "hiển thị" người chọn ngày (xóa cái trước đó, nếu có). Phương pháp làm việc này giải quyết được phần lớn các vấn đề mà tôi gặp phải trong quá trình phát triển.

Đã thử nghiệm trên Chrome, Firefox, Safari và IE> 8 (vì IE8 không hoạt động tốt với jsFiddle và tôi đang mất hứng thú khi quan tâm đến

Tôi biết rằng đây là sự kết hợp giữa các ngữ cảnh jQuery và javascript, nhưng tại thời điểm này, tôi không muốn chuyển đổi nó sang jQuery. Sẽ đơn giản, tôi biết. Tôi đã hoàn thành việc này ngay bây giờ. Hy vọng ai đó khác có thể hưởng lợi từ giải pháp này.


1

Họ đã thay đổi tên lớp thành ui-datepicker-trigger

Vì vậy, điều này hoạt động trong jquery 1.11.x

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


1

Hoặc bạn có thể sử dụng sự kiện tiêu điểm trên đối tượng dateSelect và vị trí api cùng nhau. Bạn có thể hoán đổi trên cùng và dưới cùng và trái cho phải hoặc giữa (hoặc thực sự bất cứ thứ gì bạn muốn từ vị trí api). Bằng cách này, bạn không cần khoảng thời gian hoặc bất kỳ giải pháp quá phức tạp nào và bạn có thể định cấu hình bố cục cho phù hợp với nhu cầu của mình tùy thuộc vào vị trí đầu vào.

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

Câu trả lời đúng nhất / đúng nhất !!
HirsuteJim

0

Cũng cần lưu ý rằng nếu IE rơi vào chế độ quirks, các thành phần giao diện người dùng jQuery của bạn và các phần tử khác, sẽ được định vị không chính xác.

Để đảm bảo bạn không rơi vào chế độ kỳ quặc, hãy đảm bảo bạn đặt chính xác loại tài liệu của mình thành HTML5 mới nhất.

<!DOCTYPE html>

Sử dụng chuyển tiếp làm cho mọi thứ trở nên lộn xộn. Hy vọng rằng điều này sẽ giúp ai đó tiết kiệm thời gian trong tương lai.


0

Điều này đặt chức năng vào một phương thức có tên là hàm, cho phép mã của bạn đóng gói nó hoặc để phương thức được tạo thành một phần mở rộng jquery. Chỉ được sử dụng trên mã của tôi, hoạt động hoàn hảo

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

Trong Jquery.UI, chỉ cần cập nhật hàm _checkOffset, để viewHeight được thêm vào offset.top, trước khi trả về offset.

_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;
    },

Giải pháp này về cơ bản là đúng: Chèn hàm _checkOffset () của riêng bạn thông qua jQuery.extend () và trả về một đối tượng tùy ý có thuộc tính số "top" và "left", tức là jQuery.extend (jQuery.datepicker, {_checkOffset: function (inst , offset, isFixed) {return {top: mytop , left: myleft };}}); trong đó mytop và myleft là theo sở thích cá nhân của bạn, ví dụ như bắt nguồn từ inst .
whaefelinger

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

tại sao bỏ phiếu? cái này không giải quyết được vấn đề à? codepen.io/coconewty/pen/rajbNj
James

phiếu phản đối? Bởi vì bạn chỉ đọc tiêu đề của câu hỏi và không mất bất kỳ nỗ lực nào để đào sâu vào vấn đề thực sự. Đơn giản chỉ cần giả sử rằng bạn có hai bộ chọn ngày được đính kèm vào các trường đầu vào có độ rộng khác nhau. Làm cách nào để giải pháp của bạn đảm bảo rằng cạnh trái của mỗi tiện ích con người chọn ngày chạm vào cạnh phải của trường đầu vào? Mặt khác, bạn sẽ nhận được ít nhất một điểm cho tính độc đáo của câu trả lời của bạn.
whaefelinger

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.