vue3+ant之实现月份多选组件

效果图:
在这里插入图片描述

multiMonth.vue

<template>
  <div class="mul-box">
    <a-popover v-model:visible="isShow" title="" trigger="click" getPopupContainer placement="bottom" overlayClassName="monthCard">
      <template #content>
        <a-calendar :fullscreen="false" @select="onPanelChange" mode="year">
          <template #monthFullCellRender="{ current }">
            <div :class="calculateMonth(current)">{{new Date(current).getMonth() + 1 + '月'}}</div>
            <div :class="getAllMonth(current)"></div>
          </template>
        </a-calendar>
      </template>
      <!--      :id="monthId"-->
      <div :class="useConfig?.disabled ? 'dised-arrbox' : 'arrbox'" @click="toolTipShow"  :style="styleConfig">
        <div class="suffix">
          <CalendarOutlined style="color: rgba(0, 0, 0, 0.45)"/>
        </div>
        <div class="tags-part">
          <a-tag v-for="(item,index) in tagList" :closable="typeParent === 'searchUse' && tagList.length < 2 ? false  : true" class="suspend" @close="tagClose(index,item)" :key="index">
            {{item + '月'}}
          </a-tag>
        </div>
        <a-input v-model:value="time"  ref="inputTag" class="inputTag" :style="inputStyle" :disabled="useConfig.disabled" />
      </div>
    </a-popover>
  </div>
</template>
<script>
import { computed, reactive, toRefs, watch,ref, nextTick} from 'vue'
import {CalendarOutlined} from '@ant-design/icons-vue'
import dayjs from 'dayjs'
export default {
  components:{
    CalendarOutlined
  },
  props:{
    defaultMonth:{
      type: String,
      required: false,
      default: ''
    },
    mounthType: {
      type: String,
      default: ''
    },
    mounthId: {
      type: String,
      default: 'id_1'
    },
    styleConfig: {
      type:String,
      default:''
    },
    allDataList:{
      type: Array,
      default: ()=>{
        return []
      }
    },
    useConfig: {
      type: Object,
      default: function() {
        return {}
      }
    }
  },
  setup(props,context){
    let inputTag = ref(null);
    let aside = ref(null)
    const state = reactive({
      time:null,
      isShow:false,
      inputLength:0,
      tagList:[],
      month:[],
      typeParent:'',
      mounthId:'0',
      allDataList:[],//已有的
    })

    const inputStyle =  computed(() =>{
      let style = {}
      style.width = `${state.inputLength}px`
      return style
    })

    watch(() => props.allDataList, (value) => {
      if(value.length>0){
        state.allDataList = value
      }
    }, {immediate: true})

    watch(() => props.monthId, (value) => {
      if(!value) return
      state.mounthId = value
    }, {immediate: true})

    watch(() => props.defaultMonth, (value) => {
      if(!value) {
        state.tagList = []
        state.month = []
        state.time = ''
        return
      }
      const val_list = value !== '' ? value.split(',') : []
      setTimeout(() =>{
        state.tagList = [].concat(val_list)
        state.month = [].concat(val_list)
        context.emit('updateMonth',state.month)
        state.time = value
      },200)
    }, {immediate: true})

    watch(() => props.mounthType, (value) =>{
      if(!value) return
      state.typeParent = value
    }, {immediate: true})

    watch(() => state.time, (value) => {
      if(!value) return
      state.inputLength = inputTag.value.length * 12 + 50;
    }, {immediate: true})

    function toolTipShow(){
      if(props.useConfig?.disabled) return
      state.isShow = !state.isShow
    }

    function tagClose(index,data){
      state.tagList.splice(index,1)
      state.month = [].concat(state.tagList)
      state.time = state.tagList.join(',')
      context.emit('updateMonth',state.month)
    }

    const calculateMonth = (month) => {
      if(state.month.findIndex(mon => mon === dayjs(month).format('YYYY-MM')) !== -1){
        return 'checkbox'
      }else{
        return 'defultbox'
      }
    }
	
	//实现月份下方添加小圆点需求
    const getAllMonth = (month) => {
      if(state.allDataList.findIndex(mon => mon === dayjs(month).format('YYYY-MM')) !== -1){
        return 'checkbox1'
      }else{
        return 'defultbox1'
      }
    }

    const onPanelChange = (day,mode) => {
      if(mode.source == "month"){
        const index = state.month.findIndex(mon => mon === dayjs(day).format('YYYY-MM'))
        if(index === -1){
          state.month.push(dayjs(day).format('YYYY-MM'))
        }else{
          state.month.splice(index,1)
        }
        state.time = state.month.map(mons => (new Date(mons).getMonth() + 1)).join(',')
        state.tagList = [].concat(state.month)
        context.emit('updateMonth',state.month)
      }
    };
    return{
      inputTag,
      aside,
      ...toRefs(state),
      toolTipShow,
      getAllMonth,
      onPanelChange,
      calculateMonth,
      inputStyle,
      tagClose
    }
  }
}
</script>

<style lang="scss">
.mul-box {
  width: 100%;
  .arrbox {
    box-sizing:border-box;
    border: 1px solid #dcdee2;
    background-color: white;
    border-radius: 4px;
    font-size: 14px;
    width: 100% ;
    text-align: left;
    padding-left: 5px;
    overflow: hidden;
    cursor: pointer;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    .suffix{
      display: inline-flex;
      margin-right: 10px;
    }
    .tooltip{
      color: #ffffff;
      visibility: hidden
    }
  }
  /* 禁用盒子 */
  .dised-arrbox {
    box-sizing:border-box;
    border: 1px solid #dcdee2;
    background-color: rgba(238, 238, 236, 0.6);
    cursor: not-allowed;
    border-radius: 4px;
    font-size: 14px;
    width: 100% ;
    text-align: left;
    padding-left: 5px;
    // word-wrap: break-word;
    overflow: hidden;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    .suffix{
      margin-right: 10px;
      display: inline-flex;
    }
    .tooltip{
      color: #ffffff;
      visibility: hidden
    }
  }
  /* 标签 */
  .tags-part {
    display: inline-block;
    font-size: 14px;
    margin: 4px 4px 3px 0;
    .ant-tag-hidden{
      display: inline-block;
    }
  }
  .inputTag {
    display: inline-block;
    font-size: 14px;
    border: none;
    box-shadow: none;
    outline: none;
    padding: 5px;
    background-color: transparent;
    padding: 0;
    vertical-align: top;
    height: 32px;
    color: #495060;
    line-height: 32px;
  }
}
.monthCard .ant-tooltip-arrow-content{
  display: none
}
.checkbox{
  background-color: #0067c0;
  width: 73px;
  height: 30px;
  margin-right: 5px;
  margin-bottom: 5px;
  color: #ffffff;
  display: flex;
  border-radius: 5px;
  justify-content: center;
  align-items: center;
}
.defaultbox{
  background-color: #ffffff;
  width: 73px;
  height: 30px;
  margin-right: 5px;
  margin-bottom: 5px;
}
.checkbox1{
  position: absolute;
  left: 50%;
  height: 5px;
  width: 8px;
  border-radius: 5px;
  background-color: #ff9800;
  transform: translate3d(-50%,0,0)
}
.defaultbox1{
  background-color: #ff9800;
  height: 5px;
  width: 8px;
}
.monthCard {
  z-index: 9999;
}
.monthCard .ant-fullcalendar-month-panel-cell{
  width: 60px;
  height: 30px;
  text-align: center;
  line-height: 30px;
}
.monthCard .ant-popover-inner-content{
  width: 250px;
  padding: 8px;
  .ant-radio-group{
    display: none;
  }
  .ant-fullcalendar{
    border-top: none;
  }
}
</style>

使用月份组件

<template>
	 <div>
	 	 <multi-month @update-month="monthChange" :default-month="months" />
     </div>
<template>
<script>
import { ref, shallowRef, watch, nextTick, onMounted, inject,reactive ,computed,toRefs,getCurrentInstance,watchEffect} from 'vue'
import multiMonth from 'src/components/multiMonth/index'
export default {
      name: "monthlyLedgerProduction",
      components:{
	    multiMonth
	  },
	setup(){
		const state = reactive({
			months:'',//默认值 :default-month
		})
		 const monthChange = (timeListStr) =>{
		  console.log('月份',timeListStr)
		 }
		return{
		    monthChange,
			...toRefs(state)
		}	
	}
  }
</script>

如果想实现日期下方加黄色小圆点需求
添加 :allDataList=“allDataList”

<multi-month @update-month="monthChange" :default-month="months"  :allDataList="allDataList"/>

//给 allDataList:[‘2019-01’,‘2019-02’,‘2019-03’,‘2019-04’,‘2019-05’,‘2019-06’,‘2019-07’,‘2019-08’] 赋值即可

在这里插入图片描述

你可以使用 Vue 3 和 Ant Design Vue实现一个下拉框选择器,其中还可以输入并进行模糊搜索。这里是一个简单的示例代码: 首先,安装所需的依赖: ``` npm install vue@next ant-design-vue@next ``` 然后,在你的 Vue 组件中,引入需要的组件和样式: ```vue <template> <a-select v-model="selectedItem" mode="tags" placeholder="请输入关键字" @search="handleSearch" > <a-select-option v-for="option in filteredOptions" :key="option">{{ option }}</a-select-option> </a-select> </template> <script> import { ref, reactive, watch } from 'vue'; import { Select } from 'ant-design-vue'; export default { components: { ASelect: Select, ASelectOption: Select.Option, }, setup() { const options = ['Apple', 'Banana', 'Cherry', 'Durian', 'Elderberry']; const selectedItem = ref([]); const filteredOptions = reactive([]); watch(selectedItem, (newVal) => { console.log(newVal); }); const handleSearch = (value) => { filteredOptions.splice(0); // 清空数组 if (value) { const searchResult = options.filter((option) => option.toLowerCase().includes(value.toLowerCase()) ); filteredOptions.push(...searchResult); } }; return { selectedItem, filteredOptions, handleSearch, }; }, }; </script> <style> @import '~ant-design-vue/dist/antd.css'; </style> ``` 这个示例中,我们使用了 `a-select` 组件实现下拉框选择器,并将 `mode` 属性设置为 "tags",以支持多选。`placeholder` 属性设置为 "请输入关键字",提供了一个搜索框用于输入关键字。 在 `@search` 事件中,我们通过过滤选项数组来实现模糊搜索功能,并将搜索结果更新到 `filteredOptions` 数组中。 最后,我们使用 `v-for` 指令来渲染 `a-select-option` 组件,将搜索结果展示为可选项。 `v-model` 指令用于绑定选中的项,可以通过 `selectedItem` 引用来获取或操作选中的项。 记得在组件中导入所需的组件和样式。这样,你就可以在你的 Vue 3 项目中使用这个下拉框选择器,并实现输入和模糊搜索了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值