Home > Web Front-end > JS Tutorial > body text

How to develop a two-dimensional week view calendar using Javascript

亚连
Release: 2018-06-20 16:56:08
Original
1726 people have browsed it

This article mainly introduces you to the relevant information on how to use Javascript to develop a two-dimensional weekly view calendar. The article introduces it in great detail through sample code. It has certain reference learning value for everyone's study or work. It is needed Friends, please follow the editor to learn together.

Preface

This article introduces to you the relevant content of Javascript development of two-dimensional weekly view calendar, that is, a month view calendar was previously implemented. Today we will implement a two-dimensional week view calendar.

The key parts are analyzed below.

Structure preparation

The difference is that it also has a classification axis based on the calendar to display different categories. Mainly used for scheduling, meeting arrangements, etc. within a week.

The two-dimensional calendar is different from the previous single one. When switching dates, the two-dimensional calendar does not need to be re-rendered. The classification does not need to be changed, only the displayed date is changed.

And because it is two-dimensional, the inserted content must belong to a category and a time period at the same time. The content can definitely span time (that is, the date axis), so the inserted content cannot be directly inserted like the beginning The calendar is placed directly in the calendar grid. But to be processed separately.

In addition, as long as the classification remains unchanged, the grid composed of dates and categories does not need to be redrawn.

Considering the above situation, the insertion of content and the grid need to be separated. I made the ready-made calendar into a 3D effect:

That is, the layer for inserting content is placed separately above the grid composed of time and category.

Based on the above analysis, first build the following basic structure:

<p class="ep-weekcalendar border">
 <!-- 头部 -->
 <p class="ep-weekcalendar-header">
 <p class="ep-weekcalendar-header-left"></p>
 <p class="ep-weekcalendar-header-center">
 <span class="ep-weekcalendar-header-btn ep-weekcalendar-header-btn-prev"></span>
 <span class="ep-weekcalendar-title">2017年12月04日 - 10日</span>
 <span class="ep-weekcalendar-header-btn ep-weekcalendar-header-btn-next"></span>
 </p>
 <p class="ep-weekcalendar-header-right"></p>
 </p>
 <!-- 主体 -->
 <p class="ep-weekcalendar-body">
 <!-- 分类区域 -->
 <p class="ep-weekcalendar-category-area">
 <p class="ep-weekcalendar-category-header">
 <span class="ep-weekcalendar-category-title">车辆</span>
 </p>
 <ul class="ep-weekcalendar-category-list">
 </ul>
 </p>
 <!-- 内容区域 -->
 <p class="ep-weekcalendar-time-area">
 <!-- 每周日期渲染区域。切换日期时重新绘制内容 -->
 <p class="ep-weekcalendar-weeks"></p>
 <p class="ep-weekcalendar-main">
 <!-- 分类和内容构建的网格区域,仅在分类改变时进行调整 -->
 <p class="ep-weekcalendar-grid"> </p>
 <!-- 可插入任意内容的区域,日期切换时清空,根据使用需求插入内容 -->
 <p class="ep-weekcalendar-content"></p>
 </p>
 </p>
 </p>
 <!-- 底部 -->
 <p class="ep-weekcalendar-body"></p>
</p>
Copy after login

The structure is as above, and the implementation code does not need to be shown.

Drawing implementation

After the necessary structure is initially completed, we proceed with the drawing of the calendar.

Classification Drawing

The first thing to deal with is classification. In the weekly view, the number of days in a week is fixed. Only when the classification is determined can the main part of the grid be drawn.

For classification, temporarily consider the following necessary data format:

{
 id: &#39;cate-1&#39;, // 分类ID
 name: &#39;法拉利&#39;, // 分类名称
 content: &#39;苏E00000&#39; // 分类的具体描述
}
Copy after login

The implementation is as follows:

{
 // 设置分类数据
 setCategory: function (data) {
 if (!(data instanceof Array)) {
 this.throwError(&#39;分类数据必须是一个数组&#39;);
 return;
 }
 this._categoryData = data;

 // 绘制分类
 this._renderCatagories();
 // 绘制其他需要改变的部分
 this._renderChanged();
 },
 // 左侧分类渲染
 _renderCatagories: function () {
 this._categoryListEl.innerHTML = &#39;&#39;;
 var i = 0,
 data = this._categoryData,
 node = document.createElement(&#39;li&#39;),
 cataEl;
 node.className = &#39;ep-weekcalendar-category&#39;;
 // 用行作为下标记录当前分类id集合
 this._categoryIndexs = [];
 // id为键记录索引
 this._categoryReocrds = {};
 while (i < data.length) {
 this._categoryIndexs.push(data[i].id);
 this._categoryReocrds[data[i].id] = i;
 cataEl = node.cloneNode(true);
 this._rendercategory(data[i], cataEl);
 i++;
 }
 },
 _rendercategory: function (cate, cateEl) {
 cateEl.setAttribute(&#39;data-cateid&#39;, cate.id);
 var titleEl = document.createElement(&#39;span&#39;),
 contentEl = document.createElement(&#39;span&#39;);
 titleEl.className = &#39;title&#39;;
 contentEl.className = &#39;content&#39;;
 titleEl.innerHTML = cate.name;
 contentEl.innerHTML = cate.content;
 cateEl.appendChild(titleEl);
 cateEl.appendChild(contentEl);
 this.fire(&#39;categoryRender&#39;, {
 categoryEl: cateEl,
 titleEl: titleEl,
 contentEl: contentEl
 });
 this._categoryListEl.appendChild(cateEl);
 this.fire(&#39;agterCategoryRender&#39;, {
 categoryEl: cateEl,
 titleEl: titleEl,
 contentEl: contentEl
 });
 }
}
Copy after login

The above sets the classification data setCategory as the entry point to call the drawing classification method, which also calls _renderChanged This method is used to redraw the variable parts of the calendar, such as the title, date and its contents, which will be introduced later.

Date drawing

The classification axis has been prepared above, and the date axis needs to be drawn. For the week view, the implementation of the week It's very simple, just render 7 days in sequence based on the start date of the week. Pay attention to providing the necessary information of the date to the corresponding event during the drawing process, so that the user can personalize the event.

{
 // 渲染日历的星期
 _renderWeeks: function () {
 this._weeksEl.innerHTML = &#39;&#39;;
 var i = 0,
 currDate = this._startDate.clone(),
 node = document.createElement(&#39;p&#39;),
 week;
 node.className = &#39;ep-weekcalendar-week&#39;;
 // 单元格列作为下标记录日期
 this._dateRecords = [];
 while (i++ < 7) {
 // 更新记录日期
 this._dateRecords.push(currDate.clone());
 week = node.cloneNode(true);
 this._renderWeek(currDate, week);
 currDate.add(1, &#39;day&#39;);
 }
 // 切换日期 需要重绘内容区域
 this._rednerContent();
 },
 _renderWeek: function (date, node) {
 var dateText = date.format(&#39;YYYY-MM-DD&#39;),
 day = date.isoWeekday();
 if (day > 5) {
 node.className += &#39; weekend&#39;;
 }
 if (date.isSame(this.today, &#39;day&#39;)) {
 node.className += &#39; today&#39;;
 }
 node.setAttribute(&#39;data-date&#39;, dateText);
 node.setAttribute(&#39;date-isoweekday&#39;, day);
 var ev = this.fire(&#39;dateRender&#39;, {
 // 当前完整日期
 date: dateText,
 // iso星期
 isoWeekday: day,
 // 显示的文本
 dateText: &#39;周&#39; + this._WEEKSNAME[day - 1] + &#39; &#39; + date.format(&#39;MM-DD&#39;),
 // classname
 dateCls: node.className,
 // 日历el
 el: this.el,
 // 当前el
 dateEl: node
 });
 // 处理事件的修改
 node.innerHTML = ev.dateText;
 node.className = ev.dateCls;
 this._weeksEl.appendChild(node);
 this.fire(&#39;afterDateRender&#39;, {
 // 当前完整日期
 date: dateText,
 // iso星期
 isoWeekday: day,
 // 显示的文本
 dateText: node.innerHTML,
 // classname
 dateCls: node.className,
 // 日历el
 el: this.el,
 // 当前el
 dateEl: node
 });
 }
}
Copy after login

Grid and content

The two axes in the two-dimensional view have been prepared above, and then the grid and content layer can be drawn.

Grid

Here the categories are drawn in the Y direction (rows) and the dates are drawn in the X direction (columns):

{
 // 右侧网格
 _renderGrid: function () {
 this._gridEl.innerHTML = &#39;&#39;;
 var rowNode = document.createElement(&#39;p&#39;),
 itemNode = document.createElement(&#39;span&#39;),
 rowsNum = this._categoryData.length,
 i = 0,
 j = 0,
 row, item;
 rowNode.className = &#39;ep-weekcalendar-grid-row&#39;;
 itemNode.className = &#39;ep-weekcalendar-grid-item&#39;;
 while (i < rowsNum) {
 row = rowNode.cloneNode();
 row.setAttribute(&#39;data-i&#39;, i);
 j = 0;
 while (j < 7) {
 item = itemNode.cloneNode();
 // 周末标识
 if (this.dayStartFromSunday) {
  if (j === 0 || j === 6) {
  item.className += &#39; weekend&#39;;
  }
 } else {
  if (j > 4) {
  item.className += &#39; weekend&#39;;
  }
 }
 item.setAttribute(&#39;data-i&#39;, i);
 item.setAttribute(&#39;data-j&#39;, j);
 row.appendChild(item);

 j++;
 }
 this._gridEl.appendChild(row);

 i++;
 }
 rowNode = itemNode = row = item = null;
 }
}
Copy after login

Content

Theoretically speaking, two dimensions should support both cross-row and cross-column situations, that is, the content area should be a whole block of elements. But when combined with actual situations, cross-time requirements are common (one thing is used continuously over a period of time). Cross-classification does not have much practical significance. It must be managed separately by classification, and then cross-classification becomes complicated again. And even if it is necessary to use multiple things at the same time for a period of time, it can be implemented directly (category A is used in the XX time period, and B is used in the XX time period, but the XX is exactly the same at this time).

Therefore, only cross-time situations are dealt with here. The content can be drawn by rows or categories, which can simplify many calculations when inserting content components.

{
 // 右侧内容
 _rednerContent: function () {
 this._contentEl.innerHTML = &#39;&#39;;
 var i = 0,
 node = document.createElement(&#39;p&#39;),
 row;
 node.className = &#39;ep-weekcalendar-content-row&#39;;
 while (i < this._categoryData.length) {
 row = node.cloneNode();
 row.setAttribute(&#39;data-i&#39;, i);

 this._contentEl.appendChild(row);
 ++i;
 }
 row = node = null;
 },
 // 日期切换时清空内容
 _clearContent: function () {
 var rows = this._contentEl.childNodes,
 i = 0;
 while (i < rows.length) {
 rows[i].innerHTML && (rows[i].innerHTML = &#39;&#39;);
 ++i;
 }
 // 部件数据清空
 this._widgetData = {};
 }
}
Copy after login

If you must achieve cross-row and cross-column situations, you can directly draw the content into a whole block of elements. However, when clicking events and inserting content components, you need to calculate the corresponding classification and date and time at the same time.

Difficulties in implementation

Content component insertion

We implement this two-dimensional week view calendar The main purpose is to support the insertion of arbitrary content. The DOM element for inserting content has been prepared above. What needs to be done here is to draw the data into DOM and place it in the appropriate position.

Consider the necessary content component data structure as follows:

{
 id: &#39;数据标识&#39;,
 categoryId: &#39;所属分类标识&#39;,
 title: &#39;名称&#39;,
 content: &#39;内容&#39;,
 start: &#39;开始日期时间&#39;
 end: &#39;结束日期时间&#39;
 bgColor: &#39;展示的背景色&#39;
}
Copy after login

Since the content area is drawn directly according to the classification, the corresponding classification already exists after getting the data. The key point is to calculate the start and end positions based on the specified start and end times.

Consider the following:

  • Consider responsiveness, and the position calculation is based on percentage

  • 一周的总时间是固定的,开始日期时间和这周开始日期时间的差额占总时间的百分比即开始位置的百分比

  • 结束日期时间和开始时间的差额占总时间的百分比即为结束时间距离最左侧的百分比

  • 注意处理开始和结束时间溢出本周的情况

因此关于位置计算可以用如下代码处理:

{
 // 日期时间分隔符 默认为空 对应格式为 &#39;2017-11-11 20:00&#39;
 // 对于&#39;2017-11-11T20:00&#39; 这样的格式务必指定正确的日期和时间之间的分隔符T
 _dateTimeSplit:&#39; &#39;,
 // 一周分钟数
 _WEEKMINUTES: 7 * 24 * 60,
 // 一周秒数
 _WEEKSECONDS: 7 * 24 * 3600,
 // 一天的分钟数秒数
 _DAYMINUTES: 24 * 60,
 _DAYSCONDS: 24 * 3600,
 // 计算位置的精度 取值second 或 minute
 posUnit: &#39;second&#39;,
 // 计算指定日期的分钟或秒数
 _getNumByUnits: function (dateStr) {
 var temp = dateStr.split(this._dateTimeSplit),
  date = temp[0];
 // 处理左侧溢出
 if (this._startDate.isAfter(date, &#39;day&#39;)) {
  // 指定日期在开始日期之前
  return 0;
 }
 // 右侧溢出直接算作第7天即可
 var times = (temp[1] || &#39;&#39;).split(&#39;:&#39;),
  days = (function (startDate) {
  var currDate = startDate.clone(),
   i = 0,
   d = moment(date, &#39;YYYY-MM-DD&#39;);
  while (i < 7) {
   if (currDate.isSame(d, &#39;day&#39;)) {
   return i;
   } else {
   currDate.add(1, &#39;day&#39;);
   ++i;
   }
  }
  console && console.error && console.error(&#39;计算天数时出错!&#39;);
  return i;
  }(this._startDate)),
  hours = parseInt(times[0], 10) || 0,
  minutes = parseInt(times[1], 10) || 0,
  seconds = parseInt(times[2], 10) || 0,
  // 对应分钟数
  result = days * this._DAYMINUTES + hours * 60 + minutes;
 return this.posUnit == &#39;minute&#39; ? result : (result * 60 + seconds);
 },
 // 计算日期时间的百分比位置
 _getPos: function (dateStr) {
 var p = this._getNumByUnits(dateStr) / (this.posUnit == &#39;minute&#39; ? this._WEEKMINUTES : this._WEEKSECONDS);
 return p > 1 ? 1 : p;
 }
}
Copy after login

上面就拿到了一个数据所对应的开始位置和结束位置。基本上是已经完成了,但是还需要再处理一个情况:相同分类下的时间冲突问题。

考虑以如下方式进行:

  • 没添加一个就记录下其数据

  • 新增的如果和当前分类下已有的存在时间重叠,则认为冲突。

实现如下:

{
 /**
 * 检查是否发生重叠
 *
 * @param {Object} data 当前要加入的数据
 * @returns false 或 和当前部件重叠的元素数组
 */
 _checkOccupied: function (data) {
 if (!this._widgetData[data.categoryId]) {
  return false;
 }
 var i = 0,
  cate = this._widgetData[data.categoryId],
  len = cate.length,
  result = false,
  occupied = [];
 for (; i < len; ++i) {
  // 判断时间是否存在重叠
  if (data.start < cate[i].end && data.end > cate[i].start) {
  occupied.push(cate[i]);
  result = true;
  }
 }
 return result ? occupied : false;
 }
}
Copy after login

完成以上两步就可以往我们的内容区域中插入了

{
 // 缓存widget数据
 _cacheWidgetData: function (data) {
 if (!this._widgetData[data.categoryId]) {
  this._widgetData[data.categoryId] = [];
 }
 // 记录当前的
 this._widgetData[data.categoryId].push(data);
 },
 // 新增一个小部件
 addWidget: function (data) {
 var row = this._contentEl.childNodes[this._categoryReocrds[data.categoryId]];
 if (!row) {
  this.throwError(&#39;对应分类不存在,添加失败&#39;);
  return false;
 }
 // 先查找是否含有
 var $aim = jQuery(&#39;.ep-weekcalendar-content-widget[data-id="&#39; + data.id + &#39;"]&#39;, row);
 if ($aim.length) {
  // 已经存在则不添加
  return $aim[0];
 }
 // 创建部件
 var widget = document.createElement(&#39;p&#39;),
  title = document.createElement(&#39;span&#39;),
  content = document.createElement(&#39;p&#39;),
  startPos = this._getPos(data.start),
  endPos = this._getPos(data.end),
  _data = {
  categoryId: data.categoryId,
  id: data.id,
  start: startPos,
  end: endPos,
  el: widget,
  data: data
  };
 widget.className = &#39;ep-weekcalendar-content-widget&#39;;
 title.className = &#39;ep-weekcalendar-content-widget-title&#39;;
 content.className = &#39;ep-weekcalendar-content-widget-content&#39;;
 widget.appendChild(title);
 widget.appendChild(content);
 // 通过绝对定位,指定其left和right来拉开宽度的方式来处理响应式
 // 可以通过样式设置一个最小宽度,来避免时间段过小时其中文本无法显示的问题
 widget.style.left = startPos * 100 + &#39;%&#39;;
 widget.style.right = (1 - endPos) * 100 + &#39;%&#39;;
 data.bgColor && (widget.style.backgroundColor = data.bgColor);
 data.id && widget.setAttribute(&#39;data-id&#39;, data.id);
 widget.setAttribute(&#39;data-start&#39;, data.start);
 widget.setAttribute(&#39;data-end&#39;, data.end);
 title.innerHTML = data.title;
 data.content && (content.innerHTML = data.content);
 widget.title = data.title;
 // 检查是否发生重叠
 var isoccupied = this._checkOccupied(_data);
 if (isoccupied) {
  // 触发重叠事件
  var occupiedEv = this.fire(&#39;widgetoccupied&#39;, {
  occupiedWidgets: (function () {
   var arr = [];
   for (var i = 0, l = isoccupied.length; i < l; ++i) {
   arr.push(isoccupied[i].el);
   }
   return arr;
  })(),
  currWidget: widget,
  widgetData: data
  });
  // 取消后续执行
  if (occupiedEv.cancel) {
  return false;
  }
 }
 // 缓存数据
 this._cacheWidgetData(_data);
 var addEv = this.fire(&#39;widgetAdd&#39;, {
  widgetId: data.id,
  categoryId: data.categoryId,
  start: data.start,
  end: data.end,
  startPos: startPos,
  endPos: endPos,
  widgetEl: widget
 });
 if (addEv.cancel) {
  return false;
 }
 row.appendChild(widget);
 this.fire(&#39;afterWidgetAdd&#39;, {
  widgetId: data.id,
  categoryId: data.categoryId,
  start: data.start,
  end: data.end,
  startPos: startPos,
  endPos: endPos,
  widgetEl: widget
 });
 return widget;
 },
}
Copy after login

点击事件和范围选择

此控件不仅用于结果展示,还要可用于点击进行添加,需要处理其点击事件,但是由于要展示内容,内容是覆盖在分类和日期构成的网格之上的,用户的点击是点击不到网格元素的,必须要根据点击的位置进行计算来获取所点击的日期和所在分类。

同时,由于展示的部件都是时间范围的,因此点击返回某天和某个分类是不够的,还需要能够支持鼠标按下拖动再松开,来直接选的一段时间。

考虑到以上需求,点击事件不能直接使用 click 来实现,考虑使用 mousedown 和 mouseup 来处理点击事件,同时需要在 mousemove 中实时给出用户响应。

{
 _initEvent: function () {
 var me = this;
 // 点击的行索引
 var row,
  // 开始列索引
  columnStart,
  // 结束列索引
  columnEnd,
  // 是否在按下、移动、松开的click中
  isDurringClick = false,
  // 是否移动过 用于处理按下没有移动直接松开的过程
  isMoveing = false,
  $columns,
  // 网格左侧宽度
  gridLeft,
  // 每列的宽度
  columnWidth
 jQuery(this.el)
  // 按下鼠标 记录分类和开始列
  .on(&#39;mousedown.weekcalendar&#39;, &#39;.ep-weekcalendar-content-row&#39;, function (e) {
  isDurringClick = true;
  gridLeft = jQuery(me._gridEl).offset().left;
  columnWidth = jQuery(me._gridEl).width() / 7;
  jQuery(me._gridEl).find(&#39;.ep-weekcalendar-grid-item&#39;).removeClass(me._selectedCls);
  row = this.getAttribute(&#39;data-i&#39;);
  $columns = jQuery(me._gridEl).find(&#39;.ep-weekcalendar-grid-row&#39;).eq(row).children();

  columnStart = (e.pageX - gridLeft) / columnWidth >> 0;
  });
 // 移动和松开 松开鼠标 记录结束列 触发点击事件 
 // 不能直接绑定在日期容器上 否则鼠标移出日历后,松开鼠标,实际点击已经结束,但是日历上处理不到。
 jQuery(&#39;body&#39;)
  // 点击移动过程中 实时响应选中状态
  .on(&#39;mousemove.weekcalendar&#39;, function (e) {
  if (!isDurringClick) {
   return;
  }
  isMoveing = true;
  // 当前列索引
  var currColumn;
  // mousemoveTimer = setTimeout(function () {
  currColumn = (e.pageX - gridLeft) / columnWidth >> 0;
  // 修正溢出
  currColumn = currColumn > 6 ? 6 : currColumn;
  currColumn = currColumn < 0 ? 0 : currColumn;
  $columns.removeClass(me._selectedCls);
  // 起止依次选中
  var start = Math.min(columnStart, currColumn),
   end = Math.max(columnStart, currColumn);
  do {
   $columns.eq(start).addClass(me._selectedCls);
  } while (++start <= end);
  })
  // 鼠标松开
  .on(&#39;mouseup.weekcalendar&#39;, function (e) {
  if (!isDurringClick) {
   return;
  }
  var startIndex = -1,
   endIndex = -1;
  columnEnd = (e.pageX - gridLeft) / columnWidth >> 0;
  columnEnd = columnEnd > 6 ? 6 : columnEnd;
  // 没有移动过时
  if (!isMoveing) {
   startIndex = endIndex = columnEnd;
   // 直接down up 没有move的过程则只会有一个选中的,直接以结束的作为处理即可
   $columns.eq(columnEnd).addClass(me._selectedCls)
   .siblings().removeClass(me._selectedCls);
  } else {
   startIndex = Math.min(columnStart, columnEnd);
   endIndex = Math.max(columnStart, columnEnd);
  }
  // 触发点击事件
  me.fire(&#39;cellClick&#39;, {
   // 分类id 
   categoryId: me._categoryIndexs[row],
   // 时间1
   startDate: me._dateRecords[startIndex].format(&#39;YYYY-MM-DD&#39;),
   // 日期2
   endDate: me._dateRecords[endIndex].format(&#39;YYYY-MM-DD&#39;),
   // 行索引
   rowIndex: row,
   // 列范围
   columnIndexs: (function (i, j) {
   var arr = [];
   while (i <= j) {
    arr.push(i++);
   }
   return arr;
   }(startIndex, endIndex))
  });
  row = columnStart = columnEnd = isMoveing = isDurringClick = false;
  });
 }
}
Copy after login

此过程要注意的问题是:mousedown 必须绑定在日历上,而 mouseup 和 mousemove 则不能绑定在日历上,具体原因已经写在上面代码注释中了。

另外需要注意,由于范围点击选择使用了 mousedown 和 mouseup 来模拟,那么日历内容区域中插入的数据部件的点击事件也要用 mousedown 和 mouseup 来模拟,因为 mouseup 触发比 click 早,如果使用 click ,会导致先触发日历上的日期点击或日期范围点击。

使用

此日历实现基于一个控件基类扩展而来,其必要功能仅为一套事件机制,可参考实现一套自定义事件机制

实测一下效果吧:

<p id="week-calendar" style="width:100%;height:80vh"></p>
<script>
var calendar = epctrl.init(&#39;WeekCalendar&#39;, {
 el: &#39;#week-calendar&#39;,
 categoryTitle: &#39;车辆&#39;,
 category: [{
 id: &#39;cate-1&#39;,
 name: &#39;法拉利&#39;,
 content: &#39;苏E00000&#39;
 }, {
 id: &#39;cate-2&#39;,
 name: &#39;Lamborghini&#39;,
 content: &#39;苏E00001&#39;
 }, {
 id: &#39;cate-3&#39;,
 name: &#39;捷豹&#39;,
 content: &#39;苏E00002&#39;
 }, {
 id: &#39;cate-4&#39;,
 name: &#39;宾利&#39;,
 content: &#39;苏E00003&#39;
 }, {
 id: &#39;cate-5&#39;,
 name: &#39;SSC&#39;,
 content: &#39;苏E00004&#39;
 }],
 events: {
 // 日期变化时触发
 dateChanged: function (e) {
  var data = {
  start: e.startDate,
  end: e.endDate,
  };
  // 获取数据并逐个添加到日历上
  getData(data).done(function (data) {
  $.each(data, function (i, item) {
   calendar.addWidget(item);
  });
  });
 },
 // 部件重叠时触发
 widgetOccupied: function (e) {
  // 冲突时禁止继续添加
  console.error(e.widgetData.categoryId + &#39;分类下id为&#39; + e.widgetData.id + &#39;的部件和现有部件有重叠,取消添加&#39;);
  e.cancel = true;
 }
 }
});
calendar.on(&#39;dateClick&#39;, function (e) {
 alert(JSON.stringify({
 &#39;开始时间&#39;: e.startDate,
 &#39;结束时间&#39;: e.endDate,
 &#39;分类id&#39;: e.categoryId,
 &#39;行索引&#39;: e.rowIndex,
 &#39;列索引范围&#39;: e.columnIndexs
 }, 0, 4));
});
</script>
Copy after login

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在js中如何实现登录需要滑动验证

在js中如何实现判断文件类型大小

在vue中如何使用cdn优化

使用js如何实现各种排序方法

使用JavaScript如何实现猜拳游戏(详细教程)

如何使用node模块与npm包管理工具

The above is the detailed content of How to develop a two-dimensional week view calendar using Javascript. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template