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;
}