如何使用 HTML5 或/使用 Angular8 实现持续时间选择器,小时数超过 24?

Gur*_*ish 3 html angular-material angular angular8

我正在尝试实现一个控件,使用

 <input type="time"/>
Run Code Online (Sandbox Code Playgroud)

或只是与

  <input type="text"/>
Run Code Online (Sandbox Code Playgroud)

并实现一个持续时间选择器控件,该控件的小时格式可以超过 24,例如 000:00:00 或 hhh:mm:ss,并且没有 am/pm 选项(时间的默认输入类型具有 am/pm 格式的格式,这在我的情况下没有用)。要求是能够使用向上和向下键增加减少持续时间,就像 HTML 的默认输入类型时间一样。

是否有任何本机HTMLangular或材料组件?或者有没有办法使用正则表达式/模式或其他东西来实现这一点?

Chi*_*hif 5

我能想到的一种方法是编写您的自定义控件(正如@Allabakash 也提到的)。对于原生 HTML,控件可以是这样的:

window.addEventListener('DOMContentLoaded', (event) => {
            document.querySelectorAll('[my-duration-picker]').forEach(picker => {
                //prevent unsupported keys
                const acceptedKeys = ['Backspace', 'ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp'];
                const selectFocus = event => {
                    //get cursor position and select nearest block;
                    const cursorPosition = event.target.selectionStart;
                    "000:00:00" //this is the format used to determine cursor location
                    const hourMarker = event.target.value.indexOf(":");
                    const minuteMarker = event.target.value.lastIndexOf(":");
                    if (hourMarker < 0 || minuteMarker < 0) {
                        //something wrong with the format. just return;
                        return;
                    }
                    if (cursorPosition < hourMarker) {
                        event.target.selectionStart = 0; //hours mode
                        event.target.selectionEnd = hourMarker;
                    }
                    if (cursorPosition > hourMarker && cursorPosition < minuteMarker) {
                        event.target.selectionStart = hourMarker + 1; //minutes mode
                        event.target.selectionEnd = minuteMarker;
                    }
                    if (cursorPosition > minuteMarker) {
                        event.target.selectionStart = minuteMarker + 1; //seconds mode
                        event.target.selectionEnd = minuteMarker + 3;
                    }
                }
                const insertFormatted = (inputBox, secondsValue) => {
                    let hours = Math.floor(secondsValue / 3600);
                    secondsValue %= 3600;
                    let minutes = Math.floor(secondsValue / 60);
                    let seconds = secondsValue % 60;
                    minutes = String(minutes).padStart(2, "0");
                    hours = String(hours).padStart(3, "0");
                    seconds = String(seconds).padStart(2, "0");
                    inputBox.value = hours + ":" + minutes + ":" + seconds;
                }
                const increaseValue = inputBox => {
                    const rawValue = inputBox.value;
                    sectioned = rawValue.split(':');
                    let secondsValue = 0
                    if (sectioned.length === 3) {
                        secondsValue = Number(sectioned[2]) + Number(sectioned[1] * 60) + Number(sectioned[0] * 60 * 60);
                    }
                    secondsValue += 1;
                    insertFormatted(inputBox, secondsValue);
                }
                const decreaseValue = inputBox => {
                    const rawValue = inputBox.value;
                    sectioned = rawValue.split(':');
                    let secondsValue = 0
                    if (sectioned.length === 3) {
                        secondsValue = Number(sectioned[2]) + Number(sectioned[1] * 60) + Number(sectioned[0] * 60 * 60);
                    }
                    secondsValue -= 1;
                    if (secondsValue < 0) {
                        secondsValue = 0;
                    }
                    insertFormatted(inputBox, secondsValue);
                }
                const validateInput = event => {
                    sectioned = event.target.value.split(':');
                    if (sectioned.length !== 3) {
                        event.target.value = "000:00:00"; //fallback to default
                        return;
                    }
                    if (isNaN(sectioned[0])) {
                        sectioned[0] = "000";
                    }
                    if (isNaN(sectioned[1]) || sectioned[1] < 0) {
                        sectioned[1] = "00";
                    }
                    if (sectioned[1] > 59 || sectioned[1].length > 2) {
                        sectioned[1] = "59";
                    }
                    if (isNaN(sectioned[2]) || sectioned[2] < 0) {
                        sectioned[2] = "00";
                    }
                    if (sectioned[2] > 59 || sectioned[2].length > 2) {
                        sectioned[2] = "59";
                    }
                    event.target.value = sectioned.join(":");
                }
                const controlsDiv = document.createElement("div");
                const scrollUpBtn = document.createElement("button");
                const scrollDownBtn = document.createElement("button");
                scrollDownBtn.textContent = " - ";
                scrollUpBtn.textContent = " + ";
                scrollUpBtn.addEventListener('click', (e) => {
                    increaseValue(picker);
                });
                scrollDownBtn.addEventListener('click', (e) => {
                    decreaseValue(picker);
                });
                picker.parentNode.insertBefore(scrollDownBtn, picker.nextSibling);
                picker.parentNode.insertBefore(scrollUpBtn, picker.nextSibling);
                picker.value = "000:00:00";
                picker.style.textAlign = "right"; //align the values to the right (optional)
                picker.addEventListener('keydown', event => {
                    //use arrow keys to increase value;
                    if (event.key == 'ArrowDown' || event.key == 'ArrowUp') {
                        if(event.key == 'ArrowDown'){
                        decreaseValue(event.target);
                        }
                        if(event.key == 'ArrowUp'){
                        increaseValue(event.target);
                        }
                        event.preventDefault(); //prevent default
                    }

                    if (isNaN(event.key) && !acceptedKeys.includes(event.key)) {
                        event.preventDefault(); //prevent default
                        return false;
                    }
                });
                picker.addEventListener('focus', selectFocus); //selects a block of hours, minutes etc
                picker.addEventListener('click', selectFocus); //selects a block of hours, minutes etc
                picker.addEventListener('change', validateInput);
                picker.addEventListener('blur', validateInput);
                picker.addEventListener('keyup', validateInput);
            });
        });
Run Code Online (Sandbox Code Playgroud)
<input type="text" my-duration-picker></input>
Run Code Online (Sandbox Code Playgroud)

在 Google Chrome 78 上测试和工作。我稍后会做一个 Angular 版本。

对于 Angular 版本,您可以编写自己的自定义指令并将其导入到您的app-module-ts声明中。请参阅 stackblitz 上的此示例:

应用演示:https : //angular-xbkeoc.stackblitz.io

代码:https : //stackblitz.com/edit/angular-xbkeoc

更新:随着时间的推移,我开发并改进了这个概念。您可以在此处查看选择器 https://nadchif.github.io/html-duration-picker.js/