UI日期选择器:选择日期会覆盖现有设置。

3
我正在尝试编写自定义日期选择器,其中通过changeMonthchangeYear选项启用的默认月份和年份范围下拉菜单被替换为自定义下拉菜单。就像这样:

Fiddle: http://jsfiddle.net/gGV3v/

$("#myId").datepicker({
   ...default settings...
   beforeShow: function() {
      ...here I replace the default dropdowns by custom dropdowns...
      ...something like...
      $(".ui-datepicker-month").replaceWith("#custom-html-block");
      $(".ui-datepicker-year").replaceWith("#another-custom-html-block");
    }
 });

当从自定义下拉菜单中选择月份或年份时,我希望能相应地更改视图中的日期。因此,我从当前月份和年份构建日期字符串(这里新月/年组合的日期默认为1),然后调用...
$("#custom-html-block .custom-dropdown-option").on("click",function() {
     ...construct newDateString...
     $("#myId").datepicker("setDate",newDateString)
});

$("#another-custom-html-block .custom-dropdown-option").on("click",function() {
     ...construct newDateString...
     $("#myId").datepicker("setDate",newDateString)
});

当通过点击它来编程设置新日期时,我希望具有文本 foo span 保持不变。


问题是:它会清除自定义下拉菜单,然后再次显示默认的下拉菜单。我尝试过像这样的操作:

$("#myId").datepicker($.extend({setDate: newDateString},oldSettings))

但是它仍然无法运行。我该如何使其工作?

3
你介意提供一个 fiddle 吗?(译注:fiddle 是指一个在线代码编辑器和共享工具,可以用于演示、测试和共享 Web 开发代码。) - Thorsten
选择日期会导致下拉菜单也被重置吗? - Robbert
不,因为当文本输入框被聚焦时下拉菜单弹出,我点击日期后它就会消失。当我再次聚焦到文本输入框时,一个新的实例将会弹出,带有自定义的下拉菜单。所以在选择日期时,在它消失之前,我并没有看到它们被替换。然而,如果你尝试通过左上角和右上角的按钮导航到上一个或下一个月份,新的月份将会出现,下拉菜单也会变成默认设置。 - SexyBeast
你为什么要使用自定义下拉框呢?你只是想更好地控制下拉框的外观吗? - apaul
https://dev59.com/YXI-5IYBdhLWcg3wW3Cp - apaul
显示剩余8条评论
2个回答

1
您可以设置函数$.datepicker._generateMonthYearHeader的值,但缺点是它将对页面上所有日期选择器产生全局影响。
以下是示例:
$.datepicker._generateMonthYearHeader = function(inst, drawMonth, drawYear, minDate, maxDate,
        secondary, monthNames, monthNamesShort) {


    var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
        changeMonth = this._get(inst, "changeMonth"),
        changeYear = this._get(inst, "changeYear"),
        showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
        html = "<div class='ui-datepicker-title'>",
        monthHtml = "";

    // year selection
    if ( !inst.yearshtml ) {
        inst.yearshtml = "";
        if (secondary || !changeYear) {
            html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
        } else {
            // determine range of years to display
            years = this._get(inst, "yearRange").split(":");
            thisYear = new Date().getFullYear();
            determineYear = function(value) {
                var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
                    (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
                    parseInt(value, 10)));
                return (isNaN(year) ? thisYear : year);
            };
            year = determineYear(years[0]);
            endYear = Math.max(year, determineYear(years[1] || ""));
            year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
            endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
            inst.yearshtml += "<span class = 'dummy'>Foo</span> <select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"
            for (; year <= endYear; year++) {
                inst.yearshtml += "<option value='" + year + "'" +
                    (year === drawYear ? " selected='selected'" : "") +
                    ">" + year + "</option>";
            }
            inst.yearshtml += "</select>";


            html += inst.yearshtml;
            inst.yearshtml = null;
        }
    }

您的 JSFiddle 示例链接:http://jsfiddle.net/gGV3v/2/

更新:

去除按钮,采用更好的方法,现在您可以控制所有生成的HTML:

var oldGenerateHTML = $.datepicker._generateHTML;

function newGenerateHTML(inst) {
    var html = oldGenerateHTML.call(this, inst);
    var $html = $(html);
    $html.find('[data-handler=prev]').remove();
    $html.find('[data-handler=next]').remove();
    $html.find('[data-handler=selectMonth]').replaceWith('<span class="dummy">Foo</span>');
    return $html;
}

$.datepicker._generateHTML = newGenerateHTML;

Fiddle也更新了:http://jsfiddle.net/gGV3v/4/


就我所见,它的工作非常好。只需要进行一次编辑,您的代码没有更改日期,因为您忘记在<span class='dummy'></span>中包含文本foo。这是更新后的fiddle链接:http://jsfiddle.net/gGV3v/2/ - SexyBeast
当然,我错过了那部分。我已更新答案,谢谢。 - sergiogarciadev
但是我再次查看了答案,它也考虑了用户通过左上角和右上角的按钮浏览月份的部分。太棒了! - SexyBeast
顺便问一下,你能在if-else条件语句中添加更多注释吗? - SexyBeast
这是从datepicker.js源代码中获取的。我会更新答案并提供一个简化版本。 - sergiogarciadev
我仍然不太清楚_generateMonthYearHeader方法中变量的种类。特别是inst.yearshtml是什么意思,以及if ( !inst.yearshtml ) {...}条件语句的含义是什么。你能添加一些进一步的注释吗? - SexyBeast

1
一般来说,这就是为什么 extend 不好用。父元素(在你的情况下是 datepicker)对子元素(你的自定义 HTML)一无所知。每次刷新视图时,你的更改都会丢失。通常使用组合来解决这个问题。目标是创建自己的小部件(我认为 jQuery 中是这个术语),其中具有本地变量 datepicker,并控制 _generateMonthYearHeader 函数的调用。理论上很容易说,但在实践中(特别是 jQuery 的情况下)很难实现。更简单的解决方案是代理该函数。
//preserve _generateHTML because after it finish, html is visible and .ui-datepicker-month and .ui-datepicker-year are in dom tree
fn = $.datepicker._generateHTML; //preserve original function
$.datepicker._generateHTML = function(inst) {
    //call original function
    fn.call(this, inst);
    //do custom changes
    //you'll need better selectors in case of multiple datepicker instances
    $(".ui-datepicker-month").replaceWith("#custom-html-block");
    $(".ui-datepicker-year").replaceWith("#another-custom-html-block");   
}

个人而言,我不喜欢这种方法(正如我所说,我更喜欢组合),但在你的情况下,它会更容易实现。原因是generateMonthYearHeader从许多不同的函数中调用。
附注:未经测试。

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