javascript實(shí)現(xiàn)富文本框選中對(duì)齊的思路與代碼
需求:
一個(gè)可編輯(contenteditable=true)的div,對(duì)齊選中內(nèi)容,左、中,右 ,其實(shí)質(zhì)是:對(duì)選中的末梢節(jié)點(diǎn),找到塊屬性的父元素,設(shè)置text-algin:center:
MDN:text-align CSS屬性定義行內(nèi)內(nèi)容(例如文字)如何相對(duì)它的塊父元素對(duì)齊。text-align 并不控制塊元素自己的對(duì)齊,只控制它的行內(nèi)內(nèi)容的對(duì)齊。
分析需求:
我們來(lái)分解一下這個(gè)需求的三個(gè)關(guān)鍵問(wèn)題: ”選中部分“,”塊元素“,"末梢元素"
1如何獲取選中的部分 *
這里涉及到的Web API Document.getSelection().getRangeAt(0) 這里只處理一個(gè)選取的情況
注意:光標(biāo)所在位置,光標(biāo)所在節(jié)點(diǎn) 視為選中區(qū)域
2什么是塊元素
MDN:
display:block
這個(gè)值會(huì)生成一個(gè)塊級(jí)元素盒子,同時(shí)在該元素之前和之后打斷(換行)。簡(jiǎn)單來(lái)說(shuō)就是,這個(gè)值會(huì)將該元素變成塊級(jí)元素。
除非特殊指定,諸如標(biāo)題(<h1>等)和段落(<p>)默認(rèn)情況下都是塊級(jí)的盒子。
用做鏈接的 <a> 元素、 <span>、 <em> 以及 <strong> 都是默認(rèn)處于 inline 狀態(tài)的。
3末梢元素(沒(méi)有子節(jié)點(diǎn)的元素)
我們操作對(duì)齊,實(shí)質(zhì)是操作盒模型中的內(nèi)容的對(duì)齊方式,也就是對(duì):圖片,文字 等設(shè)置對(duì)齊樣式,在這里我稱其為末梢節(jié)點(diǎn)
實(shí)現(xiàn)思路:
1、獲取選區(qū)內(nèi)的所有末梢元素(遞歸)
2、找到這些末梢元素的父塊元素,設(shè)置其text-align:'left|center|right'
代碼實(shí)現(xiàn):
前端頁(yè)面:一個(gè)div contenteditable="true";三個(gè)按鈕:觸發(fā)對(duì)齊(左,中,右)
document.querySelector("#btn_alignl").addEventListener("click", () => { Align.call(this, 'left') }) document.querySelector("#btn_alignc").addEventListener("click", () => { Align.call(this, 'center') }) document.querySelector("#btn_alignr").addEventListener("click", () => { Align('right') })
js 代碼:
1、一個(gè)公共的Align方法,參數(shù)為:left|center|right
/** * 1 通過(guò)getBoundaryEndNodes獲取所有末梢元素 * 2 遍歷末梢節(jié)點(diǎn),通過(guò)getBlockParent獲取每一個(gè)末梢節(jié)點(diǎn)的父級(jí)block元素 * 3 設(shè)置endnode 的 blockparent.style.textAlign=left|center|right * @param alignStr left|center|right **/ function Align(alignStr) { const rng = document.getSelection().getRangeAt(0) const commonAncestor = rng.commonAncestorContainer //獲取開(kāi)始節(jié)點(diǎn),到結(jié)尾節(jié)點(diǎn)之間的所有末梢節(jié)點(diǎn) let getBoundaryEndNodes = function (pNode) { if (pNode == boundaries.start) { boundaries.isStart = true } if (pNode == boundaries.end) { boundaries.isEnd = true resultNodes.push(pNode) console.log(pNode) } if (boundaries.isStart == true && boundaries.isEnd == false && pNode.hasChildNodes() == false) { resultNodes.push(pNode); console.log(pNode) } if (pNode.hasChildNodes() && boundaries.isEnd == false) { pNode.childNodes.forEach(node => { getBoundaryEndNodes(node) }); } } //獲取所有末梢節(jié)點(diǎn) let getEndNodes = function (node, nodes=[]) { if (node.hasChildNodes()) { node.childNodes.forEach(node => { getEndNodes(node, nodes) }); } else { nodes.push(node) } return nodes } const startBoundaryNode = getEndNodes(rng.startContainer)[0] const endBoundaryNode = getEndNodes(rng.endContainer).pop() let resultNodes = [] //存放開(kāi)始節(jié)點(diǎn),到結(jié)尾節(jié)點(diǎn)之間的所有末梢節(jié)點(diǎn) let boundaries = { start: startBoundaryNode, end: endBoundaryNode, isStart: false, isEnd: false } getBoundaryEndNodes.call(this, commonAncestor) //遍歷所有末梢節(jié)點(diǎn),找到其塊父元素 設(shè)置對(duì)齊樣式 resultNodes.forEach(node => { const blockparent = getBlockParent(node) if (!!blockparent && blockparent.style.textAlign != alignStr) { blockparent.style.textAlign = alignStr } }) }
getBlockParent的實(shí)現(xiàn)--獲取選中末梢節(jié)點(diǎn)的塊父節(jié)點(diǎn)的實(shí)現(xiàn)
let blockTags = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'ul', 'ol', 'li', 'div', 'body', 'td', 'th'] // let inlineTags = ['img', 'font', 'b', 'strong', 'span', 'a'] let blockTagSet = new Map() blockTags.forEach((v) => { blockTagSet.set(v, true) }); const source = document.querySelector('div.source'); function getBlockParent(ele) { let result = undefined if (ele === source) { console.log('已找到editor的根,并沒(méi)有找父級(jí)block元素'); result = undefined } else { switch (ele.nodeType) { //element: 判斷ele是否是塊級(jí)元素,判斷依據(jù)1 display:block 2 默認(rèn)的塊級(jí)元素 case 1: { const disPro = ele.style.display; if (disPro && disPro.toLowerCase().indexOf('block') > -1) { result = ele; } else if (blockTagSet.get(ele.tagName.toLowerCase())) { result = ele } else { result = getBlockParent(ele.parentElement) } break; } case 3: {//textNode if (!!ele.nodeValue.trim()) result = getBlockParent(ele.parentElement) else result = undefined break; } default: { break; } } //end switch }//end if return result }
總結(jié)
到此這篇關(guān)于javascript實(shí)現(xiàn)富文本框選中對(duì)齊的思路與代碼的文章就介紹到這了,更多相關(guān)js富文本框選中對(duì)齊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何用JS實(shí)現(xiàn)網(wǎng)頁(yè)瀑布流布局
這篇文章主要介紹了如何用JS實(shí)現(xiàn)網(wǎng)頁(yè)瀑布流布局,幫助大家更好的利用JavaScript制作網(wǎng)頁(yè),感興趣的朋友可以了解下2021-04-04快速查找數(shù)組中的某個(gè)元素并返回下標(biāo)示例
最近在寫(xiě)jquery的combobox插件時(shí)遇到效率問(wèn)題,再加上jquery選擇器的類(lèi)帥選,導(dǎo)致效率很慢,采用以下方式二,可以輕松解決此問(wèn)題2013-09-0945個(gè)JavaScript編程注意事項(xiàng)、技巧大全
這篇文章主要介紹了45個(gè)JavaScript編程注意事項(xiàng)、技巧大全,在這篇文章里,我將分享一些JavaScript的技巧、秘訣和最佳實(shí)踐,除了少數(shù)幾個(gè)外,不管是瀏覽器的JavaScript引擎,還是服務(wù)器端JavaScript解釋器,均適用,需要的朋友可以參考下2015-02-02JavaScript分秒倒計(jì)時(shí)器實(shí)現(xiàn)方法
這篇文章主要介紹了JavaScript分秒倒計(jì)時(shí)器實(shí)現(xiàn)方法,可實(shí)現(xiàn)按照毫秒倒計(jì)時(shí)的效果,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02JS獲得選取checkbox整行數(shù)據(jù)的方法
這篇文章主要介紹了JS獲得選取checkbox整行數(shù)據(jù)的方法,涉及使用js對(duì)DOM節(jié)點(diǎn)的操作技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-01-01