Create calendar class only

Related tags

Calendar u-calendar
Overview

u-calendar

Create calendar class only

useage

first step:

npm install u-calendar --save

Second step:

import UCalendar from "u-calendar";

const calendar = new UCalendar(options);

examples

react

Calendar.tsx

calendar.prev()} /> {toolbarRender ? ( toolbarRender(currentYear, currentMonth) ) : (
{toolbarActions} {currentYear} {currentMonth} { const { checked } = e.target; calendar.setChecked(undefined, checked); }} style={{ marginLeft: 10 }} > {showMonthCheckbox ? '全月' : ''}
)} calendar.next()} />
    {weekCells.map((item, index) => { return (
  • {headerRender ? ( headerRender(item, index) ) : ( { const { checked } = e.target; calendar.setChecked(item.value, checked); }} > {item.name} )}
  • ); })}
    {dates.map((v, i) => { return (
  • { if (v.disabled) { return; } if (v.inView) { calendar.setChecked(v.timestamp); } if (typeof onCellClick === 'function') { onCellClick(v, i); } }} >
    {v.date}
    {cellRender ? cellRender(v, i, dates) : null}
  • ); })}
); }; export default memo(forwardRef(Calendar)); ">
import React, { useState, useEffect, memo, forwardRef, useImperativeHandle } from 'react';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { Checkbox } from 'antd';
import { CheckboxProps } from 'antd/es/checkbox';
import classnames from 'classnames';
import UCalendar from 'u-calendar';
import {
  CalendarInstance,
  CalendarProps,
  WeekCell,
  DateType,
  DateCell,
  DayType,
} from 'u-calendar/src/data.d';
import { getDateTimestamp, dateFomater } from 'u-calendar/src/utils';
import styles from './index.less';

interface ICalendarProps extends CalendarProps {
  value?: DateType;
  className?: string;
  from?: CalendarInstance;
  toolbarActions?: React.ReactNode | React.ReactNode[];
  onDateChange?: (payload: { year: string; month: string; dates: DateCell[] }) => void;
  onChange?: (value?: DateType) => void;
  onCellClick?: (cell: DateCell, index: number) => void;
  showMonthCheckbox?: boolean;
  showWeekCheckbox?: boolean;
  toolbarRender?: (currentYear: string, currentMonth: string) => React.ReactNode;
  headerRender?: (payload: WeekCell, index: number) => React.ReactNode;
  cellRender?: (cell: DateCell, index: number, rows: DateCell[]) => React.ReactNode;
}

function useCalendar(from?: CalendarInstance, optons?: CalendarProps): [CalendarInstance] {
  const formRef = React.useRef<CalendarInstance>();

  if (!formRef.current) {
    if (from) {
      formRef.current = from;
    } else {
      const calendar = new UCalendar(optons || {});

      formRef.current = calendar.getCalendar();
    }
  }

  return [formRef.current];
}

const SpanCell: React.FC<CheckboxProps> = ({ children }) => <span>{children}</span>;

const Calendar: React.ForwardRefRenderFunction<any, ICalendarProps> = (props, ref: any) => {
  const {
    className,
    from,
    toolbarActions,
    toolbarRender,
    headerRender,
    cellRender,
    showMonthCheckbox,
    showWeekCheckbox,
    onCellClick,
    onChange,
    onDateChange,
    ...rest
  } = props;
  const [checkedValues, setCheckedValues] = useState<number[]>([]);
  const [dates, setDates] = useState<DateCell[]>([]);
  const [currentYear, setCurrentYear] = useState<string>('');
  const [currentMonth, setCurrentMonth] = useState<string>('');
  const [calendar] = useCalendar(from, rest);
  const { weekCells, dateCells, checkeds, currentYear: curYear, currentMonth: curMonth } = calendar;

  useImperativeHandle(ref, () => ({
    clearChecked: () => {
      calendar.clearChecked();
    },
  }));
  const ToolbarCheckbox = showMonthCheckbox ? Checkbox : SpanCell;
  const HeaderCheckbox = showWeekCheckbox ? Checkbox : SpanCell;

  const isAllChecked = (day?: DayType) => {
    const items = dates
      .filter((v) => !v.disabled && v.inView && (day === undefined || day === v.day))
      .map((v) => v.timestamp);
    if (items.length && items.every((v) => checkedValues.includes(v))) {
      return true;
    }
    return false;
  };

  const isEqualArray = (arr: number[], newArr: number[]): boolean => {
    if (arr.length === newArr.length && arr.every((v, i) => v === newArr[i])) {
      return true;
    }
    return false;
  };

  useEffect(() => {
    setDates([...dateCells]);
    setCurrentYear(curYear);
    setCurrentMonth(curMonth);
    setCheckedValues([...checkeds]);
  }, []);

  useEffect(() => {
    if (rest.value === undefined) {
      calendar.clearChecked();
    }
    if (rest.value) {
      calendar.clearChecked();
      const vals = calendar.setChecked(rest.value, true);
      if (!isEqualArray(checkedValues, vals)) {
        setCheckedValues([...vals]);
      }
    }
  }, [rest.value]);

  useEffect(() => {
    calendar.on('change', (data) => {
      setCheckedValues([...data]);
      if (typeof onChange === 'function') {
        const vals = [...data].map((v) => dateFomater(v, rest.valueFormat || 'YYYY-MM-DD'));
        onChange(rest.maxChecked === 1 ? vals.join(',') : vals);
      }
    });
    return () => {
      calendar.off('change');
    };
  }, [onChange]);

  useEffect(() => {
    calendar.on('dateChange', ({ dateCells: datas, year, month }) => {
      setCurrentYear(year);
      setCurrentMonth(month);
      setDates([...datas]);
      if (typeof onDateChange === 'function') {
        onDateChange({ year, month, dates: datas });
      }
    });
    return () => {
      calendar.off('dateChange');
    };
  }, [onDateChange]);

  return (
    <div className={classnames([styles.calendar, className])} ref={ref}>
      <div className="calendar-toolbar">
        <LeftOutlined className="btn prev" onClick={() => calendar.prev()} />
        {toolbarRender ? (
          toolbarRender(currentYear, currentMonth)
        ) : (
          <div className="calendar-toolbar-con">
            {toolbarActions}
            <span>{currentYear}</span>
            <span></span>
            <span>{currentMonth}</span>
            <span></span>
            <ToolbarCheckbox
              checked={isAllChecked()}
              onChange={(e) => {
                const { checked } = e.target;
                calendar.setChecked(undefined, checked);
              }}
              style={{ marginLeft: 10 }}
            >
              {showMonthCheckbox ? '全月' : ''}
            </ToolbarCheckbox>
          </div>
        )}
        <RightOutlined className="btn next" onClick={() => calendar.next()} />
      </div>
      <ul className="calendar-header">
        {weekCells.map((item, index) => {
          return (
            <li key={item.value}>
              {headerRender ? (
                headerRender(item, index)
              ) : (
                <HeaderCheckbox
                  checked={isAllChecked(item.value)}
                  onChange={(e) => {
                    const { checked } = e.target;
                    calendar.setChecked(item.value, checked);
                  }}
                >
                  {item.name}
                </HeaderCheckbox>
              )}
            </li>
          );
        })}
      </ul>
      <ul className="calendar-body">
        {dates.map((v, i) => {
          return (
            <li
              className={classnames([
                'calendar-cell',
                {
                  'is-other': !v.inView,
                  'is-disabled': v.disabled,
                  'is-checked': checkedValues.includes(v.timestamp),
                  'is-today': v.timestamp === getDateTimestamp(new Date(), true),
                },
              ])}
              key={v.value}
              onClick={() => {
                if (v.disabled) {
                  return;
                }
                if (v.inView) {
                  calendar.setChecked(v.timestamp);
                }
                if (typeof onCellClick === 'function') {
                  onCellClick(v, i);
                }
              }}
            >
              <div className="calendar-cell-box">
                <div className="calendar-cell-date">{v.date}</div>
                <div className="calendar-cell-con">
                  {cellRender ? cellRender(v, i, dates) : null}
                </div>
              </div>
            </li>
          );
        })}
      </ul>
    </div>
  );
};

export default memo(forwardRef(Calendar));

vue

Calendar.vue

  • {{ week.name }}
  • {{ item.date }}
">
<template name="calendar">
  <div :class="['calendar', className]">
    <ul class="calendar-hd">
      <li v-for="week in weekCells" :key="week.value" class="cell week-cell">{{ week.name }}li>
    ul>
    <ul class="calendar-bd">
      <li
        v-for="(item, index) in dates"
        :key="item.timestamp"
        :class="[
          'cell date-cell',
          {
            indiv: item.indiv,
            disabled: item.disabled,
            checked: checkeds.includes(item.timestamp)
          }
        ]"
        @tap="onCellClick(item, index)"
      >
        <slot :cell="item" :checked="checkeds.includes(item.timestamp)">
          <div>{{ item.date }}div>
        slot>
      li>
    ul>
  div>
template>

<script lang="ts">
import { Vue, Component, Prop, Emit, Watch } from "vue-property-decorator";
import UCalendar from 'u-calendar';
import { dateFomater } from "u-calendar/src/utils";
import {
  CalendarInstance,
  DateType,
  DateCell,
  WeekCell,
  DayType,
} from "u-calendar/src/data.d";

let calendar: CalendarInstance;

@Component
export default class Calendar extends Vue {
  @Prop() private className?: string;
  @Prop() private current?: DateType;
  @Prop() private value?: DateType | DateType[];
  @Prop() private defaultValue?: DateType | DateType[];
  @Prop() private maxChecked?: number;
  @Prop() private disabled?: boolean;
  @Prop({ default: "YYYY-MM-DD" }) private valueFormat!: string;
  @Prop() private startWeek?: DayType;
  @Prop() private disabledDate?: (currentDate: DateCell) => boolean;
  @Prop() private customCells?: PlainObject[];

  weekCells: WeekCell[] = [];
  dateCells: DateCell[] = [];
  checkeds: number[] = [];

  @Watch("current")
  onCurrentChange(nv: DateType) {
    if (calendar) {
      this.dateCells = calendar.setCurrent(nv);
    }
  }

  private get dates() {
    const arr = this.dateCells.map((v) => {
      const item = { ...v };
      const custom =
        this.customCells?.find((v) => v.value === item.value) || {};
      const cur = { ...item, ...custom };
      if (typeof this.disabledDate === "function") {
        cur.disabled = this.disabledDate(cur);
      }
      return cur;
    });
    return arr;
  }

  init() {
    const calendar = new UCalendar(this.$props || {}).getCalendar();

    this.weekCells = calendar.weekCells;
    this.dateCells = calendar.dateCells;
    this.checkeds = calendar.checkeds;

    calendar.on("change", () => {
      const vals = this.checkeds.map((v) => dateFomater(v, this.valueFormat));
      const val = this.maxChecked === 1 ? vals[0] : vals;
      this.$emit("update:value", val);
      this.$emit("change", val);
    });

    calendar.on("dateChange", (data) => {
      this.$emit("dateChange", data);
    });
  }

  @Emit("onCellTap")
  onCellClick(cell: DateCell, index: number) {
    if (cell.disabled || this.disabled) return;
    calendar.setChecked(
      cell.timestamp,
      this.maxChecked === 1 ? true : undefined
    );
    return { cell, index };
  }

  created() {
    this.init();
  }

  destroyed() {
    if (calendar) {
      calendar.off("change");
      calendar.off("dateChange");
    }
  }
}
script>

<style lang="less">
@import "./index.less";
style>
You might also like...
Full calendar base on Vue2 and momentjs.

Vue2 Calendar Component Full calendar base on Vue2 and dayjs. Support month and week view. Custom date item style with scopeSlots. 中文文档 📺 Live demo I

vue 2.x  calendar component
vue 2.x calendar component

vue2-calendar vue 2 calendar, datepicker component which supported lunar or date event Live Demo This project is not only a vue component, but also

A full event display calendar for the Quasar framework that has multiple viewing formats.
A full event display calendar for the Quasar framework that has multiple viewing formats.

Daykeep Calendar An event display calendar for the Quasar framework. Formerly known as Quasar Calendar, Daykeep Calendar for Quasar is a Quasar-flavor

Vue.js wrapper for TOAST UI Calendar

Vue TOAST UI Calendar A Vue.js wrapper for TOAST UI Calendar Installation npm install --save tui-calendar @lkmadushan/vue-tuicalendar Usage Example Tr

Toast UI Calendar for Vue

TOAST UI Calendar for Vue This is Vue component wrapping TOAST UI Calendar. 🚩 Table of Contents Collect statistics on the use of open source Install

Vue.js Functional Calendar | Component/Package
Vue.js Functional Calendar | Component/Package

Vue Functional Calendar Modern calendar and datepicker module for Vue.js Demo Demo: https://y3jnxov469.codesandbox.io/ Lightweight, high-performance c

A Vue JS full calendar, no dependency, no BS. :metal:

vue-cal A Vue JS full calendar, no dependency, no BS. 🤘 Installation npm i vue-cal Vue 3 npm i vue-cal@next Demo & Documentation antoniandre.github

A full 12-Month view calendar made by vue.js.
A full 12-Month view calendar made by vue.js.

English | 繁體中文 There is no full year (12 months on a page) calendar right now, the Vue-material-year-calendar is designed to solve this problem. 🔥 12

Simple and clean calendar written in Vue.js
Simple and clean calendar written in Vue.js

Vuelendar Simple and clean calendar written in Vue.js. Check out full Vuelendar's documentation here. Features Select single date Select range of date

Owner
null
Convenient Vue wrapper for the add to calendar button snippet, which lets you reliably create beautiful buttons, where people can add events to their calendars.

The Add to Calendar Button - optimized for Vue 3 This is a wrapper repository for the popular Add to Calendar Button, making it even more convenient,

Add to Calendar 3 Nov 9, 2022
vue calendar fullCalendar. no jquery required. Schedule events management

##vue-fullcalendar Works for Vue2 now. This is a fullCalendar component based on vue.js . No Jquery or fullCalendar.js required. Currently, It only su

Sunny Wang 1.5k Dec 18, 2022
A simple events calendar for Vue2, no dependencies except Vue2.

vue-event-calendar A simple events calendar for Vue2, no dependencies except Vue2. responsive & mobile first. Live Demo Here 中文文档 Requirements vue: ^2

Geoff Zhu 633 Nov 11, 2022
Calendar component

vue-calendar-picker Calendar component vue-calendar-picker demo on jsfiddle Example - basic <template> <calendar></calendar> </template> <script>

Franck Freiburger 47 Nov 24, 2022
A vue component for lunar calendar.

vue-lunar-calendar A vue component for lunar calendar. Uses Moment.js for date operations. This is the Korean lunar calendar. It is different from Chi

Kim WooHyun 70 Aug 20, 2022
Simple Vue component to show a month-grid calendar with events

VueSimpleCalendar Introduction vue-simple-calendar is a flexible, themeable, lightweight calendar component for Vue that supports multi-day scheduled

Richard Tallent 762 Jan 3, 2023
A lightweight calendar component for Vue2

vue2-calendar Check out the demo here on Code Sandbox: Introduction This is a simple and small event calendar component for Vue js. It is very lightwe

Vincent 55 May 2, 2022
An elegant calendar and datepicker plugin for Vue.

An elegant calendar and datepicker plugin for Vuejs. npm i --save v-calendar Documentation For full documentation, visit vcalendar.io. Attributes High

Nathan Reyes 3.7k Dec 31, 2022
A simple infinite calendar component in Vue 2

vue-infinite-calendar A simple infinite calendar component in Vue 2 Build Setup # install dependencies npm install # serve with hot reload at localho

Rares S 15 Feb 28, 2022
A calendar component for Vue.js

calendar Chinese This is a calendar component based on vue.js . support custom content. No dependencies. Currently, It only supports month view. You c

Kylin 47 Aug 16, 2022