Closed MorningZheng closed 1 year ago
Here is a way to add clock picker with calendar.
<style lang="scss" scoped> .info { position: relative; width: 100%; background-color: var(--primary-color); color: var(--primary-color-text); display: flex; flex-direction: column; padding: 0.5rem 0.5rem 0.5rem 0.5rem; div.line { width: 50%; position: absolute; bottom: -0.5rem; height: 3px; background-color: var(--pink-600); animation: { duration: 0.2s; timing-function: linear; fill-mode: forwards; iteration-count: 1; } &.full{ width: 100%; } &.date,&.year,&.month { animation: { name: rightToLeft; }; } &.hours,&.minutes { animation: { name: leftToRight; }; } @keyframes leftToRight { 0% { left: 0; } 100% { left: 50%; } } @keyframes rightToLeft { 0% { right: 0; } 100% { right: 50%; } } } ; .sleep { opacity: 0.6; } ; .dateTimeGroup { position: relative; width: 100%; display: flex; flex-direction: row; justify-content: space-around; & > div:not(.line) { //.data,.time cursor: pointer; position: relative; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; flex-grow: 1; .text { font-family: Roboto, sans-serif; font-weight: 400; font-size: 300%; } &.time { //相对.text font-size: 115%; } ; &.date { & > div { display: flex; flex-direction: column; } .year { font-size: 115%; /*opacity:0.8;*/ padding: { top: 0.5rem; bottom: 0.5rem; } } } span.pi { width: 100%; font-size: 120%; text-align: center; padding: { top: 2rem; bottom: 0.5rem; }; } } } } //覆盖 .p-datepicker { padding: 0 0 0 0; &:not(.p-datepicker-touch-ui){ min-width:24em; } ::v-deep(.p-datepicker-header,.p-timepicker){ padding: 0 0 0 0; } .footer { width: 100%; padding: { bottom: 0.5rem; left: 0.5rem; right: 0.5rem; }; } } </style> <template> <FixCalendar v-bind="PropsForCalendar" v-model:view="view.calendar" v-model="data.value" v-model:is-show="view.open" :panelStyle="{minWidth:'22em;'}"> <template #header> <div class="info"> <div class="dateTimeGroup"> <div v-if="!props.timeOnly" :class="{date:true,}"> <div> <span class="year" :class="{sleep:view.calendar!=='year'}" @click="view.calendar='year'">{{ data.year }}</span> <span class="text"> <span :class="{sleep:view.calendar!=='month'}" @click="view.calendar='month'">{{ data.month }}</span> <span class="sleep">-</span> <span :class="{sleep:view.calendar!=='date'}" @click="view.calendar='date'">{{ data.date }}</span> </span> </div> <span class="pi pi-calendar" @click="view.calendar='date'"></span> </div> <div :class="{time:true,}"> <span class="text"> <span :class="{sleep:view.calendar!=='hours'}" @click="view.calendar='hours'">{{ data.hour }}</span> <span class="sleep">:</span> <span :class="{sleep:view.calendar!=='minutes'}" @click="view.calendar='minutes'">{{ data.minute }}</span> </span> <span v-if="!props.timeOnly" class="pi pi-clock" @click="view.calendar='hours'"></span> </div> <div class="line" :class="{[props.timeOnly?'full':view.calendar]:true}"></div> </div> </div> </template> <template #clock> <ClockPicker class="flex center middle" v-model:view="view.clock" v-model:value="data.value" :is12="props.hourFormat==='12'"></ClockPicker> </template> <template #footer> <div class="width-100% flex center gap-1em padding-round-3px"> <Button class="p-button-text grow-1" label="现在" @click="data.value=new Date()"></Button> <Button class="p-button-text grow-1" label="确定" @click="view.open=false"></Button> </div> </template> </FixCalendar> </template> <script setup> import Calendar from "primevue/calendar"; import {h, reactive, toRef, watch,} from 'vue'; import ClockPicker from "./ClockPicker"; import Button from "primevue/button"; //循环劫持组件,按需修改 const walk=function (node,root){ if (node.props && node.props.class) { if (node.props.class.indexOf('p-datepicker-header') !== -1) { let a = [], b = []; for (const o of node.children) { (o.type.constructor === String ? b : a).push(o); } node.props.class += ' flex-as-col'; node.children = [...a, ]; if(this.currentView==='year'||this.currentView==='month'||this.currentView==='date') node.children.push(h('div', {class: 'width-100% flex-as-row padding-round-3px'}, b)); }else if (node.props.class.indexOf('p-timepicker') !== -1) { node.children = []; }else if (/(^|[\s\t])p\-datepicker([^\-]|[\s\t]|$)/.test(node.props.class)) { node.props[out.__scopeId] = ''; //增加clock if((this.currentView==='hours'||this.currentView==='minutes') && this.$slots.clock){ node.children=[...node.children.slice(0,-1),...this.$slots.clock(),...node.children.slice(-1)] } } } if (node.children) { if (Array.isArray(node.children)) for (const o of node.children) walk.call(this,o, node); else { for (const i in node.children) { if (node.children[i] instanceof Function) { const fn=node.children[i]; node.children[i]=(...args)=>{ const temp=[]; for(const o of fn(...args)){ temp.push(walk.call(this,o,node)); } return temp; } } } } } return node; } const FixCalendar = { mixins: [Calendar], emits:['update:view','update:isShow'], props:{ isShow:{ type:Boolean, default:false, }, }, watch:{ isShow:{ handler(nv,ov){ nv?this.open():this.close(); }, immediate:true, }, currentView(nv){ this.$emit('update:view',nv); }, overlayVisible(nv){ this.$emit('update:isShow',nv); }, view(nv){ this.currentView=nv; }, }, render(ctx, cache, $props, $setup, $data, $options) { //使用父类生成组件,并劫持 return walk.call(this,Calendar.render.call(this, ctx, cache, $props, $setup, $data, $options),null); }, methods:{ open(){ if(!this.overlayVisible)this.overlayVisible=true; }, close(){ if(this.overlayVisible)this.overlayVisible=false; }, alignOverlay(){ Calendar.methods.alignOverlay.apply(this,arguments); if(this.overlay.style.minWidth)this.overlay.style.minWidth='';//自定义min-width,允许其他组件修改 }, } } const props=defineProps({ ...Calendar.props, value:{ type:[String,Date], default:null, }, }); //批量绑定 const PropsForCalendar=reactive({}); for(const k in Calendar.props){ if(k==='view' || k==='value'|| k==='modelValue')continue; PropsForCalendar[k]=toRef(props,k); } const emits=defineEmits(['update:view','update:value','update:modelValue']); const view=reactive({ clock:undefined, calendar:undefined, open:false, }); watch(()=>view.clock,nv=>view.calendar=nv+'s'); watch(()=>view.calendar,nv=>{ if(nv.slice(-1)==='s')view.clock=nv.slice(0,-1); emits('update:view',nv); }) watch(()=> props.view,nv=>view.calendar=nv,{immediate:true}); const data=reactive({ value:null, year: '-', month: '-', date: -'', hour: '-', minute: '-', second: '-', }); watch(()=>data.value,nv=>{ if(nv){ data.year=nv.getFullYear(); data.month=`0${nv.getMonth()+1}`.slice(-2); data.date=`0${nv.getDate()}`.slice(-2); data.hour=`0${nv.getHours()}`.slice(-2); data.minute=`0${nv.getMinutes()}`.slice(-2); data.second=`0${nv.getSeconds()}`.slice(-2); }else for(const i of 'year,month,date,hour,minute,second'.split(','))view[i]='-'; }) watch(()=>props.value,nv=>data.value=nv,{immediate:!!props.value}); watch(()=>props.modelValue,nv=>data.value=nv,{immediate:!!props.modelValue}); watch(()=>data.value,nv=>{ emits('update:value',nv) emits('update:modelValue',nv); }); </script> <script> const out={}; export default out; </script>
ClockPicker.vue
<style scoped lang='scss'> /*! * ClockPicker v{package.version} for Bootstrap (http://weareoutman.github.io/clockpicker/) * Copyright 2014 Wang Shenwei. * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) */ /*! * ClockPicker v{package.version} for Bootstrap (http://weareoutman.github.io/clockpicker/) * Copyright 2014 Wang Shenwei. * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) */ .clockpicker{ .input-group-addon { cursor: pointer; } &-moving { cursor: move; } background-color: #f8f8f8; } .clockpicker-align-left.popover > .arrow { left: 25px; } .clockpicker-align-top.popover > .arrow { top: 17px; } .clockpicker-align-right.popover > .arrow { left: auto; right: 25px; } .clockpicker-align-bottom.popover > .arrow { top: auto; bottom: 6px; } .popover-title { background-color: #fff; color: #999; font-size: 24px; font-weight: bold; line-height: 30px; text-align: center; } .popover-title span { cursor: pointer; } .popover-content { padding: 12px; &:last-child { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } } .clockpicker-plate { background-color: #fff; border: 1px solid #ccc; border-radius: 50%; width: 200px; height: 200px; overflow: visible; position: relative; /* Disable text selection highlighting. Thanks to Hermanya */ -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .clockpicker-canvas, .clockpicker-dial { width: 200px; height: 200px; position: absolute; left: -1px; top: -1px; } .clockpicker-minutes { visibility: hidden; } .clockpicker-tick { border-radius: 50%; color: #666; line-height: 26px; text-align: center; width: 26px; height: 26px; position: absolute; cursor: pointer; &.active,&:hover { background-color: rgb(192, 229, 247); background-color: rgba(0, 149, 221, .25); } } .clockpicker-button { width: 100%; position: absolute; bottom: 32px; button{ position: absolute; background-image: none; background-color: #fff; border-width: 1px 0 0; border-top-left-radius: 0; border-top-right-radius: 0; margin: 0; padding: 10px 0; width: 6em !important; &:hover { background-image: none; background-color: #ebebeb; } &:focus { outline: none!important; } &.am-button { left: 5px; padding: 5px; border: 1px solid rgba(0, 0, 0, .2); border-radius: 4px; } &.pm-button { right: 5px; padding: 5px; border: 1px solid rgba(0, 0, 0, .2); border-radius: 4px; } &.selected{ color: rgb(0, 149, 221); font-weight: bolder; } } } .clockpicker-dial { -webkit-transition: -webkit-transform 350ms, opacity 350ms; -moz-transition: -moz-transform 350ms, opacity 350ms; -ms-transition: -ms-transform 350ms, opacity 350ms; -o-transition: -o-transform 350ms, opacity 350ms; transition: transform 350ms, opacity 350ms; &-out { opacity: 0; } } .clockpicker-dial-out{ &.clockpicker-hours { -webkit-transform: scale(1.2, 1.2); -moz-transform: scale(1.2, 1.2); -ms-transform: scale(1.2, 1.2); -o-transform: scale(1.2, 1.2); transform: scale(1.2, 1.2); } &.clockpicker-minutes { -webkit-transform: scale(.8, .8); -moz-transform: scale(.8, .8); -ms-transform: scale(.8, .8); -o-transform: scale(.8, .8); transform: scale(.8, .8); } } .clockpicker-canvas { -webkit-transition: opacity 175ms; -moz-transition: opacity 175ms; -ms-transition: opacity 175ms; -o-transition: opacity 175ms; transition: opacity 175ms; &-out { opacity: 0.25; } &-bearing, &-fg { stroke: none; fill: rgb(0, 149, 221); } &-bg { stroke: none; fill: rgb(192, 229, 247); } &-bg-trans { fill: rgba(0, 149, 221, .25); } & line { stroke: rgb(0, 149, 221); stroke-width: 1; stroke-linecap: round; /*shape-rendering: crispEdges;*/ } } </style> <template> <div :class="['relative','clockpicker',{'clockpicker-moving':view.moving}]"> <div class="popover-content"> <div class="clockpicker-plate" :ref="_=>view.plate=_" @mousemove="pick.move" @touchmove="pick.move" @mousedown="mouse.plate" @touchstart="mouse.plate" @mouseup="pick.done" @touchend="pick.done"> <div class="clockpicker-canvas" :ref="_=>view.canvas=_"> <svg class="clockpicker-svg" width="200" height="200" @mousedown="mouse.plate"> <g transform="translate(100,100)" :ref="_=>view.g=_"> <circle class="clockpicker-canvas-bg" :ref="_=>view.bg=_" r="13" :cx="data.cx" :cy="data.cy"></circle> <line x1="0" y1="0" :ref="_=>view.hand=_" :x2="data.cx" :y2="data.cy"></line> <circle class="clockpicker-canvas-bearing" :ref="_=>view.bearing=_" cx="0" cy="0" r="2"></circle> <circle class="clockpicker-canvas-fg" :ref="_=>view.fg=_" r="3.5" :cx="data.cx" :cy="data.cy"></circle> </g> </svg> </div> <div class="clockpicker-dial clockpicker-hours" :class="[ {'clockpicker-dial':data.currentView==='hour','clockpicker-dial-out':data.currentView!=='hour',}, ]" :style="{visibility: data.currentView==='hour'?'visible':'hidden'}"> <div v-for="(o,i) of view.hours" :style="o.css" :key="i" :class="['clockpicker-tick',{active:data.hour===o.value}]" @mousedown="pick.start" @touchstart="pick.start" @click="pick.click">{{o.html}}</div> </div> <div class="clockpicker-dial clockpicker-minutes" :class="[ {'clockpicker-dial':data.currentView==='minute','clockpicker-dial-out':data.currentView!=='minute',}, ]" :style="{visibility: data.currentView==='minute'?'visible':'hidden'}"> <div v-for="(o,i) of view.minutes" :style="o.css" :class="['clockpicker-tick',{active:data.minute===o.value}]" @mousedown="pick.start" @touchstart="pick.start">{{o.html}}</div> </div> </div> </div> <div class="clockpicker-button" v-if="props.is12" :midday="data.midday"> <button v-for="(v,i) of ['am','pm']" :class="[`${v}-button`,{selected:data.midday===v}]" @click="data.midday=v">{{v.toUpperCase()}}</button> </div> </div> </template> <script> export default { name: "TimeInput" } const Radius={ dial:100, outer:80, inner:54, tick:13, },leadingZero=num=>(num < 10 ? '0' : '') + num,transitionSupported = (()=>{ const style = document.createElement('div').style; return 'transition' in style || 'WebkitTransition' in style || 'MozTransition' in style || 'msTransition' in style || 'OTransition' in style; })(),duration = transitionSupported ? 350 : 1; const vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null; const events={ on(el,type,listener){ if(Array.isArray(type)){ for(const t of type)events.on(el,t,listener); }else{ if(!el['#listener'])el['#listener']={}; const {'#listener':_}=el; if(!_[type])_[type]=new Map; if(!_[type].has(listener))_[type].set(listener); el.addEventListener(type,listener); } return events; }, off(el,type,listener){ if(Array.isArray(type)){ for(const t of type)events.off(el,t,listener); }else{ if(!el['#listener'])return events; const {'#listener':_}=el; if(!_[type])_[type]=new Map; if(_[type].has(listener))_[type].delete(listener); el.removeEventListener(type,listener); } return events; }, removeAll(el,type){ if(Array.isArray(type)){ for(const t of type)events.removeAll(el,t); }else{ if(!el['#listener'])return events; const {'#listener':_}=el; if(!_[type])return events; for (const listener of _[type].keys()) { el.removeEventListener(type,listener); _[type].delete(listener); }; } return events; }, }; </script> <script setup> import {reactive, watch} from 'vue'; const props = defineProps({ value: { type: Date, default: null, }, is12:{ type:Boolean, default: false, }, midday:{ type:String, default:'pm', validator(val){ if(val){ val=String(val).toLowerCase(); return val==='am'||val==='pm'; }else return false; }, }, vibrate:{ type:Boolean, default:true, }, autoSwitch:{ type:Boolean, default:true, }, view:{ type:String, validator(val){ if(val){ val=String(val).toLowerCase(); return val==='hour'||val==='minute'; }else return true; }, default:'hour', }, }); const emits=defineEmits(['update:midday','update:value','update:view',]); const data = reactive({ value: null, currentView:null, midday:null, minute:0, hour:0,second:0, cx:0, cy:0, }) const view=reactive({ minutes:[], hours:[], moving:false, moved:false, editing:false, plate:null, g:null, bg:null, fg:null, hand:null, bearing:null, canvas:null, }) const flag={ setting:false, moved:true, up:true, tmr:{ up:-1, } } const setView=()=>{ const value=data[data.currentView],isHours = data.currentView === 'hour', unit = Math.PI / (isHours ? 6 : 30); const radian = value * unit, radius = !props.is12 && (isHours && value > 0 && value < 13) ? Radius.inner : Radius.outer; data.cx = Math.sin(radian) * radius; data.cy = - Math.cos(radian) * radius; }; const toggleView=(view, delay)=>setTimeout(()=>data.currentView=view,delay); const setHand = (x, y, roundBy5, dragging)=>{ const isHours = data.currentView === 'hour', unit = Math.PI / (isHours || roundBy5 ? 6 : 30), z = Math.sqrt(x * x + y * y), inner = isHours && z < (Radius.outer + Radius.inner) / 2; let radian = Math.atan2(x, - y),radius = inner ? Radius.inner : Radius.outer,value; if (props.is12) radius = Radius.outer; // Radian should in range [0, 2PI] if (radian < 0) radian = Math.PI * 2 + radian; // Get the round value value = Math.round(radian / unit); // Get the round radian radian = value * unit; const cx = Math.sin(radian) * radius, cy = - Math.cos(radian) * radius; data.cx=cx,data.cy=cy; // Correct the hours or minutes if(isHours){ if(props.is12){ if (value === 0) value = 12; if(data.midday==='pm')value+=12; }else{ if (value === 12) value = 0; value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12; } }else{ if (roundBy5) value *= 5; if (value === 60) value = 0; } // Once hours or minutes changed, vibrate the device if (data[data.currentView] !== value) { if (vibrate && props.vibrate) { // Do not vibrate too frequently if (! data.vibrateTimer) { navigator[vibrate](10); data.vibrateTimer = setTimeout(()=>data.vibrateTimer=-1, 100); } } } data[data.currentView] = value; // Place clock hand at the top when dragging if(!view.g)return; if (dragging || (! isHours && value % 5)) { view.g.insertBefore(view.hand, view.bearing); view.g.insertBefore(view.bg, view.fg); view.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans'); } else { // Or place it at the bottom view.g.insertBefore(view.hand, view.bg); view.g.insertBefore(view.fg, view.bg); view.bg.setAttribute('class', 'clockpicker-canvas-bg'); } }; const mouse={ plate(e,start=true){ if(e.defaultPrevented)return; const rect=view.bg.getBoundingClientRect(),{top,left} = { top: rect.top + window.scrollY, left: rect.left + window.scrollX, },{clientX:x,clientY:y}=e; const inner = x>=left && x<=(left+rect.width) && y>=top && (y<=top+rect.height); if(inner && start)pick.start(e); }, } const pick={ start(e, space){ e.preventDefault(); if(e.touches) pick['#']={ touches:e.touches, changedTouches:e.changedTouches, }; view.editing=true; flag.moved=false; clearTimeout(flag.tmr.up); flag.tmr.up=setTimeout(()=>flag.up=false,200); }, move(e){ if(!view.editing||flag.moved)return; e.preventDefault(); const rect=view.plate.getBoundingClientRect(); const offset = { top: rect.top + window.scrollY, left: rect.left + window.scrollX, }, isTouch = /^touch/.test(e.type), x0 = offset.left + Radius.dial, y0 = offset.top + Radius.dial, dx = (isTouch ? e.touches[0] : e).pageX - x0, dy = (isTouch ? e.touches[0] : e).pageY - y0, z = Math.sqrt(dx * dx + dy * dy); // When clicking on minutes view space, check the mouse position if (view.space && (z < Radius.outer - Radius.tick || z > Radius.outer + Radius.tick)) return; // Clock setHand(dx, dy, data.currentView==='hour'?true:flag.up, true); }, done(e){ if(!view.editing)return; e.preventDefault(); clearTimeout(flag.tmr.up); flag.moved=true; view.editing=false; const isTouch = /^touch/.test(e.type); const rect=view.plate.getBoundingClientRect(); const offset = { top: rect.top + window.scrollY, left: rect.left + window.scrollX, }, x0 = offset.left + Radius.dial, y0 = offset.top + Radius.dial; const dx = (isTouch ? e.touches[0]||pick['#'].touches[0] : e).pageX - x0, dy = (isTouch ? e.touches[0]||pick['#'].touches[0] : e).pageY - y0; const x = (isTouch ? e.changedTouches[0]||pick['#'].changedTouches[0] : e).pageX - x0; const y = (isTouch ? e.changedTouches[0]||pick['#'].changedTouches[0] : e).pageY - y0; if (flag.moved && x === dx && y === dy) setHand(x, y,data.currentView==='hour'?true:flag.up,true); view.moving=false; flag.up=true; if(props.autoSwitch){ if(data.currentView==='hour')toggleView('minute', duration / 2); else if(data.currentView==='minute')toggleView('hour', duration / 2); }; }, } { watch(()=>props.is12,nv=>{ if(nv){ for (let i = 1; i < 13; i ++) { const tick = {value:i},radian = i / 6 * Math.PI,radius = Radius.outer; tick.css={ left: Radius.dial + Math.sin(radian) * radius - Radius.tick +'px', top: Radius.dial - Math.cos(radian) * radius - Radius.tick +'px', 'font-size': '120%', }; tick.html=leadingZero(i); view.hours.push(tick); } }else{ for (let i = 0; i < 24; i ++) { const tick = {value:i}; const radian = i / 6 * Math.PI; const inner = i > 0 && i < 13; const radius = inner ? Radius.inner : Radius.outer; tick.css={ left: Radius.dial + Math.sin(radian) * radius - Radius.tick +'px', top: Radius.dial - Math.cos(radian) * radius - Radius.tick +'px' }; if (inner) tick.css['font-size']='120%'; tick.html=i>13||i===0?leadingZero(i):i; view.hours.push(tick); } } },{immediate:true}); for (let i = 0; i < 60; i += 5) { const tick = {'font-size': '120%'},radian = i / 30 * Math.PI,radius = Radius.outer; tick.css={ left: Radius.dial + Math.sin(radian) * radius - Radius.tick +'px', top: Radius.dial - Math.cos(radian) * radius - Radius.tick +'px', }; tick.html=leadingZero(i); view.minutes.push(tick); } } //初始化 watch(()=>data.currentView,nv=>{ setView(); if(props.view!==nv)emits('update:view',nv); }); watch(()=>props.view,nv=>{ if(data.currentView!==nv)data.currentView=nv; },{immediate:true}); watch(()=>props.midday,nv=>{ if(data.midday!==nv)data.midday=nv; }) watch(()=>data.midday,nv=>{ if(props.midday!==nv)emits('update:midday',nv); const time=new Date; if(data.value)time.setTime(data.value.getTime()); let prefix=0; if(props.is12){ if((data.midday==='pm'&&data.hour<12))prefix=12; else if(data.midday==='am'&&data.hour===12)prefix=-12; } time.setHours(data.hour+prefix); if(!data.value || data.value.getTime()!==time.getTime())data.value=time; }) watch(()=>[data.hour,data.minute,view.editing],nv=>{ if(view.editing)return; const time=new Date(); if(data.value)time.setTime(data.value.getTime()); let prefix=0; if(props.is12){ if((data.midday==='pm'&&data.hour<12))prefix=12; else if(data.midday==='am'&&data.hour===12)prefix=-12; } time.setHours(data.hour+prefix); time.setMinutes(data.minute); time.setSeconds(data.second); // console.log(time) if(!data.value || time.getTime()!==data.value.getTime())data.value=time; }) watch(()=>data.value,nv=>{ let hour=0,minute=0,second=0,midday=null; if(nv){ hour=nv.getHours(); minute=nv.getMinutes(); second=nv.getSeconds(); if(props.is12){ midday='am'; if(hour>11){ if(hour<24)midday='pm'; hour-=12; } if(hour===0)hour=12; } } if(data.hour!==hour)data.hour=hour; if(data.minute!==minute)data.minute=minute; if(data.second!==second)data.second=second; if(data.midday!==midday)data.midday=midday; setView(); flag.setting=false; if(props.value && nv){ if(props.value.getTime()===nv.getTime())return; } emits('update:value',nv); }); watch(() => props.value, nv => { flag.setting=true; if(nv){ if(!data.value || data.value.getTime()!==nv.getTime())data.value=nv; }else data.value=nv; },{immediate:true}) defineExpose({ toggleView, }) </script>
No response
Hope it helps you
Please describe the issue properly. We would be grateful if you create a PR with the possible solution.
Describe the feature you would like to see added
Here is a way to add clock picker with calendar.
ClockPicker.vue
Is your feature request related to a problem?
No response
Describe the solution you'd like
No response
Describe alternatives you have considered
No response
Additional context
No response