SOURCE

console 命令行工具 X clear

                    
>
console
let factories = {};
let caches = {};
function define(modsname, factory) {
    factories[modsname] = factory;
}
function require(mods, callback) {
    let result = mods.map(function (name) {
        if (caches[name]) {
            return caches[name];
        } else {
            caches[name] = factories[name]();
        }
        return caches[name];
    });
    return callback.apply(null, result);
}

define('measure', function () {
    let span = document.createElement('span');
    let st = span.style;
    st.position = 'absolute';
    st.left = 0;
    st.top = 0;
    st.zIndex = -1;
    st.visibility = 'hidden';
    st.fontSize = '14px';
    st.fontFamily = 'Consolas';
    span.classList.add('measurer');
    document.body.appendChild(span);
    let cvs = document.createElement('canvas');
    let ctx = null;
    function m1(str) {
        span.innerHTML = str.replace(/\s/g, ' ');
        return span.getBoundingClientRect().width;
    }
    function m2(str) {
        if (!ctx) {
            ctx = cvs.getContext('2d');
        }
        ctx.font = '14px Consolas';
        return ctx.measureText(str).width;
    }
    if (cvs.getContext) {
        return m2;
    } else {
        return m1;
    }
});


define('inputarea', function () {
    let elem = document.querySelector('.inputarea');
    return {
        on(type, listener) {
            elem.addEventListener(type, listener);
        },
        off(type, listener) {
            elem.removeEventListener(type, listener);
        },
        getFrontWidth() {
            return require(['measure'], function (measure) {
                let sel = elem.selectionEnd;
                let front = elem.value.slice(0, sel);
                return measure(front);
            });
        }
    };
});

define('cursor', function () {
    let elem = document.querySelector('.cursor');
    return {
        moveX(x) {
            elem.style.left = x + 'px';
        },
        moveY(y) {
            elem.style.top = y + 'px';
        },
        move(x, y) {
            elem.style.left = x + 'px';
            elem.style.top = y + 'px';
        }
    }
});

require(['inputarea', 'cursor'], function (inputarea, cursor) {
    function move() {
        setTimeout(() => {
            let width = inputarea.getFrontWidth();
            cursor.moveX(width);
        });
    }
    inputarea.on('input', function () {
        let width = inputarea.getFrontWidth();
        cursor.moveX(width);
    });
    inputarea.on('mousedown', function () {
        move();
        inputarea.on('mousemove',move);
    });
    inputarea.on('mouseup',function(){
        inputarea.off('mousemove',move);
    })
    inputarea.on('keydown', function () {
        setTimeout(() => {
            let width = inputarea.getFrontWidth();
            cursor.moveX(width);
        })
    })
})
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=, initial-scale=">
	<meta http-equiv="X-UA-Compatible" content="">
	<title></title>
</head>
<body>
	<textarea wrap="off" class="inputarea" name="" id="" cols="" rows=""></textarea>
    <div class="cursor"></div>
</body>
</html>
* {
    margin: 0;
    padding: 0;
}
.inputarea {
    position: absolute;
    outline: none;
    width: 100%;
    height: 100%;
    border: 0;
    font-size: 14px;
    font-family: Consolas;
    caret-color: transparent;
    line-height: 20px;
}
.cursor {
    position: absolute;
    top: 0;
    left: 0;
    border-left: 2px solid red;
    z-index: 1;
    height: 20px;
    width: 0;
    cursor: text;
}
.inputarea::selection {
    background: #ddd;
}