当前位置: 首页 > news >正文

vue/H5的日历组件可简单定制

在components创建riliZujian.vue

<template>
  <div class="max_box">
    <!-- 日历 文字 -->
    <div class="month">
      <div @click="lastMonth" class="monthText13">上月</div>
      <div class="monthText2">{{ year }}年{{ month }}月</div>
      <div class="monthText13" @click="nextMonth">下月</div>
    </div>

    <!-- 日历 周 -->
    <div class="week">
      <div v-for="weeks in weekArr" :key="weeks">
        {{ weeks }}
      </div>
    </div>

    <!-- 日历 日 -->
    <div class="day">
      <div
        :class="[{ checkday: !days.date }, { choose: days.flag }]"
        v-for="(days, index) in dayArr"
        :key="index"
      >
        {{ days.day }}
        <img src="./yidaka.png" class="dayImg" v-if="days.flag" />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    already: {
      type: Array
    }
  },
  watch: {
    already: {
      handler (v) {
        // 监听getAlready方法 获得已打卡的样式
        this.getAlready()
      },
      immediate: true, // 第一次赋值时触发
      deep: true // 深度监听
    }
  },
  name: 'rili-zujian',
  data () {
    return {
      dayArr: [], // 当前月每日
      day: new Date().getDate(), // 当前日
      year: new Date().getFullYear(), // 当前年
      month: new Date().getMonth() + 1, // 当前月
      weekArr: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], // 每周
      aheadDay: 0 // 前方空白天数数量
    }
  },
  mounted () {
    const that = this
    // 初始日期
    that.initDate()
  },
  methods: {
    // 渲染已经签到的日期
    getAlready () {
      for (const i in this.dayArr) {
        if (
          this.already.indexOf(new Date(this.dayArr[i].date).getTime()) === -1
        ) {
          this.$set(this.dayArr[i], 'flag', false)
        } else {
          this.$set(this.dayArr[i], 'flag', true)
        }
      }
    },

    // 初始化日期
    initDate () {
      const that = this
      that.dayArr = []
      // 当前月总天数
      const totalDay = new Date(that.year, that.month, 0).getDate()
      // 遍历总天数将日期逐个添加至数组
      for (let i = 1; i <= totalDay; i++) {
        // 得到需补充天数
        const value = new Date(that.year, that.month - 1, i).getDay()
        // 补充前面空白日期
        if (i === 1 && value !== 0) {
          that.addBefore(value)
          that.aheadDay = value
        }
        // 添加本月日期
        const obj = {}
        obj.date =
          that.year +
          '-' +
          that.formatNum(that.month) +
          '-' +
          that.formatNum(i)
        obj.day = i
        that.dayArr.push(obj)
        // 补充后面空白日期
        if (i === totalDay && value !== 6) that.addAfter(value)
      }
    },
    // 补充前面空白日期
    addBefore (value) {
      const that = this
      const totalDay = new Date(that.year, that.month - 1, 0).getDate()
      for (let i = 0; i < value; i++) {
        const obj = {}
        obj.date = ''
        obj.day = totalDay - (value - i) + 1
        that.dayArr.push(obj)
      }
    },
    // 补充后空白日期
    addAfter (value) {
      const that = this
      for (let i = 0; i < 6 - value; i++) {
        const obj = {}
        obj.date = ''
        obj.day = i + 1
        that.dayArr.push(obj)
      }
    },
    // 格式化日期位数
    formatNum (num) {
      return num < 10 ? '0' + num : num
    },
    // 上一个月
    lastMonth () {
      const that = this
      if (that.month === 1) {
        that.year -= 1
        that.month = 12
      } else {
        that.month -= 1
      }

      that.initDate()
      that.getAlready()
    },
    // 下一个月
    nextMonth () {
      const that = this
      if (that.month === 12) {
        that.year += 1
        that.month = 1
      } else {
        that.month += 1
      }
      that.initDate()
      that.getAlready()
    }
  }
}
</script>

<style lang="less" scoped>
// 最大的盒子
.max_box {
  width: 375px;
  box-sizing: border-box;
  background-color: none;
}
// 月周日的样式 flex布局
.month,
.week,
.day {
  width: 375px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
// 月的文字的样式
.month {
  height: 50px;
}
.monthText13 {
  width: 50px;
  height: 50px;
  line-height: 50px;
  text-align: center;
}
.monthText2 {
  width: 100px;
  height: 50px;
  line-height: 50px;
  text-align: center;
}
// 日 flex超出 的换行
.day {
  flex-wrap: wrap;
}
// 周和日 的div样式
.week > div,
.day > div {
  width: 32px;
  height: 32px;
  line-height: 32px;
  margin: 9px;
  text-align: center;
  position: relative;
}
// 本月之外的数字 改成白色 隐藏起来
.checkday {
  color: #f9f9f9;
}
// 已打卡 的日期 的样式
.choose {
  color: #ffffff;
  background: #b5443a;
  border-radius: 10px;
  position: relative;
}
.dayImg {
  width: 36px;
  height: 13px;
  position: absolute;
  top: -3px;
  left: 0;
}
</style>

在业务代码中引入 riliZujian 组件

<template>
  <!-- 打卡领取道具礼包 -->
  <div class="maxBox">
    <!-- 导航栏 只有返回键 -->
    <div
      class="title"
      :style="{ top: this.$route.query.statusBarHeight + 'px' }"
    >
      <img src="./climbersImg/title01.png" class="title01" @click="goBack" />
      <div class="title03"></div>
    </div>
    <!-- 打卡 背景图 -->
    <img src="./climbersImg/dakaMaxBg.png" class="dakabeijingtu" />

    <!-- 内容 -->
    <div class="content">
      <!-- 用户信息 -->
      <div class="content_top">
        <!-- 打卡 打卡规则 子绝父相 -->
        <img
          src="./climbersImg/dakaguize.png"
          class="dakaguize"
          @click="onDakaguize"
        />

        <img :src="userInfo.userHeadUrl" class="content_top_img" />
        <div class="content_top_text">
          <div class="content_top_text_1">
            <img
              src="./climbersImg/dakaText1.png"
              class="content_top_text_1_img"
            />
            <div class="content_top_text_1_number">
              {{ userInfo.signCount }}
            </div>
            <img
              src="./climbersImg/dakaText2.png"
              class="content_top_text_1_img"
            />
          </div>

          <div class="content_top_text_2">
            <div class="content_top_text_2_text">
              <span style="color: #b5443a">{{ userInfo.signCount }}</span
              >/{{ userInfo.amount }}元
            </div>
            <div class="content_top_text_2_text">
              满{{ userInfo.amount }}元自动发放到钱包
            </div>
          </div>
        </div>
      </div>
      <!-- 日历 -->
      
      <riliZujian :already="dakaData" @changeMonth="historysign" />
    </div>

    <!-- 弹出框 打卡规则 -->
    <van-popup v-model="showDakaguize" position="bottom" style="background: none;">
      <img src="./climbersImg/dakaguizeBig.png" class="guizetanchuang" />
    </van-popup>
  </div>
</template>

<script>
// getDakaSub,
import { getDakaUserInfo, getDakaRili } from '@/api/zhidou'
import riliZujian from '@/components/rilizujian.vue'

export default {
  name: 'climbers-dakalinglibao',
  data () {
    return {
      showDakaguize: false, // 弹出框 展示打卡规则的字段
      dakaData: [], // 打卡的日历的接收字段
      userInfo: {} // 用户的打卡和基本信息
    }
  },
  components: {
    riliZujian
  },
  mounted () {
    this.getUserInfo()
    this.historysign()
  },
  methods: {
    // 打开 打卡规则 的方法
    onDakaguize () {
      console.log(123)
      this.showDakaguize = true
    },
    // 获取当前用户的打卡基础信息
    getUserInfo () {
      getDakaUserInfo({ userId: this.$route.query.userId }).then((res) => {
        // console.log(res, 'res---')
        if (res.status === 200) {
          this.userInfo = res.data
        } else {
          this.$toast.fail(res.msg)
        }
      })
    },
    // 获取当前用户的打卡日历信息
    historysign () {
      getDakaRili({
        userId: 107,
        time: '2025-03-17 12:26:43'
      }).then((res) => {
        if (res.status === 200) {
          for (const i in res.data) {
            // 接口返回的每一项 如果为 true 则进来
            if (res.data[i]) {
              this.dakaData.push(new Date(i).getTime())
            }
          }
          // console.log(this.dakaData)
        } else {
          this.$toast.fail(res.msg)
        }
      })
    },
    // 返回到上级页面
    goBack () {
      this.$router.push({
        path: '/上级页面地址',
        query: {
          userId: this.$route.query.userId,
          statusBarHeight: this.$route.query.statusBarHeight
        }
      })
    }
  }
}
</script>

<style lang="less" scoped>
.maxBox {
  width: 375px;
  position: relative;
}
.title {
  width: 375px;
  height: 44px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: absolute;
  left: 0;

  .title01 {
    width: 28px;
    height: 28px;
    margin-left: 16px;
  }
  .title03 {
    width: 44px;
    height: 20px;
  }
}
.dakabeijingtu {
  width: 375px;
}
.content {
  width: 375px;
  // height: 500px;
  background-image: url(./climbersImg/dakaMinBg.png);
  background-size: 100% 100%;
  position: absolute;
  top: 250px;
  bottom: 0;

  .content_top {
    width: 343px;
    height: 94px;
    margin: 0 16px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    display: flex;
    position: relative;

    .dakaguize {
      width: 34px;
      height: 96px;
      position: absolute;
      top: -23px;
      right: -18px;
    }
    .content_top_img {
      width: 56px;
      height: 56px;
      border-radius: 56px;
      margin: 21px 15px 0 18px;
    }
    .content_top_text {
      width: 254px;
      margin-top: 20px;

      .content_top_text_1 {
        width: 254px;
        height: 32px;
        display: flex;
        align-items: center;

        .content_top_text_1_img {
          height: 16px;
        }
        .content_top_text_1_number {
          height: 32px;
          line-height: 32px;
          font-size: 27px;
          font-weight: 700;
          color: #b5443a;
          margin: 0 5px;
        }
      }
      .content_top_text_2 {
        width: 254px;
        height: 20px;
        display: flex;

        .content_top_text_2_text {
          font-size: 14px;
          font-weight: 400;
          color: rgba(0, 0, 0, 0.5);
          margin-right: 8px;
        }
      }
    }
  }
}
.guizetanchuang {
  width: 375px;
}

::v-deep .van-calendar__header {
  background: rgba(255, 255, 255, 0.1);
}
::v-deep .van-calendar__body {
  background: rgba(255, 255, 255, 0.1);
}
::v-deep .van-calendar__header-title {
  display: none;
}
</style>

参考资料:签到组件、可签到和补签,统计签到天数和积分 - DCloud 插件市场

相关文章:

  • 【spring boot 实现图片验证码 前后端】
  • STM32微控制器_03_GPIO原理与应用
  • 力扣No.376.摆动序列
  • LightGBM + TA-Lib A股实战进阶:Optuna调优与Plotly可视化详解
  • 【pptx-preview】react+pptx预览
  • 蓝牙系统的核心组成解析
  • 拥抱健康养生,开启活力生活
  • {瞎掰} 手机安装app问题:app签名,手机 or OS官方商店 其他非官方app源,安全防护 突破限制
  • gitee 远程修改完密码本地提交出错的解决方案
  • 网络性能指标
  • TK矩阵系统的软件服务
  • tuh_eeg数据集
  • 文档搜索引擎项目测试
  • 国密系列加密技术及其在爬虫逆向中的应用研究
  • linux按照nginx
  • Day 18:数字 1 的个数
  • DFT mode下hard phy STA Nopath
  • Go红队开发—日志打印优化
  • 子序列问题写法
  • 【嵌入式】复刻SQFMI开源的Watchy墨水屏电子表——(1)硬件部分
  • 吉林:消纳绿电,“氢”装上阵
  • 旭辉控股集团主席林中:债务重组是活下来的前提,自营开发业务收缩至少数核心城市
  • 观众走入剧院空间,人艺之友一起“再造时光”
  • 巴基斯坦全国航班仍持续延误或取消
  • A股三大股指集体高开
  • 印控克什米尔地区再次传出爆炸声