亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

基于Web?Components實現(xiàn)一個日歷原生組件

 更新時間:2023年07月21日 09:34:03   作者:silencealoe  
這篇文章主要為大家詳細介紹了如何利用Web?Components實現(xiàn)一個簡單的日歷原生組件,文中的示例代碼講解詳細,需要的小伙伴可以了解一下

接到一個需求,需要在原生的頁面實現(xiàn)一個日歷功能,正好之前利用閑暇時間用js寫了一個萬年歷在github吃灰, 再用web components封裝一下,完美的一個組件就誕生了。

Web Components 基礎

Web Components API相對于其他UI框架, 不用加載其他模塊, 原裝組件更簡單,代碼量更小.API很多,這里只介紹本次封裝組件使用到的

template標簽

template標簽在頁面加載時該標簽中的內(nèi)容不會顯示,需要使用js來使其展示在頁面上。標簽里面可以包含css 和 組件html結(jié)構(gòu)。

日歷組件template 內(nèi)容: 包括日歷樣式css, 日歷組件html結(jié)構(gòu), 預留可擴充功能的插槽

let template = document.createElement("template");
template.innerHTML = `
<style>
    * {
      user-select: none;
      list-style: none;
      margin: 0;
      padding: 0;
    }
    .calendar_wrap {
      width: 1280px;
      margin: 100px auto;
      position: relative;
      padding-bottom: 10px;
      border-radius: 20px;
      box-shadow: 10px 10px 50px 10px #ccc;
    }
    .pick_year_month {
      width: 100%;
      height: 80px;
      line-height: 80px;
      text-align: center;
      background: #cdb092;
      border-radius: 20px 20px 0 0;
    }
    .pick_year_item {
      margin: 0 20px;
      font-size: 24px;
      font-weight: 600;
    }
    .date_action {
      cursor: pointer;
      display: inline-block;
      width: 30px;
      height: 30px;
      border-radius: 50%;
      text-align:center;
      line-height: 30px;
      background: #d6d4d4;
      color: #b1afaa;
      font-size: 24px;
      margin: 0 4px;
    }
    .change_num_txt {
        color: #000;
    }
    .weekday,
    .month_days {
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-start;
    }
    .weekday_item,
    .days_item {
        width: 80px;
        margin: 0 50px;
        text-align: center;
        font-size: 20px;
    }
    .weekday {
      margin-bottom: 20px;
      font-weight:600;
    }
    .days_item {
      height: 80px;
      margin-bottom: 10px;
      padding-top: 5px;
      text-align: center;
      line-height: 80px;
      font-size: 24px;
      font-weight: bold;
    }
    .day_color {
        color: #5678FE;
        background: #bb7665;
        color: #fff;
        border-radius: 50%;
    }
    .gray_color {
        color: #acacac;
    }
    .red_color {
        color: #c26228;
    }
    .blue_color {
        color: #c26228;
    }
    .real_day {
      cursor: pointer;
    }
    .real_day:hover {
        outline: 1px solid orange;
        border-radius: 5px;
        box-shadow: 0 0 2px 2px orange;
    }
    .select_day_active {
        outline: 1px solid orange;
    }
    </style>
<div class="calendar_wrap" id="calendar_container">
  <div class="pick_year_month">
    <span class="pick_year_item" id="decrease_year">? </span>
    <span class="pick_year_item" id="decrease_month">? </span>
    <span class="pick_year_item"><span class="change_num_txt" id="year_num">2019</span>年<span class="change_num_txt" id="month_num">1</span>月
    </span>
    <span class="pick_year_item" id="increase_month"> ?</span>
    <span class="pick_year_item" id="increase_year"> ?</span>
  </div>
  <ul class="weekday">
    <li class="weekday_item blue_color">日</li>
    <li class="weekday_item">一</li>
    <li class="weekday_item">二</li>
    <li class="weekday_item">三</li>
    <li class="weekday_item">四</li>
    <li class="weekday_item">五</li>
    <li class="weekday_item blue_color">六</li>
  </ul>
  <ul class="month_days" id="getdays">
  </ul>
  <slot name="customBox"></slot>
</div>

自定義元素類

自定義元素CustomCalendar, 繼承HTMLElement父類, 因此具有html元素特性

class CustomCalendar extends HTMLElement {
}

接下來需要在自定元素類中加載剛才定義好的template內(nèi)容

class CustomCalendar extends HTMLElement {
     #shadowDom
    constructor() {
        super();
        this.#shadowDom = this.attachShadow({ mode: "open"});
   this.#shadowDom.appendChild(template.content.cloneNode(true));
    }
}
customElements.define('a-calendar', CustomCalendar);

this.attachShadow() 控制影子DOM 是否可操作。返回一個影子DOM(this.#shadowDom 可以用來操作DOM)。影子DOM表示內(nèi)部元素與外部隔離,不受外部任何影響。

  • mode: "closed" 內(nèi)部元素可見,外部無法操作DOM
  • mode: "open" 內(nèi)部元素可見,外部可操作DOM

這里使用template.content.cloneNode(true) 克隆一份template內(nèi)容加載到自定義元素內(nèi)是因為可能有多個自定義元素的實例,這個模板內(nèi)容還要留給其他實例使用,所以不能直接移動它的子元素

瀏覽器原生方法 customElements.define('a-calendar', CustomCalendar) 表示了自定義元素a-calendar 與自定義類CustomCalendar的關聯(lián),然后就可以在HTML結(jié)構(gòu)中使用a-calendar標簽了,在template中,我們還預留了插槽的功能,還可以使用插槽來自行擴展組件

<a-calendar>
    <div slot="customarea">111</div>
</a-calendar>

父子組件傳值

在之前定義了自定義標簽,在html中使用,還可以像Vue React組件那樣在標簽上添加任意屬性

<a-calendar config="123"></a-calendar>

父組件向子組件傳遞值

和其他UI框架組件一樣, 父組件傳值給子組件也是直接在標簽上添加要傳遞的屬性,只是在子組件接收傳值這塊,web components 處理有些出入。

在自定義類CustomCalendar中,可以通過attributeChangedCallback鉤子函數(shù)來監(jiān)聽標簽上屬性值的變化,同時需要observedAttributes來注冊需要監(jiān)聽的屬性, observedAttributes返回一個數(shù)組,只有在數(shù)組中填入的屬性名字,屬性值變化后才會在attributeChangedCallback拿到對應的值

class CustomCalendar extends HTMLElement {
     #shadowDom
    constructor() {
        super();
        this.#shadowDom = this.attachShadow({ mode: "open"});
   this.#shadowDom.appendChild(template.content.cloneNode(true));
    }
      // 監(jiān)聽屬性attr 值變化
     attributeChangedCallback(name, olddata, newData) {}
     static get observedAttributes() {return ['config']; }
}

子組件傳值給父組件

可以通過自定義事件來實現(xiàn),在子組件需要傳值的時刻,觸發(fā)自定義事件,父組件監(jiān)聽自定義事件,就能拿到傳值

在日歷組件中,我們初始化好了當前的日期,需要向父組件傳遞這個日期,子組件觸發(fā)一個自定義yearmonthchange事件

class CustomCalendar extends HTMLElement {
     #shadowDom
    constructor() {
        super();
        this.#shadowDom = this.attachShadow({ mode: "open"})
        this.#shadowDom.appendChild(template.content.cloneNode(true));
        this.date = new Date(); //獲取當前日期
        this.year = this.date.getFullYear();
        this.curYear = this.year;
        this.month = this.date.getMonth() + 1;
        this.curMonth = this.date.getMonth() + 1; // 當前月份
        this.day = this.date.getDate();  
        // 觸發(fā)自定義事件, 將年月傳遞給父組件
        this.dispatchEvent(new CustomEvent('yearmonthchange', {detail: {year: this.year, month: this.month}}))
    }
      // 監(jiān)聽屬性attr 值變化
     attributeChangedCallback(name, olddata, newData) {}
     static get observedAttributes() {return ['config']; }
}

在父組件監(jiān)聽yearmonthchange事件,獲取到傳值

<a-calendar id="cal" config="123"></a-calendar>
<script>
 var cal = document.getElementById('cal');
 cal.addEventListener('yearmonthchange', (e) => {
     console.log(e.detail)
  })
</script>

日歷功能實現(xiàn)

實現(xiàn)好的日歷大致是這個樣子

以上介紹了基本的Web Components 使用, 搭好了組件的基本框架,接下來只需要把日歷的功能代碼填入到自定義類中就OK了。

初始化事件

一共五個點擊事件:增減年月, 點擊日期

 changeCurrentYearMonth(op, type) {
      this.month_days_wrap.innerHTML = '';
      if (op === 'inc') {
        this[type] = this[type] + 1;
        if (type==='month' && this[type] > 12) {
          this[type] = 1
          this.year = this.year + 1;
          this.year_change_txt.innerHTML = this.year;
        }
      } else {
        this[type] = this[type] - 1;
        if (type==='month' && this[type] === 0) {
          this[type] = 12
          this.year = this.year - 1;
          this.year_change_txt.innerHTML = this.year;
        }
      }
      var opEle = type + '_change_txt';
      this[opEle].innerHTML = this[type];
      this.dispatchEvent(new CustomEvent('change', {detail: {year: this.year, month: this.month}}))
      this.getMonthDays(this.year, this.month);
    }
clickDayItem(day) {
      // 子組件向父組件傳遞值
      this.dispatchEvent(new CustomEvent('dayClick', day)) 
   }
 addEvent () {
      var container = this.#shadowDom.getElementById('container');
      var self = this;
      container.addEventListener('click', function(e){
        switch (e.target.id) {
          case 'increase_year': 
            self.changeCurrentYearMonth('inc', 'year');
            break;
          case 'decrease_year': 
            self.changeCurrentYearMonth('dec', 'year');
            break;
          case 'increase_month':
            self.changeCurrentYearMonth('inc', 'month');
            break;
          case 'decrease_month':
            self.changeCurrentYearMonth('dec', 'month');
            break;
        }
        if(e.target.className.includes('real_day')) {
          self.clickDayItem(e.target.innerHTML);
        }
      })
    }

初始化日歷

將當前的日期填入到頂部的操作欄中

initDays () {
      this.month_days_wrap = this.#shadowDom.getElementById('getdays');
      this.year_change_txt = this.#shadowDom.getElementById('year_num');
      this.month_change_txt = this.#shadowDom.getElementById('month_num');
      this.year_change_txt.innerHTML = this.year;
      this.month_change_txt.innerHTML = this.month;
      this.getMonthDays(this.year, this.month);
    }

然后開始計算每個月的天數(shù)填入到每月的布局中

 getMonthDays(yearNums, monthNums) {
      // 當月最后一天
      var date1 = new Date(yearNums, monthNums, 0);
      // 當月第一天
      var date2 = new Date(yearNums, monthNums - 1, 1);
      // 上個月最后一天
      var date3 = new Date(yearNums, monthNums - 1, 0);
      var last_month_day = date3.getDate(); // 日期
      var insert_before_nums = date2.getDay(); // 當月第一天星期
      var insert_after_nums = date1.getDay(); // 當月最后一天星期
      var days = date1.getDate();
      for (var i = 1; i <= days; i++) {
          let dates = new Date(yearNums, monthNums - 1, i);
          var li = document.createElement('li');
          li.className = 'days_item real_day';
          li.innerHTML = i;
          var isWeekend = dates.getDay();
          if (isWeekend === 0 || isWeekend === 6) { // 周六日
              li.className = 'days_item real_day blue_color';
          }
          this.month_days_wrap.appendChild(li);
      }
      if (monthNums === this.curMonth && yearNums === this.curYear) {  //今日日期顯示色
          var today = this.#shadowDom.querySelectorAll('.days_item')[this.day - 1];
          today.className = "days_item real_day day_color"
      }
      for (let i = 0; i < insert_before_nums; i++) { // 上月后幾天
          var days_one = this.#shadowDom.querySelectorAll('.days_item')[0];
          var lis = document.createElement('li');
          lis.className = 'days_item gray_color';
          lis.innerHTML = last_month_day--;
          this.#shadowDom.querySelector('.month_days').insertBefore(lis, days_one);
      }
      for (let i = 1; i <= 6 - insert_after_nums; i++) { // 下月前幾天
          var lis = document.createElement('li');
          lis.className = 'days_item gray_color';
          lis.innerHTML = i;
          this.#shadowDom.querySelector('.month_days').appendChild(lis);
      }
  }

至此,日歷功能就完成了,我們可以把自定義類單獨放在一個js文件,這樣使用的時候,直接引入js文件就可以在頁面上使用組件啦~~

以上就是基于Web Components實現(xiàn)一個日歷原生組件的詳細內(nèi)容,更多關于Web Components日歷組件的資料請關注腳本之家其它相關文章!

  • JavaScript股票的動態(tài)買賣規(guī)劃實例分析上篇

    JavaScript股票的動態(tài)買賣規(guī)劃實例分析上篇

    這篇文章主要介紹了JavaScript對于動態(tài)規(guī)劃解決股票問題的真題例舉講解。文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • js實現(xiàn)5秒倒計時重新發(fā)送短信功能

    js實現(xiàn)5秒倒計時重新發(fā)送短信功能

    這篇文章主要為大家詳細介紹了js實現(xiàn)5秒倒計時重新發(fā)送短信功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • JavaScript數(shù)據(jù)結(jié)構(gòu)常見面試問題整理

    JavaScript數(shù)據(jù)結(jié)構(gòu)常見面試問題整理

    在JavaScript中,數(shù)據(jù)結(jié)構(gòu)是指相互之間存在一種或多種特定關系的數(shù)據(jù)元素的集合,是帶有結(jié)構(gòu)特性的數(shù)據(jù)元素的集合。常用的數(shù)據(jù)結(jié)構(gòu)有:數(shù)組、列表、棧、隊列、鏈表、字典、集合等等
    2022-08-08
  • JSX在render函數(shù)中的應用詳解

    JSX在render函數(shù)中的應用詳解

    這篇文章主要介紹了JSX在render函數(shù)中的應用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • 微信小程序?qū)崿F(xiàn)人臉識別登陸的示例代碼

    微信小程序?qū)崿F(xiàn)人臉識別登陸的示例代碼

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)人臉識別登陸的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Js 回車換行處理的辦法及replace方法應用

    Js 回車換行處理的辦法及replace方法應用

    當我們在文本框里輸入文字敲下回車后,希望在提交后網(wǎng)頁也顯示是換行的效果,可往往并不能如愿以償啊,實在是憤怒啊自己寫了一個回車換行處理的函數(shù),感興趣的朋友可以了解下啊,希望本文對你有所幫助
    2013-01-01
  • JavaScript控制圖片加載完成后調(diào)用回調(diào)函數(shù)的方法

    JavaScript控制圖片加載完成后調(diào)用回調(diào)函數(shù)的方法

    這篇文章主要介紹了JavaScript控制圖片加載完成后調(diào)用回調(diào)函數(shù)的方法,實例分析了javascript回調(diào)函數(shù)的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • 利用jsonp解決js讀取本地json跨域的問題

    利用jsonp解決js讀取本地json跨域的問題

    這篇文章主要給大家介紹了關于利用jsonp解決js讀取本地json跨域的問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-12-12
  • 最新評論