當我們要修改h5頁面上的一個表格或者段落的文本時候,通常的方法彈出一個模態對話框來提示用戶輸入,點擊確認后根據輸入的內容來修改文本節點,但這樣用戶體驗肯定不是很好。之前看到有x-editable插件可以很好的進行行內編輯,拿來使用卻發現和我用的bootstrap4不太兼容,無奈自己動手實現一個吧。
首先,理清行內編輯的基本原理:選中要編輯的DOM節點,先保存文本節點值然后插入一個文本輸入框,當按下回車鍵的時候保存文本框輸入的值同時移除文本輸入框。是不是很簡單?不過需要注意的是和文件重命名一樣,不要默認選中文件后綴名,也不允許輸入空文本。editText.js如下:
1 // 行內文本編輯 2 function editText(id, callback = null) { 3 let node = document.getElementById(id); 4 let text = node.innerText; 5 // 插入文本框 6 let input = document.createElement('input'); 7 input.type = 'text'; 8 input.placeholder = '輸入文本不能為空'; 9 input.spellcheck = false; 10 input.value = text; 11 node.innerText = ''; 12 node.append(input); 13 // 選中文本 14 let end = text.search(/\.\w+$/); 15 input.focus(); 16 input.selectionStart = 0; 17 input.selectionEnd = (end == -1) ? text.length : end; 18 // 按鍵事件 19 input.onkeydown = function(e) { 20 // 按下回車鍵 21 if (e.keyCode == 13) { 22 let data = this.value; 23 if (data == '') { 24 return; 25 } else { 26 input.onblur = false; 27 this.remove(); 28 node.innerText = data; 29 if (callback) { 30 callback(data); 31 } 32 } 33 // 按下ESC鍵 34 } else if (e.keyCode == 27) { 35 input.onblur = false; 36 this.remove(); 37 node.innerText = text; 38 } 39 } 40 // 失去焦點默認完成編輯 41 input.onblur = function() { 42 let data = this.value; 43 this.remove(); 44 if (data == '') { 45 node.innerText = text; 46 } else { 47 node.innerText = data; 48 if (callback) { 49 callback(data); 50 } 51 } 52 } 53 }
這里使用id選中元素,然后插入文本輸入框編輯,可以傳入一個回調函數來處理編輯后的數據。需要注意的是當編輯完成remove輸入框的時候會觸發blur事件,所以我添加了input.onblur = false來取消該事件,以防止重復移除,這句寫成this.onblur = false也行,不過vscode編輯器會提示你“此構造函數可能會轉換為類聲明”,因為我們以前就是用函數來申明類型的。該函數調用過程也非常簡單:
1 <body> 2 <p id="text">hello.txt</p> 3 <button onclick="edit()">編輯</button> 4 <script src="./editText.js"></script> 5 <script> 6 function edit() { 7 editText('text', function(data) { 8 console.log('新文本:' + data); 9 }); 10 } 11 </script> 12 </body>
演示一下行內編輯效果:
最后我們可以把它封裝成jquery插件,方便以后調用,改名為jquery.editText.js:
1 $.fn.extend({ 2 editText: function(callback = null) { 3 let $node = $(this); 4 let text = $node.text(); 5 $node.text('').append($('<input>').attr({type:'text', placeholder:'輸入文本不能為空', spellcheck:false}).val(text).on({ 6 keydown: function(e) { 7 if (e.keyCode == 13) { 8 let data = $(this).val(); 9 if (data == '') { 10 return; 11 } else { 12 $(this).remove(); 13 $node.text(data); 14 if (callback) { 15 callback(data); 16 } 17 } 18 } else if (e.keyCode == 27) { 19 $(this).remove(); 20 $node.text(text); 21 } 22 }, 23 blur: function() { 24 let data = $(this).val(); 25 $(this).remove(); 26 if (data == '') { 27 $node.text(text); 28 } else { 29 $node.text(data); 30 if (callback) { 31 callback(data); 32 } 33 } 34 }, 35 focus: function() { 36 let end = text.search(/\.\w+$/); 37 this.setSelectionRange(0, end == -1 ? text.length : end); 38 } 39 })).children('input:first').focus(); 40 } 41 });
引入jquery后即可使用:
1 <body> 2 <p id="text">hello.txt</p> 3 <button onclick="edit()">編輯</button> 4 <script src="./jquery-3.4.1.min.js"></script> 5 <script src="./jquery.editText.js"></script> 6 <script> 7 function edit() { 8 $('#text').editText();//可以不帶回調函數 9 } 10 </script> 11 </body>