“dojo”未定义_扩展Dojo dijits以创建自定义小部件

“dojo”未定义

Dojo Toolkit是一个功能强大JavaScript™库,它使Web开发人员可以使用面向对象的小部件以最少的开发时间和精力来创建Rich Internet Applications。 它带有四个软件包,分别称为Dojo (核心), Dijit (UI框架), dojox (dojo扩展)和util 。 您可以按原样使用工具箱提供的功能,也可以扩展它们并创建自己的窗口小部件。 提供的功能包括DOM操作,使用AJAX开发,事件,数据存储等。

Dijo(dojo小部件)包是dojo自己的UI库,其中包含dojo类的集合,这些类使开发人员可以轻松创建丰富而强大的跨平台Web 2.0界面。 这些Dijit小部件(或dijit)由易于操作的主题支持。 此程序包中的dijit示例包括按钮,文本字段,编辑器,进度条等等。

例如,使用这些dijit,您可以创建一个提交表单,其中包括姓名,电子邮件地址和电话号码的文本字段,以及日期字段,复选框,按钮和验证,所有这些都只需几分钟,而对JavaScript的了解却很少。

提供的最丰富的dijit之一是Calendar dijit,它使您可以在一个月的上下文中显示日历。 用户可以轻松地逐月,逐年导航,或跳至同一年的任何月份以选择特定日期。

在开发富Internet应用程序(RIA)时,通常可以按原样使用dijits。 但是,有时您可能需要使用不同的样式(例如更改颜色或主题),或者涉及更多涉及功能,模板和样式更改的组合。 您可以通过从头开始创建新的自定义窗口小部件或扩展现有dijit的自定义窗口小部件来满足这些要求。

本文提供了一个练习,您需要在网站上使用日历小部件的其他变体。 为了满足此要求,您将创建一个满足要求的新类。 本练习使用Dojo 1.7版,并提供了探索Calendar dijit和重用现有dijit的方法,并进行了最少的修改以节省开发时间。 您还将看到在Dojo 1.7中声明的新类的工作示例,并探索了一些Dojo基本函数,例如日期操纵,连接,发布和订阅等等。

问题

在本练习中,您将按照以下要求使用定制版本的Calendar dijit:

  • 日历应仅显示当月的日期(隐藏和禁用不属于当月的日期)。
  • 日历应仅在日历底部显示当前年份(无前几年或后几年)。
  • 日历应在日历小部件的顶部显示当前月份的名称。
  • 用户不能跳转到其他月份(禁用顶部的月份下拉按钮)。
  • 提取显示在日历顶部的箭头,以便逐月移动(向后或向前),并在日历旁边显示箭头代替dijit按钮。 这两个新按钮是用户更改月份的唯一方法。
  • 有最小和最大边界日期,这意味着该边界之外的所有日期都应被禁用且不可访问。
  • 到达边界日期时,禁用相应的月份导航按钮。
  • 为日历中的选定日期添加特殊样式。
  • 当用户选择日期时,将日期传递给将处理新选定值的函数。

解决方案是创建通过使用JavaScript和CSS编辑Calendar dijit开发的自定义窗口小部件。 图1显示了应用上述要求之前(左)和之后(右)的Calendar小部件。

图1.标准Calendar dijit与自定义Calendar小部件的比较
图1.标准Calendar dijit与自定义Calendar小部件的比较

为此,您将需要创建三个文件:

  • Dijit模板:一种标记,将显示自定义窗口小部件的组件。
  • Dijit类:使用声明(JavaScript)创建的小部件类。
  • CSS文件:包含所有必需的样式表类。

图2显示了自定义窗口小部件的文件结构和位置。 您的起点是index.html,在此示例中,它将充当小部件的控制器。 simple.css文件将包含所有样式。

图2.文件结构
图2.文件结构

创建小部件

dijit模板

创建三个JavaScript div元素:一个用于日历,两个用于箭头按钮,用于逐月向前和向后导航(清单1)。 div将使用附加点(data-dojo-attach-point)作为参考。 使用连接点比使用ID更好,因为它使您可以在同一页面上拥有同一窗口小部件的多个实例,而不必担心ID冲突。

清单1. dijit模板
<div class="CalendarArrow">
<div data-dojo-attach-point="calendarPreviousMonthButtonAP"></div>
</div>

<div class="CalendarDijit">
<span data-dojo-attach-point="calendarMonthOneAttachPoint"></span>
</div>

<div class="CalendarArrow">
<div data-dojo-attach-point="calendarFollowingMonthButtonAP"></div>
</div>

dijit类

根据应用程序需求,您需要定义以下变量:

  • selectedDate:日历的初始值。
  • currentFocusDate:日历引用以知道要显示的月份的值; 最初设置为与selectedDate等效。
  • calendarInstance: Dijit日历实例。
  • bookingWindowMaxDate:日历中允许的最后一天。
  • bookingWindowMinDate:日历中的第一个允许的日期。
  • onValueSelectedPublishIDString:表示发布/ 订阅频道(或主题)的字符串。

JavaScript函数

首先修改以下样式表元素:

  • 构造函数

    重写构造函数以复制从控制器传递的变量。 使用dojo / _base / lang / mixin,它将匹配变量名并将值复制到您的自定义小部件变量中(清单2)。

    清单2.构造函数
    constructor: function (args){
    	if(args){
    		lang.mixin(this,args);
    	}
    }
  • postCreate

    所有日期将以mm / dd / yyyy的en-us短格式作为字符串传递。 使用dojo / date / locale函数将所有日期字符串转换为date对象,用于selectedDate,bookingWindowMaxDate,bookingWindowMinDate(清单3)。

    清单3.使用dojo / date / locale
    this.bookingWindowMinDate = locale.parse(this.bookingWindowMinDate, {formatLength:
    'short', selector:'date', locale:'en-us'});

    创建日历对象的一个​​实例(清单4)。 创建的逻辑在createCalendar函数中。 您可以通过编程方式创建dijit日历的实例,并将其附加到将使用dojo / dom-construct创建的div(与dojo的较早版本中的dojo.create等效)。 通常,这是一个好习惯,因为它使您可以销毁日历而不会丢失附加点。

    清单4.返回dijit / Calendar的实例
    return new Calendar({
    	value : selectedDate,
    	currentFocus : selectedDate	},  domConstruct.create("div", {}, 
    	calendarAttachPoint));
    }

    请注意,您正在日历dijit中设置currentFocus值。 Calendar dijit将始终使用本地当前日期来显示其第一个登陆屏幕,因此,如果希望日历显示其他屏幕(日期),则必须设置currentFocus。 因此,对于您的自定义窗口小部件,您需要将日历的初始值和currentFocus设置为selectedDate(根据要求)。 对于此示例,这是2012年8月的一天。

为了满足其他要求,您需要重写Calendar dijit中的这三个功能:

  • isDisabledDate

    当日历dijit加载视图时,它将逐一遍历当前视图的天数(共42天),并每天调用isDisabledDate和getClassForDate函数(接下来介绍)。

    isDisabledDate函数用于禁用日历中的某些日期(清单5)。 如果函数返回true,则将禁用该日期。 日历每次刷新时,都会调用此函数,并将日历中的每一天传递给它。 对于您的自定义小部件,您需要:

    • 禁用不属于当前月份的任何一天:为此,您将使用dojo / date / difference函数,该函数根据时间间隔比较两个日期对象,如果相等则返回0。 您将使用月份间隔将currentFocusDate变量与当前视图中的每一天进行比较,如果它们不等于禁用日期,则返回true。
    • 禁用边界日期以外的日期:再次使用dojo / date / difference,但间隔设置为“ day”。 如果返回值小于bookingWindowMinDate或大于bookingWindowMaxDate,则返回true以禁用日期。
      清单5.覆盖isDisabledDate
      isDisabledDate: function(date) {
       //disable any day that doesn't belong to current month
      	if(dojoDate.difference(parent.currentFocusDate, date, "month")!==0){
      		return true;
      	}
      	if(dojoDate.difference(parent.bookingWindowMinDate, date, "day" || 
      dojoDate.difference(parent.bookingWindowMaxDate, date, "day")<0){
      		return true;
      	}
      	else {
      		return false;
      	}
      }
  • getClassForDate

    尽管使用isDisabledDate禁用了不属于当前月份视图的日期,但是您也需要隐藏它们。 getClassForDate函数用于返回CSS类名称,以在日历上标记不同的日期。 对于您的自定义窗口小部件,您需要通过向该日期添加带有黑色边框的蓝色框来指示selectedDate(清单6)。 您还需要用灰色指示最小和最大边界之外的日期,并隐藏不属于当前月份的日期。

    要标识需要使用不同样式设置的日期,可以使用dojo / date / compare,它将采用两个日期值(日期对象)和部分(字符串),如果相等则返回0。 在这里,您将传递currentFocusDate,迭代中的日期和“日期”作为部分,因为您仅对比较日期而没有时间戳感兴趣。 如果此比较返回0,则此函数将返回CSS文件中定义的类“ Available”(清单7)。 您将使用CSS .class选择器来定位我们要更改的特定元素。

    清单6.覆盖getClassForDate
    getClassForDate: function(date) {	
    	if ( dojoDate.compare(date,selectedDate,"date") === 0) {
    		return "Available";
    	} // apply special style
    }
    清单7.标记可用日期CSS类
    .AvailabilityCalendars .Calendars .CalendarDijit .Available 
    	.dijitCalendarDateLabel
    {
            background-color: #bccedc !important;
            border: 1px solid #000000 !important;
    }

    如果使用isDisabledDate中的条件,您将使用相同的条件来标识超出边界的日期和不属于当前月份的日期,但返回CSS类名称(清单8和9)。

    清单8.隐藏和禁用日期
    if(dojoDate.difference(parent.currentFocusDate, date, "month")!==0){ 
    	return "HiddenDay";
    }
    if(dojoDate.difference(parent.bookingWindowMinDate, date, "day")<0 || 
    	dojoDate.difference(parent.bookingWindowMaxDate, date, "day")>0){
    	return "Disabled";
    }
    清单9.标记隐藏和禁用日期CSS类
    .AvailabilityCalendars .Calendars .CalendarDijit .HiddenDay 
    	.dijitCalendarDateLabel
    {
        background-color: #ffffff !important;
        border-color: #ffffff;
        color: #ffffff;
    }
    
     .AvailabilityCalendars .Calendars .CalendarDijit .Disabled 
    	.dijitCalendarDateLabel
    {
    	background-color: #9c9c9c;
    }
  • onChange

    仅当您为日历设置新值或在日历上选择启用的日期时,才会调用此函数(清单10)。 此函数返回所选日期的日期对象。 您将使用该日期将日期发布到另一个处理日期的方法。 调用在自定义窗口小部件中定义的函数(onValueSelected),在发布到控制器之前,可以在其中进行任何需要的处理(清单11)。 在此示例中,您将只使用dojo / _base / connect / publish将日期发布到控制器。 频道(或主题)字符串存储在变量onValueSelectedPublishIDString中。

    清单10.使用Calendar的onChange和拖挂
    onChange : lang.hitch(this, function(date){
    	this.onValueSelected(date);
    })
    清单11.使用发布
    onValueSelected : function (date){
    	connect.publish(this.onValueSelectedPublishIDString, [date]);
    }

    注意,您使用了dojo / _base / lang / hitch来提供范围来调用函数onValueSelected(清单10)。 您的控制器(在这种情况下为index.html)将拥有该频道的订阅者来处理日期(清单12)。 在此示例中,您仅记录它。 您可以将其替换为任何其他必需的逻辑。

    清单12.我们发布的订阅者
    connect.subscribe("selectedValueID", function(date){
      //Do some processing 
      console.log("New Selected Date: ", date);
    });

日历dijit附带标头处的monthDropDownButton。 此按钮显示所有月份的列表,并允许用户跳至任何月份。 为了满足要求,您需要通过将monthWidget设置为“ disabled”来禁用此按钮(清单13)。

清单13.在Calendar标头中禁用下拉按钮
this.calendarInstance.monthWidget.set("disabled", true);

从可用性的角度来看,您还需要隐藏箭头,以免用户被迫单击。 为此,添加将针对您要操作的元素CSS类(清单14)。

清单14.隐藏下拉按钮箭头CSS类
.AvailabilityCalendars .Calendars .CalendarDijit .dijitDropDownButton 
	.dijitArrowButtonInner
{
    visibility: hidden;
}

接下来,使用CSS类隐藏前几年和后几年的数字,使其不显示在底部(清单15)。

清单15.隐藏日历底部的年份数字CSS类
.AvailabilityCalendars .Calendars .CalendarDijit .dijitCalendarPreviousYear, 
	.dijitCalendarNextYear
    {
padding: 1px 6px;
visibility: hidden;
    }

您还将隐藏顶部的箭头,否则将使用户能够逐月移动(清单16)。

清单16.隐藏日历顶部的月箭头CSS类
.AvailabilityCalendars .Calendars .CalendarDijit .dijitCalendarArrow
{
     visibility: hidden;
}

接下来,创建两个新按钮,使用户可以浏览月份。 使用dijit / form / Button并以编程方式创建它们。 对于第一个按钮(向后),将标签设置为“ <<”,并覆盖onClick函数(清单17)。 onClick的逻辑将在goToPreviousMonth函数中。

清单17.创建dijit / form / bottom的实例
this.calendarPreviousMonthButton = new Button({
       label: "<<",	
       onClick: lang.hitch(this, function(){
    	   this.goToPreviousMonth(this.calendarInstance);
       })
}, this.calendarPreviousMonthButtonAP);

您希望日历在用户每次单击按钮时向后移动一个月。 在goToPreviousMonth中,您需要首先将currentFocusDate更改为currentFocusDate-1月,然后刷新日历视图。 最后,您必须检查这是否是显示的最后一个月,如果是,请禁用该按钮。

使用dojo / date / add函数,该函数需要一个日期对象,时间间隔(字符串)和金额(整数)。 对于您的情况,日期将为currentFocusDate对象,时间间隔为“月”,金额为-1(清单18)。

清单18.日历视图减少了一个月
this.currentFocusDate = dojoDate.add(this.currentFocusDate,"month",-1);
calendarInstance.set("currentFocus",this.currentFocusDate);

通过使用新的日期值设置currentFocus来设置日历的新视图。 (这将自动刷新日历并显示新视图)。

最后,通过将currentFocusDate与最小边界进行比较,检查这是否是上个月的视图; 如果是,则禁用向后按钮。 另外,检查是否应启用前进按钮(以防万一它已被禁用,而现在您正在远离最大边界)(清单19)。

清单19.检查是否应该禁用新的导航按钮
if(this.isLastCalendarMonth(this.bookingWindowMinDate, this.currentFocusDate)){
	this.calendarPreviousMonthButton.set("disabled", true);
}
if(!this.isLastCalendarMonth(this.bookingWindowMaxDate, this.currentFocusDate)){
	this.calendarFollowingMonthButton.set("disabled", false);
}

第二个按钮以相同的方式工作。 标签将为“ >>”,并且onClick调用goToNextMonth,该函数使用相同的功能,只不过您增加了一个月(清单20)。

清单20.控制按钮移动到下个月的函数
goToNextMonth : function (calendarInstance){
	this.currentFocusDate = dojoDate.add(this.currentFocusDate,"month",1);
	calendarInstance.set("currentFocus",this.currentFocusDate);
	if(this.isLastCalendarMonth(this.bookingWindowMaxDate, this.currentFocusDate)){
		this.calendarFollowingMonthButton.set("disabled", true);
	}	
	if(!this.isLastCalendarMonth(this.bookingWindowMinDate, this.currentFocusDate)){
		this.calendarPreviousMonthButton.set("disabled", false);
	}
}

最后,清单21显示了控制器类中的示例,它将调用以实例化新的customCalendar。

清单21.有关如何创建新的自定义日历小部件的实例的快照
require(["myUtil/customCalendar","dojo/_base/connect"], function(myCalendar, connect){
	var params = {
		"bookingWindowMinDate":"10/9/2011",
		"bookingWindowMaxDate":"10/9/2012",
		"selectedDate":"8/15/2012",
		"onValueSelectedPublishIDString":"selectedValueID"
	};
	var myTest = myCalendar(params);
	myTest.placeAt("nodeId", "last");
		
	connect.subscribe("selectedValueID", function(date){
	  //Do some processing 
	  console.log("I got: ", date);
	});	
	
});

如您所见,您正在创建一个对象参数,该参数具有传递给自定义日历窗口小部件并订阅通道所需的值。

更多功能

在这种情况下,您可能会发现其他一些有用的功能和属性:

  • 当您将日期对象和语言环境传递到dojo / date / locale / isWeekend时,如果该天是周末(对于美国语言环境为星期六和星期日),则返回true。 如果需要,可以使用它来禁用或设置周末的样式。
  • Calendar dijit还包含将字符串作为值的dayWidth属性。 默认情况下,它设置为“ narrow”,这将缩短显示的日历日,例如,缩短为“ M”而不是星期一。 其他值是“宽”用于全天姓名显示,“ abbr”用于缩写(例如“ Mon”)。

这些自定义窗口小部件要求的变体可能要求窗口小部件显示多个日历,然后在用户单击查看下个月时要求两个日历都前进(图3)。 通过更改窗口小部件变量以支持数组而不是单个值变量,可以轻松实现这一点。

图3.每个视图有多个日历
图3.每个视图有多个日历

结论

通过结合JavaScript和CSS修改,您可以轻松创建自定义窗口小部件,以更好地满足您的项目要求。 本文演示了使用Dojo 1.7声明扩展Calendar dijit的类的实践,并探讨了一些dojo功能,例如日期操纵,挂接,发布和订阅以及其他基本dojo函数。 希望您将能够应用这些步骤来扩展Dojo dijit并创建自己的新窗口小部件。


翻译自: https://www.ibm.com/developerworks/websphere/techjournal/1209_weller/1209_weller.html

“dojo”未定义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值