background

Some time ago, I encountered a requirement in the project that the input amount should be separated by thousandths. I thought it was supposed to be simple, but… There are still some problems in the process of development.

Code).

<input type="text" id="input">

const inputDom = document.getElementById('input');
const separator = ', ';
const reg = new RegExp(separator, 'g');

// Listen for input events
inputDom.addEventListener('input'.function (e) {
    const value = inputDom.value;
    if (value[value.length - 1= = ='. ') {
        return;
    }
    inputDom.value = format(value.replace(reg, ' '));
});

// Format the input
function format(string) {
    let amount = ' ';
    // To the left of the decimal
    let leftOfPoint = replaceValue;
    // Right of the decimal point
    let rightOfPoint = ' ';
    if (replaceValue.includes('. ')) {
        [leftOfPoint, rightOfPoint] = replaceValue.split('. ');
    }
    const length = leftOfPoint.length;
    / / remainder
    const n = length % 3;
    // I'm using a loop to add the thousandths, but you can also use regular expressions
    if (length > 3) {
        for (let i = 0; i < length; i++) {
            amount += leftOfPoint[i];
            //
            // n = 2 if leftOfPoint = '1234578'
            // When I = 1, I + 1 = 2 = n, amount = 12,345678
            // When I = 4, I + 1 = 5 > n, (I + 1-n) % 3 = 0, amount = 12,345,678
            if (i + 1 === n || i + 1 > n && i + 1 < length && (i + 1 - n) % 3= =0) { amount += separator; }}}else {
        amount = leftOfPoint;
    }
    // If there are decimals
    if (rightOfPoint) {
        amount += '. ' + rightOfPoint;
    }
    return amount;
}
Copy the code

Problems encountered

Normal input is no problem, the cursor is always displayed at the end. When a character is inserted or deleted continuously, the cursor position moves to the end of the inserted or deleted character, resulting in a data error. Here’s an example:

When I type 123456.90 and want to insert 7 and 8 after 6, after inserting 7, the cursor moves to the end, causing 8 to be inserted at the end, and the input box is 1234567.908 instead of the desired 12345678.90. As shown in the figure below:

Similarly, after typing 12345678.90, the cursor moves to the end of 8. If I want to delete characters 8 and 7, the cursor moves to the end of 8, resulting in the deletion of character 0. In this case, the input box value is 1234567.9 instead of the desired 123456.90. As shown in the figure below:

solution

Normally, the cursor is positioned correctly when a character is typed, inserted, or deleted, but when a value is assigned to the input box (HTMLInputElement. Value = ‘XXX’), the relative position of the cursor is lost, and the browser will display the cursor at the end by default. The crux of the matter, then, is how to remember where the cursor is.

My idea is that for each operation (input, insert, delete), remember the character before the cursor, and if the character before the cursor happens to be a delimiter, extend it to the next bit. But there are only ten numbers from 0 to 9, so what if there are repeats? For repeated numbers, we need to make an extra record, the cursor after the number of repeated. In real life, it is similar to queuing. When you’re waiting in line for the vaccine, just remember who’s in front of you. If there are a lot of programmers in the line and everyone is wearing a plaid shirt, just remember the number of people behind you in a plaid shirt.

Set cursor position mainly involves the HTMLInputElement selectionStart, HTMLInputElement. SelectionEnd, HTMLInputElement setSelectionRange ().

Input The input event object involves InputEvent, inputevent. data, and inputevent.inputType.

implementation

On paper come zhongjue shallow, must know this to practice

Without further ado, go straight to the code

<input type="text" id="input">

const separator = ', ';
const reg = new RegExp(separator, 'g');
let lastValue = ' ';

// Listen for input events
inputDom.addEventListener('input'.function (e) {
    let value = inputDom.value;
    // Enter the decimal point directly
    if (value === '. ') {
        inputDom.value = ' ';
        return;
    }
    let cursorPosition = inputDom.selectionStart;
    // If input 2 decimal points or input separator
    if (value.indexOf('. ') !== value.lastIndexOf('. ') || e.data === separator) {
        let leftOfCursor = value.substring(0, cursorPosition - 1);
        let rightOfCursor = value.substring(cursorPosition);
        inputDom.value = leftOfCursor + rightOfCursor;
        inputDom.selectionStart = cursorPosition - 1;
        inputDom.selectionEnd = cursorPosition - 1;
        return;
    } else if (value[value.length - 1= = ='. ') { // Enter the decimal point at the end
        return;
    }

    let formatValue = format(value.replace(reg, ' '));

    // Since the delete key is deleted backwards, you need to determine whether the character to be deleted is a delimiter. If so, move the cursor back one bit
    if (e.inputType === 'deleteContentForward' && getDeletedString(lastValue, value) === separator) {
        cursorPosition += 1;
    } else {
        cursorPosition = getCursorPosition(formatValue, value);
    }

    inputDom.value = formatValue;
    inputDom.selectionStart = cursorPosition;
    inputDom.selectionEnd = cursorPosition;
    lastValue = formatValue;
});

// The format function is as above
function format(string){
    // ...
}

// Get the deleted string
function getDeletedString(lastString, string) {
    let deletedString = ' ', count = 0;
    for (let i = 0; i < lastString.length; i++) {
        if (lastString[i] === string[count]) {
            if (deletedString) {
                break;
            }
            count++;
        } else{ deletedString += lastString[i]; }}return deletedString;
}

// Get the cursor position
function getCursorPosition(formatString, string) {
    let cursorPosition = inputDom.selectionStart;
    let index = cursorPosition - 1;
    // The character before the cursor is a delimiter
    if (string[index] === separator) {
        index -= 1;
    }
    // Count how many times a character before the cursor is repeated
    let count = 0;
    for (let i = 0; i < index; i++) {
        if(string[i] === string[index]) { count++; }}// Calculate the cursor position
    let n = 0;
    for (let j = 0; j < formatString.length; j++) {
        if (formatString[j] === string[index]) {
            if (n === count) {
                cursorPosition = j + 1;
                break; } n++; }}return cursorPosition;
}
Copy the code

The above code for input characters, insert characters, delete a single character, select multiple characters to delete, delete forward, delete backward can be very good to ensure that the cursor position is not wrong. As shown in the figure below:

Online demo jsdemo. Codeman. Top/HTML/inputF…

Write in the last

To recommend a GIF graph generated software GifCam, the software size is only 1.58MB, very small, easy to use. All GIF images in the article are made by this software.