Conformance: layout done.(not time range)
This commit is contained in:
198
src/components/durationjs.vue
Normal file
198
src/components/durationjs.vue
Normal file
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="duration-box" v-for="(unit, index) in inputTypes" :key="unit">
|
||||
<input
|
||||
type="text"
|
||||
class="duration duration-val"
|
||||
:data-index="index"
|
||||
:data-tunit="unit"
|
||||
:data-max="tUnits[unit].max"
|
||||
:maxlength="tUnits[unit].dsp === 'd' ? 3 : 2"
|
||||
:value="tUnits[unit].val.toString().padStart(2, '0')"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@keyup="onKeyUp"
|
||||
/>
|
||||
<label class="duration">{{ tUnits[unit].dsp }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
display: 'dhms',
|
||||
seconds: 0,
|
||||
minutes: 0,
|
||||
hours: 0,
|
||||
days: 0,
|
||||
totalSeconds: 0,
|
||||
apiTotal: 8740000,
|
||||
inputTypes: [],
|
||||
lastInput: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
tUnits: {
|
||||
get() {
|
||||
return {
|
||||
s: { dsp: 's', inc: 1, val: this.seconds, max: 60, rate: 1 },
|
||||
m: { dsp: 'm', inc: 1, val: this.minutes, max: 60, rate: 60 },
|
||||
h: { dsp: 'h', inc: 1, val: this.hours, max: 24, rate: 3600 },
|
||||
d: { dsp: 'd', inc: 1, val: this.days, max: this.days, rate: 86400 }
|
||||
};
|
||||
},
|
||||
set(newValues) {
|
||||
// 大於最大值時要等於最大值
|
||||
for (const unit in newValues) {
|
||||
this[unit] = newValues[unit].val;
|
||||
const input = document.querySelector(`[data-tunit="${unit}"]`);
|
||||
if (input) {
|
||||
input.value = newValues[unit].val.toString().padStart(2, '0');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onFocus(event) {
|
||||
this.lastInput = event.target;
|
||||
this.lastInput.select(); // 當呼叫該方法時,文本框內的文字會被自動選中,這樣使用者可以方便地進行複製或刪除等操作。
|
||||
},
|
||||
onBlur(event) {
|
||||
isNaN(event.target.value) ?
|
||||
event.target.value = '00' :
|
||||
event.target.value = event.target.value.toString().padStart(2, '0');
|
||||
|
||||
// 手 key 數值大於最大值時,要等於最大值
|
||||
if(event.target.value > event.target.dataset.max) event.target.value = (event.target.dataset.max - 1).toString().padStart(2, '0');
|
||||
|
||||
// 數值更新, tUnits 也更新, 並計算 totalSeconds
|
||||
this.tUnits[event.target.dataset.tunit].val = event.target.value;
|
||||
this.calculateTotalSeconds();
|
||||
},
|
||||
onKeyUp(event) {
|
||||
event.target.value = event.target.value.replace(/\D/g, '');
|
||||
|
||||
if (event.keyCode === 38 || event.keyCode === 40) {
|
||||
this.actionUpDown(event.target, event.keyCode === 38, true);
|
||||
};
|
||||
},
|
||||
actionUpDown(input, goUp, selectIt = false) {
|
||||
const tUnit = input.dataset.tunit;
|
||||
let newVal = parseInt(input.value, 10);
|
||||
newVal = isNaN(newVal) ? 0 : newVal;
|
||||
newVal += (goUp ? 1 : -1) * this.tUnits[tUnit].inc;
|
||||
|
||||
if (newVal <= 0 || newVal >= this.tUnits[tUnit].max) {
|
||||
if (newVal === 0 || (newVal < 0 && input.dataset.index < 1)) {
|
||||
newVal = '00';
|
||||
} else if (input.dataset.index >= 1) {
|
||||
const nextUnit = document.querySelector(`input[data-index="${parseInt(input.dataset.index) - 1}"]`);
|
||||
let nextUnitVal = parseInt(nextUnit.value);
|
||||
|
||||
if (newVal < 0 && nextUnitVal > 0) {
|
||||
nextUnit.value = nextUnitVal - 1;
|
||||
nextUnit.dispatchEvent(new Event('blur'));
|
||||
newVal = this.tUnits[tUnit].max - this.tUnits[tUnit].inc;
|
||||
} else if (newVal > 0) {
|
||||
nextUnit.value = nextUnitVal + 1;
|
||||
nextUnit.dispatchEvent(new Event('blur'));
|
||||
newVal = '00';
|
||||
} else {
|
||||
newVal = '00';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input.value = newVal.toString().padStart(2, '0');
|
||||
if (selectIt) input.select();
|
||||
},
|
||||
secondToDate(totalSeconds) {
|
||||
// .toString().padStart(2, '0')
|
||||
totalSeconds = parseInt(totalSeconds);
|
||||
if(!isNaN(totalSeconds)) {
|
||||
this.seconds = totalSeconds % 60;
|
||||
this.minutes = (Math.floor(totalSeconds - this.seconds) / 60) % 60;
|
||||
this.hours = (Math.floor(totalSeconds / 3600)) % 24;
|
||||
this.days = Math.floor(totalSeconds / (3600 * 24));
|
||||
}
|
||||
},
|
||||
calculateTotalSeconds() {
|
||||
let totalSeconds = 0;
|
||||
let tUnits = {
|
||||
s: { dsp: 's', inc: 1, val: this.seconds, max: 60, rate: 1 },
|
||||
m: { dsp: 'm', inc: 1, val: this.minutes, max: 60, rate: 60 },
|
||||
h: { dsp: 'h', inc: 1, val: this.hours, max: 24, rate: 3600 },
|
||||
d: { dsp: 'd', inc: 1, val: this.days, max: this.days, rate: 86400 },
|
||||
};
|
||||
|
||||
for (const unit in this.tUnits) {
|
||||
const val = parseInt(this.tUnits[unit].val, 10);
|
||||
if (!isNaN(val)) totalSeconds += val * this.tUnits[unit].rate;
|
||||
}
|
||||
|
||||
// 大於最大值時要等於最大值
|
||||
if(totalSeconds >= this.apiTotal){
|
||||
totalSeconds = this.apiTotal;
|
||||
this.tUnits = tUnits;
|
||||
this.secondToDate(this.apiTotal);
|
||||
} else {
|
||||
this.totalSeconds = totalSeconds;
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.inputTypes = this.display.split('');
|
||||
this.secondToDate(this.apiTotal);
|
||||
this.totalSeconds = this.apiTotal;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.duration-box {
|
||||
float:left;
|
||||
overflow: auto;
|
||||
height: var(--main-input-height);
|
||||
}
|
||||
.duration-box > .duration {
|
||||
border: 1px solid var(--main-bg-light);
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
background-color:transparent;
|
||||
color: var(--main-bg-light);
|
||||
}
|
||||
.duration-box > .duration:nth-child(1) {
|
||||
border-left: 1px solid var(--main-bg-light);
|
||||
border-top-left-radius: var(--main-input-br);
|
||||
border-bottom-left-radius: var(--main-input-br);
|
||||
}
|
||||
.duration-box > .duration:nth-last-child(1) {
|
||||
border-right: 1px solid var(--main-bg-light);
|
||||
border-top-right-radius: var(--main-input-br);
|
||||
border-bottom-right-radius: var(--main-input-br);
|
||||
}
|
||||
.duration {
|
||||
float:left;
|
||||
display: block;
|
||||
overflow: auto;
|
||||
height: var(--main-input-height);
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
.duration-box > label.duration {
|
||||
line-height: 28px;
|
||||
width: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.duration-box > input[type="text"].duration {
|
||||
text-align: right;
|
||||
width: 26px;
|
||||
padding: 3px 2px 0px 0px;
|
||||
}
|
||||
.duration-box > input[type="button"].duration {
|
||||
width: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user