组件封装(分页器、弹框、日历):提升代码复用和维护性的利器

在现代的前端开发中,组件封装成为了一项重要而强大的技术。无论是在大型应用程序还是小型项目中,良好的组件封装都能够为我们带来诸多好处。让我们一起探讨一下组件封装的优势及案例实现。

一、组件封装优势

组件封装可以大大提高代码的复用性。通过将具有相似功能或模式的代码抽象出来并封装成组件,我们可以在不同的地方重复使用它们,而无需重复编写相同的代码。这不仅减少了开发时间,还减少了出错的机会。例如,一个通用的按钮组件可以在应用的各个地方使用,而不需要每次都重新创建一个新的按钮。

组件封装可以提升代码的可维护性。通过将功能模块化并隐藏实现细节,我们可以降低代码的耦合度,使其更易于理解和维护。当我们需要对某个功能进行修改或修复时,只需关注特定的组件,而不需要担心对其他部分产生意外的影响。这种模块化的设计使得团队合作更加高效,每个人都可以专注于自己负责的组件。

二、案例实现

以下是相关的组件案例实现:

1.分页器
<template>
    <div class="pagination">
      <!-- 当当前页为1时,禁用按钮 -->
      <button :disabled="pageNo == 1" @click="$emit('getPage',pageNo-1)" >上一页</button>
      <!-- 当连续页的开始大于1时,显示按钮 -->
      <button v-if="startAndEnd.start > 1" @click="$emit('getPage',1)" :class="{'active':pageNo==1}">1</button>
      <button v-if="startAndEnd.start > 2">···</button>
  
      <!-- 遍历页数(数字),中间显示的数字页数号 -->
      <template v-for="(page,index) in startAndEnd.end" >
          <button  v-if="page >= startAndEnd.start" :key="index" @click="$emit('getPage',page)" :class="{'active':pageNo==page}">{{page}}</button>
      </template>
      
      
      <button v-if="startAndEnd.end < totalPage - 2">···</button>
      <!-- 当连续页的结尾小于总页数时,显示按钮 -->
      <button v-if="startAndEnd.end < totalPage" @click="$emit('getPage',totalPage)" :class="{'active':pageNo==totalPage}">{{totalPage}}</button>
      <!-- 当当前页为总页数时,禁用按钮 -->
      <button :disabled="pageNo == totalPage" @click="$emit('getPage',pageNo+1)">下一页</button>
      
      <button style="margin-left: 30px">共 {{total}} 条</button>
    </div>
  </template>
  
  <script>
    export default {
      name: "Pagination",
      props:['pageNo','total','continues','pageSize'],
      computed:{
          //总页数
          totalPage(){
              return Math.ceil(this.total/this.pageSize)
          },
          //连续页数中的起始页和终止页
          startAndEnd(){
              let start = 0 ,end = 0
              let {pageNo,continues,totalPage} = this
              if(continues > this.totalPage){
                  start = 1
                  end = totalPage
              }else{
                  start = pageNo - parseInt(continues/2)
                  end = pageNo + parseInt(continues/2)
              }
              //得出的起始页和结束页在进行判断
              if(start < 1){
                  start = 1
                  end = continues
              }else if(end > totalPage){
                  end = totalPage
                  start = pageNo - continues + 1
              }
              return {start,end}
          }
      }
    }
  </script>
  
  <style lang="less" scoped>
    .pagination {
      text-align: center;
      button {
        margin: 0 5px;
        background-color: #f4f4f5;
        color: #606266;
        outline: none;
        border-radius: 2px;
        padding: 0 4px;
        vertical-align: top;
        display: inline-block;
        font-size: 13px;
        min-width: 35.5px;
        height: 28px;
        line-height: 28px;
        cursor: pointer;
        box-sizing: border-box;
        text-align: center;
        border: 0;
  
        &[disabled] {
          color: #c0c4cc;
          cursor: not-allowed;
        }
  
        &.active {
          cursor: not-allowed;
          background-color: #409eff;
          color: #fff;
        }
      }
    }
  </style>

效果演示:

2.弹框
<template>
    <div>
      <button @click="openModal">Open Modal</button>
      <!-- 通过showModel来控制弹框是否显示 -->
      <div v-if="showModal" class="modal">
        <div class="modal-content">
          <span class="close" @click="closeModal">&times;</span>
          <h2>{{ title }}</h2>
          <p>{{ message }}</p>
          <button @click="cancer">取消</button>
          <button @click="save">完成</button>
        </div>
        
      </div>
    </div>
  </template>
  
  <script>
  export default {
    data() {
      return {
        showModal: false,
        title: "弹框标题",
        message: "弹框内容"
      };
    },
    methods: {
      openModal() {
        this.showModal = true;
      },
      closeModal() {
        this.showModal = false;
      },
      cancer(){
        this.showModal = false;
      },
      save(){
        //实现完成后的逻辑功能,例如:跳转页面等
      }
    }
  };
  </script>
  
  <style>
  /* 遮罩层样式 */
  .modal {
    display: flex;
    justify-content: center;
    align-items: center;
    position: fixed;
    z-index: 9999;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
  }
  
  .modal-content {
    background-color: #fff;
    padding: 20px;
    border-radius: 5px;
    max-width: 400px;
    width: 90%;
    text-align: center;
  }
  
  .close {
    float: right;
    font-size: 20px;
    font-weight: bold;
    cursor: pointer;
  }
  
  button {
    margin: 10px;
    padding: 10px 20px;
    background-color: #409eff;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
  }
  </style>

效果演示:

3.日历
<template>
    <div>
      <div class="header">
        <!-- 点击按钮:年份减一 -->
        <button @click="prevYear">&lt;&lt;</button>
        <!-- 点击按钮:月份减一 -->
        <button @click="prevMonth" :disabled="isDisabled">&lt;</button>
        <h2>{{ currentMonth }}</h2>
        <button @click="nextMonth">&gt;</button>
        <button @click="nextYear">&gt;&gt;</button>
      </div>
      <table>
        <thead>
          <!-- 星期* -->
          <tr>
            <th v-for="day in daysOfWeek" :key="day">{{ day }}</th>
          </tr>
        </thead>
        <tbody>
          <!-- 日期* -->
          <tr v-for="(week,index) in calendar" :key="index">
            <!-- 'current-day': isCurrentDay(day), 再开始页面的当前时间高亮 -->
            <td v-for="day in week" :key="day.date" :class="{ 'selected-day': isSelectedDay(day) }" @click="selectDay(day)">
              {{ day.date }}
            </td>
          </tr>
        </tbody>
      </table>
      <div>当前时间为:{{showDate}}</div>
    </div>
  </template>
  
  <script>
  export default {
    data() {
      return {
        currentDate: new Date(),
        daysOfWeek: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
        calendar: [],
        showDate:'',
        isDisabled:false
      };
    },
    computed: {
      //将当前日历转换格式
      currentMonth() {
        return this.currentDate.toLocaleString('default', { month: 'long', year: 'numeric' });
      }
    },
    mounted() {
      this.renderCalendar();
    },
    methods: {
      //获取当月的日历表
      renderCalendar() {
        const firstDayOfMonth = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1);
        const lastDayOfMonth = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, 0);
  
        const weeks = [];
        let currentWeek = [];
        let currentDate = new Date(firstDayOfMonth);
  
        while (currentDate <= lastDayOfMonth) {
          currentWeek.push({
            date: currentDate.getDate(),
            month: currentDate.getMonth(),
            year: currentDate.getFullYear()
          });
          //若当前日期为星期六,则将数组添加进新数组中
          if (currentDate.getDay() === 6) {
            weeks.push(currentWeek);
            currentWeek = [];
          }
  
          currentDate.setDate(currentDate.getDate() + 1);
        }
        if (currentWeek.length > 0) {
          weeks.push(currentWeek);
        }
  
        this.calendar = weeks;
      },
      prevMonth() {
        if(this.currentDate.getMonth() < 1){
          this.isDisabled == true
        }else{
          this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, 1);
          this.renderCalendar();
        }     
      },
      prevYear(){
        console.log(11);
        this.currentDate = new Date(this.currentDate.getFullYear() - 1, this.currentDate.getMonth(), 1);
        this.renderCalendar();
      },
      nextMonth() {
        if(this.currentDate.getMonth() > 12){
          this.disabled == true
        }else{
           this.currentDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, 1);
          this.renderCalendar();
        }       
      },
      nextYear(){
        this.currentDate = new Date(this.currentDate.getFullYear() + 1, this.currentDate.getMonth(), 1);
        this.renderCalendar();
      },
      //是当天日期高亮(获得样式)
      isCurrentDay(day) {
        const today = new Date();
        return day.date === today.getDate() && day.month === today.getMonth() && day.year === today.getFullYear();
      },
      isSelectedDay(day) {
        return false;
      },
      //显示当前点击日期
      selectDay(day) {
        this.showDate = day.year + '年' + day.month +'月' + day.date + '日';
      }
    }
  };
  </script>
  
  <style>
  table {
    width: 100%;
    border-collapse: collapse;
  }
  
  th,
  td {
    padding: 10px;
    text-align: center;
  }
  
  th {
    background-color: #f2f2f2;
  }
  
  td {
    border: 1px solid #ccc;
  }
  
  td:hover {
    background-color: #f2f2f2;
    cursor: pointer;
  }
  
  .current-day {
    background-color: #e6e6e6;
  }
  
  .selected-day {
    background-color: #409eff;
    color: #fff;
  }
  
  .header {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 10px;
  }
  
  .header button {
    background-color: transparent;
    border: none;
    cursor: pointer;
    color: palevioletred;
    font-size: 22px;
    padding: 5px 10px;
  }

  </style>

效果演示:

 

三、总结 

综上所述,组件封装是现代前端开发中不可或缺的一环。它通过提高代码复用性、维护性和可测试性,为我们带来了诸多好处。无论是在个人项目中还是大型团队开发中,合理地封装组件都能够提高开发效率和代码质量。让我们拥抱组件封装,打造更优秀的前端应用!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值