1. 程式人生 > >textarea實現輸入賬號回車新增;刪除時選中整個賬號的效果

textarea實現輸入賬號回車新增;刪除時選中整個賬號的效果

選中textarea特定範圍的內容(該textarea已被focused):

IE9以上瀏覽器:

textarea.focus();
textarea.setSelectionRange(rangeData.start, rangeData.end, [optional] selectionDirection)

IE9及以下:

textarea.focus();
var range = textarea.createTextRange(); 
range.moveStart("character", rangeData.startDev); // 偏移量
range.
moveEnd("character", rangeData.endDev); range.collapse(false); //強制游標移動到結束位置 range.select(); //選擇範圍內文字

獲取textarea選中範圍的起始位置及內容:
IE9以上瀏覽器:

textarea.focus();
rangeData.start = textarea.selectionStart;
rangeData.end = textarea.selectionEnd;
rangeData.text = (rangeData.start != rangeData.end) ? textarea.
value.substring(rangeData.start, rangeData.end) : "";

IE9及以下:

textarea.focus();
var i, 
	oS = document.selection.createRange(),
	// 為了使 oR 與 oS 在同一等級上比較 Don't: oR = textarea.createTextRange()
	oR = document.body.createTextRange();
// 移動文字範圍以便範圍的開始和結束位置能夠完全包含給定元素的文字
// 移動body的範圍,使其範圍的開始和結束位置包含textarea的整個文字
oR.moveToElementText(textarea); rangeData.text = oS.text; // 比較textarea的文字開始位置與當前選中範圍的開始位置,不斷先去移動開始位置,直至到達文字開始位置 for (i = 0; oR.compareEndPoints('StartToStart', oS) < 0 && oS.moveStart("character", -1) !== 0; i++) { // IE下回車也會佔到一個字元 if (textarea.value.charAt(i) == '\r') { i++; } } rangeData.start = i; rangeData.end = rangeData.text.length + rangeData.start;

向textarea指定位置新增文字:

// 當textarea選中文字時,新增的文字替換當前選中文字
// textarea未選中時,文字插入到游標位置(start與end相同)
this.set(textarea, rangeData); // 選中textarea特定範圍的內容

IE9以上瀏覽器:

oValue = textarea.value;
nValue = oValue.substring(0, rangeData.start) + text + oValue.substring(rangeData.end);
nStart = nEnd = rangeData.start + text.length;
st = textarea.scrollTop;
textarea.value = nValue;
// 保持textarea滾動位置不改變
if (textarea.scrollTop != st) {
    textarea.scrollTop = st;
}
// 游標指向該位置
textarea.setSelectionRange(nStart, nEnd);

IE9及以下:

// 獲取當前選中文字
sR = document.selection.createRange();
// 替換文字
sR.text = text;
// 將sR的End位置不變,起始位置與End位置合併
sR.setEndPoint('StartToEnd', sR);
// 游標指向該位置
sR.select();

實現回車時在名稱後自動新增 「;」,刪除時選中;前的整個名稱的效果:

// 註冊keydown事件
textarea.addEventListener('keydown', function(e) {
	// 	enter回車
	if(e.keyCode == 13) {...}
	// backspace刪除
	if(e.keyCode == 8) {...}
})

// enter回車處理 e.keyCode == 13
e.preventDefault();
rangeData = cursorPosition.get(this);
//此時未選中文字,獲取游標位置
if (rangeData.start == rangeData.end) {
    if (0 == rangeData.end) return;
    if (str.charAt(rangeData.end - 1) != ";"){  //游標前一個字元不是;
        cursorPosition.add(this, rangeData, ";"); //在游標位置插入;
    }
}

// backspace刪除 e.keyCode == 8
//獲取選擇文字及游標位置
rangeData = cursorPosition.get(this);
if (rangeData.start == rangeData.end) {  //此時未選中文字,獲取游標位置
    if (0 == rangeData.end) return;      //游標在最開頭
    // 游標前的字元是;
    if (str.charAt(rangeData.end - 1) == ";"){  
    	// 第一個字元是;
        if (1 == rangeData.end) return; 
		e.preventDefault();
		// 找到前一個;的位置
        var start = str.lastIndexOf(";", rangeData.end - 2),
        	end = rangeData.end;
       	setData = {
			start: start + 1,
			end: end,
			startDev: start - rangeData.start + 1,
			endDev: 0
		}
		// 選中該賬號
		cursorPosition.set(textarea, setData);
     }
}

vue自定義指令實現如下:IE9部分無效

var textareaEvent = {
    bind(el, binding, vnode) {
        var cursorPosition = {
            get: function(textarea) { //獲取選中內容
                var rangeData = { text: "", start: 0, end: 0 };
				textarea.focus();
                if (textarea.setSelectionRange) { //W3C
                    rangeData.start = textarea.selectionStart;
                    rangeData.end = textarea.selectionEnd;
                    rangeData.text = (rangeData.start != rangeData.end) ? textarea.value.substring(rangeData.start, rangeData.end) : "";
                } else if (document.selection) { //IE
                    var i, oS = document.selection.createRange(),
                        // 為了使 oR 與 oS 在同一等級上比較 Don't: oR = textarea.createTextRange()
                        oR = document.body.createTextRange();
                    // 移動文字範圍以便範圍的開始和結束位置能夠完全包含給定元素的文字
					// 移動body的範圍,使其範圍的開始和結束位置包含textarea的整個文字
                    oR.moveToElementText(textarea);
                    rangeData.text = oS.text;
                    // 比較textarea的文字開始位置與當前選中範圍的開始位置,不斷先去移動開始位置,直至到達文字開始位置
                    for (i = 0; oR.compareEndPoints('StartToStart', oS) < 0 && oS.moveStart("character", -1) !== 0; i++) {
                        // IE下回車也會佔到一個字元
                        if (textarea.value.charAt(i) == '\r') {
                            i++;
                        }
                    }
                    rangeData.start = i;
                    rangeData.end = rangeData.text.length + rangeData.start;
                }

                return rangeData;
            },
            set: function(textarea, rangeData) {
                var oR;
                if (!rangeData) {
                    alert("You must get cursor position first.")
                }
                textarea.focus();
                if (textarea.setSelectionRange) { // W3C
                    textarea.setSelectionRange(rangeData.start, rangeData.end);
                } else if (textarea.createTextRange) { // IE
                    oR = textarea.createTextRange();
                    range.moveStart("character", rangeData.startDev); // 偏移量
					range.moveEnd("character", rangeData.endDev);  
					range.collapse(false);  //強制游標移動到結束位置
					range.select();  //選擇範圍內文字
                }
            },
            add: function(textarea, rangeData, text) { //插入文字
                var oValue, nValue, sR, nStart, nEnd, st;
                this.set(textarea, rangeData);

                if (textarea.setSelectionRange) { // W3C
                    oValue = textarea.value;
                    nValue = oValue.substring(0, rangeData.start) + text + oValue.substring(rangeData.end);
                    nStart = nEnd = rangeData.start + text.length;
                    st = textarea.scrollTop;
                    textarea.value = nValue;
                    // 保持textarea滾動位置不改變
                    if (textarea.scrollTop != st) {
                        textarea.scrollTop = st;
                    }
                    // 游標指向該位置
                    textarea.setSelectionRange(nStart, nEnd);
                } else if (textarea.createTextRange) { // IE
                	// 獲取當前選中文字
                    sR = document.selection.createRange();
                    // 替換文字
                    sR.text = text;
                    // 將sR的End位置不變,起始位置與End位置合併
                    sR.setEndPoint('StartToEnd', sR);
                    // 游標指向該位置
                    sR.select();
                }
            }
        };

        function textareaEvent(e) {
            var str = this.value,
                rangeData = {};

            if (e.keyCode == 13) { //enter
                e.preventDefault();
                rangeData = cursorPosition.get(this);
                if (rangeData.start == rangeData.end) { //此時未選中文字,獲取游標位置
                    if (0 == rangeData.end) return; //游標在最開頭
                    if (str.charAt(rangeData.end - 1) != ";") { //游標前一個字元不是;
                        cursorPosition.add(this, rangeData, ";"); //在游標位置插入;
                    }
                }
            } else if (e.keyCode == 8) { //backspace
                //獲取選擇文字及游標位置
                rangeData = cursorPosition.get(this);
                if (rangeData.start == rangeData.end) { //此時未選中文字,獲取游標位置
                    if (0 == rangeData.end) return; //游標在最開頭
                    // 游標前的字元是;
                    if (str.charAt(rangeData.end - 1) == ";") {
                        // 第一個字元是;
                        if (1 == rangeData.end) return;

                        e.preventDefault();
                        // 找到前一個;的位置
                        var start = str.lastIndexOf(";", rangeData.end - 2),
                            end = rangeData.end;

                        setData = {
                            start: start + 1,
                            end: end,
                            startDev: start - rangeData.start + 1,
                            endDev: 0
                        }
                        // 選中該賬號
                        cursorPosition.set(this, setData);
                    }
                }
            }
        }
        el.__textareaEvent__ = textareaEvent;
        el.addEventListener('keydown', el.__textareaEvent__);
    },
    unbind(el, binding, vnode) {
    	el.removeEventLister('keydown', el.__textareaEvent__);
        delete el.__textareaEvent__;
    }
}

參考連結:
https://www.cnblogs.com/ranzige/p/4360457.html
http://www.planabc.net/demo/range/textarea-cursor-position.html
https://blog.csdn.net/lsy649241354/article/details/9081659
https://blog.csdn.net/skiof007/article/details/6181145?locationNum=5&fps=1