整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          快速了解JavaScript富文本編輯

          快速了解JavaScript富文本編輯

          文本編輯器(Rich Text Editor)是在網頁上使用的一種所見即所得的文本編輯器,是 Web 應用開發中很常見的需求。

          富文本實現

          在 HTML 文檔上共有 2 中方式實現富文本編輯器。一種是使用 iframe,另一種是使用 contenteditable 屬性指定 HTML 文檔元素。

          iframe

          第一種方式是使用 iframe 標簽。

          在空白的 HTML 文檔中嵌入一個 iframe,并將 designMode 屬性設置為 "on",文檔就會變成可編輯的,實際編輯的則是 <body> 元素的 HTML,默認值是 "off"。文檔變成可編輯后,就可以像使用文字處理程序一樣編輯文本,通過鍵盤將文本標記為粗體、斜體等等。

          作為 iframe 源的是一個非常簡單的空白 HTML 頁面。下面是一個例子:

          <!DOCTYPE html>
          <html>
          <head>
              <title>Blank Page for Rich Text Editing</title>
          </head>
          <body>
          </body>
          </html>

          這個頁面會像其他任何頁面一樣加載到 iframe 里。為了可以編輯,必須將文檔的 designMode 屬性設置為 "on"。不過,只有在文檔完全加載之后可以設置。在這個包含頁面內,需要使用 onload 事件處理程序在適當時機設置 designMode,如下面的例子所示:

          <iframe name="editor" style="height: 100px; width: 100px"></iframe>
          <script>
              window.addEventListener("load", ()=> {
                  frames["editor"].document.designMode="on";
              });
          </script>

          以上代碼加載之后,可以在頁面上看到一個類似文本框的區域。這個框的樣式具有網頁默認樣式,不過可以通過 CSS 調整。

          contenteditable

          第二種方式是使用 contenteditable 屬性指定 HTML 文檔中的元素。該方式是 IE 最早實現的。使用方式是在一個元素上添加 contenteditable 屬性并設置為 true 或者空字符串"",然后該元素會立即被用戶編輯。如下所示:

          <div class="editor" id="editorId" contenteditable="true"></div>

          元素中包含的任何文本都會自動被編輯, 元素本身類似于<textarea> 元素。通過設置contentEditable 屬性,也可以隨時切換元素的可編輯狀態:

          let div=document.getElementById("editorId");
          richedit.contentEditable="true";

          contentEditable 屬性有3 個可能的值:"true" 表示開啟,"false" 表示關閉,"inherit" 表示繼承父元素的設置。主流瀏覽器都支持 contentEditable 屬性。

          <small>注意:contenteditable 是一個非常多才多藝的屬性。比如,訪問偽 URL data:text/html, <html contenteditable>可以把瀏覽器窗口轉換為一個記事本。這是因為這樣會臨時創建 DOM 樹并將整個文檔變成可編輯區域。<small>

          與富文本交互

          上面講到了如何在 HTML 文檔中實現富文本編輯器,而現在需要了解要使用什么方式與富文本編輯器交互。document 提供了 execCommand() 方法,該方法會影響使用 contentEditable 屬性實現可編輯區域的元素。方法說明如下所示:

          execCommand(commandId: string, showUI?: boolean, value?: string): boolean;
          • commandId:參數是 string 值,表示要執行的命令。下面會列出可用命令。
          • showUI:參數是 boolean 的可選值,表示瀏覽器是否為命令提供用戶界面,一般為 false。為兼容的話,該參數需要始終為 false,因為 Mozilla 沒有實現,會在其為 true 時拋出錯誤。
          • value:參數是 string 的可選值,是一些命令需要額外的參數,默認為 null

          該方法執行后,會返回 boolean 值,如果是 false,表示操作不被支持或未被啟用。

          注意:在調用一個命令前,不要嘗試使用返回值去校驗瀏覽器的兼容性

          不同瀏覽器支持的命令也不一樣。下標列出了最常用的命令。

          命令

          作用

          可選值

          backColor

          設置文檔背景顏色。在styleWithCss模式下,則只影響容器元素的背景顏色。

          顏色值<color>字符串(IE使用這個命令設置文本背景色)

          bold

          切換選中文本的粗體樣式

          null

          copy

          將選中內容復制到剪貼板

          null

          createLink

          將選中內容轉換為指向給定URL的鏈接

          URL鏈接值,至少包含一個字符

          cut

          將選中內容剪切到剪貼板

          null

          delete

          刪除選中的內容

          null

          fontName

          將選中文本改為使用指定字體

          字體名(例如:"Arial")

          fontSize

          將選中文本改為指定字體大小

          提供HTML字體尺寸(1-7)

          foreColor

          將選中文本改為指定顏色

          顏色值<color>字符串

          formatBlock

          將選中文本包含在指定的HTML標簽中

          提供HTML標簽,如<h1>

          indent

          縮進文本

          null

          insertHorizontalRule

          在光標位置插入<hr>元素

          null

          insertImage

          在光標位置插入圖片

          圖片的URL鏈接

          insertOrderedList

          在光標位置插入<ol>元素

          null

          insertunorderedlist

          在光標位置插入<ul>元素

          null

          insertParagraph

          在光標位置插入<p>元素

          null

          italic

          切換選中文本的斜體樣式

          null

          justifyCenter

          在光標位置或者所選內容進行文字居中

          null

          justifyFull

          在光標位置或者所選內容進行文本對齊

          null

          justifyLeft

          在光標位置或者所選內容進行左對齊

          null

          justifyRight

          在光標位置或者所選內容進行右對齊

          null

          outdent

          減小縮進

          null

          paste

          在光標位置粘貼剪貼板內容,如果有被選中的內容,會被替換

          null

          redo

          重做被撤銷的操作

          null

          removeFormat

          對所選內容去除HTML格式。這是formatBlock的反操作

          null

          selectAll

          選中編輯區里的全部內容

          null

          strikeThrough

          切換刪除線

          null

          subscript

          切換下角標

          null

          superscript

          切換上角標

          null

          underline

          切換下劃線

          null

          undo

          撤銷最近執行的命令

          null

          unlink

          取出所選鏈接的<a>標簽

          null

          styleWithCSS

          用這個取代useCSS命令。切換使用HTML tags還是CSS來生成標記。

          Boolean值,false使用CSS,true使用HTML

          剪貼板相關的命令與瀏覽器關系密切。雖然這些命令并不都可以通過 document.execCommand() 使用,但相應的鍵盤快捷鍵都是可以用的。

          這些命令可以用于修改 iframe 中富文本區域的外觀,如下面的例子所示:

          // 在內嵌窗格中切換粗體文本樣式
          frames["editor"].document.execCommand("bold", false, null);
          // 在內嵌窗格中切換斜體文本樣式
          frames["editor"].document.execCommand("italic", false, null);
          // 在內嵌窗格中創建指向www.wrox.com 的鏈接
          frames["editor"].document.execCommand("createlink", false, "http://www.wrox.com");
          // 在內嵌窗格中為內容添加<h1>標簽
          frames["editor"].document.execCommand("formatblock", false, "<h1>");

          同樣的方法也可以用于頁面中添加了 contenteditable 屬性的元素,只不過要使用當前窗口而不是內嵌窗格中的 document 對象:

          // 切換粗體文本樣式
          document.execCommand("bold", false, null);
          // 切換斜體文本樣式
          document.execCommand("italic", false, null);
          // 創建指向www.wrox.com 的鏈接
          document.execCommand("createlink", false, "http://www.wrox.com");
          // 為內容添加<h1>標簽
          document.execCommand("formatblock", false, "<h1>");

          注意:使用bold的命令在瀏覽器中生成的 HTML 差別很大。如在 IE 和 Opera 中使用<strong>標簽,在 Safari 和 Chrome 中使用<b>標簽,在 Firefox 中使用 <span> 標簽。

          document 中提供了 queryCommandEnabled() 方法:

          queryCommandEnabled(commandId: string): boolean;
          • commandId:接收 string 類型參數,是待查詢是否可用的命令。

          該方法用于確定對當前選中文本或光標所在位置是否可以執行相關命令。true 指令可用,false 不可用。如下所示:

          let result=document.queryCommandEnabled("selectAll");

          但要注意,返回 true 并不代表允許執行相關命令,只代表當前選區適合執行相關命令。在 Firefox 中,queryCommandEnabled("cut") 即使默認不允許剪切也會返回 true

          document 還提供 queryCommandState() 方法:

          queryCommandState(commandId: string): boolean;
          • commandId:參數是要確定的命令。

          該方法用于確定相關命令是否應用到了當前文本選區。如下所示:

          let isBold=document.queryCommandState("selectAll");

          富文本編輯器可以利用這個方法更新粗體、斜體等按鈕。

          在介紹一下 queryCommandValue() 方法:

          queryCommandValue(commandId: string): string;

          這個方法用于返回執行命令時使用的值,參考 execCommand() 方法使用的第三個參數。如下所示,如果一段選中文本應用了值為 5 的 "fontsize" 命令,使用該方法會返回 5:

          let fontSize=document.queryCommandValue("fontsize");

          這個方法可用于確定如何將命令應用于文本選區,從而進一步決定是否需要執行下一個命令。

          富文件選區

          Selection 對象表示用戶選中的文本范圍或光標的位置,它代表頁面中的文本選區。可以使用 windowdocument 對象調用 getSelection() 方法獲取文本選區。Selection 對象擁有以下屬性。

          • anchorNode:只讀屬性,描述選區起點所在的節點。
          • anchorOffset:只讀屬性,返回的是選區起點在 anchorNode 中的位置偏移量 。
          • focusNode:只讀屬性,返回選區終點所在的節點。
          • focusOffset:只讀屬性,返回的是選區終點在 focusNode 中的位置偏移量。
          • isCollapsed:只讀屬性,返回boolean值,用來表示選區起點和終點是否在同一個位置。
          • rangeCount:只讀屬性,返回選區所包含的 DOM 范圍數量。

          Selection 的屬性并沒有包含很多有用的信息。好在它的以下方法提供了更多信息,并允許操作選區。

          • addRange(range):把給定的 DOM 范圍添加到選區。
          • collapse(node, offset):將選區折疊到給定節點中給定的文本偏移處。
          • collapseToEnd():將選區折疊到終點。
          • collapseToStart():將選區折疊到起點。
          • containsNode(node):判斷給定節點是否包含在選區中。
          • deleteFromDocument():從文檔中刪除選區內容。與執行 execCommand("delete", false, null) 命令結果相同。
          • extend(node, offset):通過將 focusNodefocusOffset 移動到指定值來擴展選區。
          • getRangeAt(index):返回選區中指定索引處的 DOM 范圍。
          • removeAllRanges():將所有的區域都從選區中移除。
          • removeRange(range):從選區中移除指定的 DOM 范圍。
          • selectAllChildren(node):清除選區并選擇給定節點的所有子節點。
          • toString():返回選區中的純文本內容。

          下面介紹一個例子,是使用 Selection 對象實現選中文本高亮:

          function highlight() {
              let selection=document.getSelection();
              // 取得表示選區的范圍
              let range=selection.getRangeAt(0);
              // 高亮選中的文本
              let span=document.createElement("span");
              span.style.backgroundColor="yellow";
              // 給選中文本添加背景為黃色的<span>標簽
              range.surroundContents(span);
          }

          效果如下:

          通過表單提交富文本

          因為富文本編輯不是在表單控件中實現,這意味著要將富文本編輯結果提交給服務器,就要手動進行。我們會在表單中添加一個 type="hidden" 的字段,在提交表單時,通過監聽器,從元素中提取出 HTML 并插入隱藏字段中。如下所示:

          // form 實例是`<form>` 元素,可以使用DOM獲取
          form.addEventListener("submit", (event)=> {
              let target=event.target;
              target.elements["content"].value=frames["editor"].document.body.innerHTML;
          });

          上述從編輯器中獲取了 HTML 后,將其插入名為 content 的字段中。下面是對于 contenteditable 元素實現的方式:

          這里,代碼使用文檔主體的 innerHTML 屬性取得了 iframe 的 HTML,然后將其插入名為 "comments" 的表單字段中。這樣做可以確保在提交表單之前給表單字段賦值。如果使用 submit() 方法手工提交表單,那么要注意在提交前先執行上述操作。對于 contenteditable 元素,執行這一操作的代碼是類似的:

          // form 實例是`<form>` 元素,可以使用DOM獲取
          form.addEventListener("submit", (event)=> {
              let target=event.target;
              target.elements["content"].value=document.getElementsByClassName("editor")[0].innerHTML;
          });

          總結

          本文介紹了實現富文本編輯器有兩種方式:使用 iframecontenteditable 屬性。介紹了使用 document.execCommand() 方法來實現加粗、斜體樣式等功能,還有一些相應的功能。而且富文本編輯的內容要上傳到服務器,還要將內容先復制到表單中的一個字段上,然后在提交。

          在進行元素定位時,如果遇到無法找到的情況,首先需要考慮是否存在嵌套的 frame 窗口或者目標元素位于新打開的窗口中。這時,必須進行相應的 frame 切換或窗口切換操作。

          frame 類似于在原始主 HTML 頁面的基礎上嵌套了一個獨立的 HTML,彼此之間相互獨立且不產生影響。

          通常,當打開一個頁面時,光標默認定位在主頁面中。如果頁面由多個 frame 構成,直接定位到具體元素可能會受限。因此,需要在定位元素之前切換到目標 frame 中,以便準確查找所需的元素。

          iframe 解析

          如圖可以看到 iframe 的標簽。

          iframe 的多種切換方式

          HTML 代碼示例:

          <iframe src="1.html" id="hogwarts_id" name="hogwarts_name"></iframe>

          那么通過傳入 id、name、index 以及 Selenium 的 WebElement 對象來切換 frame:

          Pyhton 實現

          # index:傳入整型的參數,從 0 開始,這里的 0 就是第一個 frame
          driver.switch_to.frame(0)
          
          #id:iframe 的 id
          driver.switch_to.frame("hogwarts_id")
          
          #name: iframe 的 name
          driver.switch_to.frame("hogwarts_name")
          
          #WebElement: 傳入 `selenium.webelement` 對象
          driver.switch_to.frame(driver.find_element(By.TAG_NAME,"iframe"))

          Java 實現

          //通過位置index選中frame,0表示第一個frame
          driver.switchTo().frame(0);
          //通過frame的id或name來選中frame
          driver.switchTo().frame("hogwarts_id");
          driver.switchTo().frame("hogwarts_name");
          //WebElement: 傳入 `selenium.webelement` 對象
          driver.switchTo().frame(driver.findElement(By.tagName("iframe")));

          iframe 切換回默認頁面

          在切換頁面之后,如果還想操作原頁面,則可以使用:

          Python 版本

          driver.switch_to.default_content()

          Java 版本

          driver.switchTo().defaultContent();

          iframe 多層切換

          如圖所示為多層嵌套結構的 iframe。

          從最外部 iframe 切換到 iframe2 則需要層層切換,當從 iframe2 切換回 iframe1 可以使用父子切換,示例如下:

          Python 實現

          driver.switch_to.frame("iframe1")
          driver.switch_to.frame("iframe2")
          
          # 從 iframe2 切換到上一級 iframe1
          driver.switch_to.parent_frame()
          # 從 iframe1 切換到上一級 iframe,如果 iframe 已經是最上級,則保持不變
          driver.switch_to.parent_frame()

          Java 實現

          driver.switchTo().frame("iframe1");
          driver.switchTo().frame("iframe2");

          從 iframe2 切換回 iframe1 可以使用父子切換:

          # 從iframe2切換到上一級iframe1
          driver.switchTo().parent_frame()
          # 從iframe1切換到上一級iframe,如果iframe已經是最上級,則保持不變
          driver.switchTo().parent_frame()

          這個方法是 Selenium 提供的直接從子 frame 切換到父 frame,可以使用在嵌套的 frame 框架中。

          總結

          在瀏覽器中,存在一種名為 frame 的組件,通過常規的定位很難直接找到這個組件內的元素,因此需要進入到該 frame 組件里,并切換到相應的 frame 句柄,以便準確地定位和操作 frame 里面的元素。

          免費領取:測試資料+性能測試+接口測試+自動化測試+測試開發+測試用例+簡歷模板+測試文檔 - 公眾號 - 測試人社區


          者:Huup_We

          轉發鏈接:https://mp.weixin.qq.com/s/21ydrXuinCtYiJdsynsTrA


          主站蜘蛛池模板: 不卡一区二区在线| 高清一区二区在线观看| 精品人体无码一区二区三区| 日韩在线不卡免费视频一区| 日韩人妻不卡一区二区三区| 国精品无码一区二区三区左线| а天堂中文最新一区二区三区| 亚洲视频在线一区二区| 国产精品一区12p| 日本大香伊一区二区三区| 日韩毛片一区视频免费| 精品一区二区三区四区电影| 国产精品香蕉一区二区三区| 亚洲一区免费观看| 国产精品一级香蕉一区| 免费日本一区二区| 国产精品无码一区二区三区毛片 | 一区二区三区在线观看免费| 亚洲一区二区三区在线观看蜜桃| 天堂资源中文最新版在线一区 | 色婷婷AV一区二区三区浪潮| 国模无码视频一区二区三区| 日本一区二区三区爆乳| 天堂一区二区三区精品| 国产伦精品一区二区三区视频小说 | 国产韩国精品一区二区三区久久| 国产一区中文字幕| 老熟妇高潮一区二区三区| 久久久国产精品亚洲一区 | 午夜天堂一区人妻| 无码国产精品一区二区免费式芒果| 精品亚洲AV无码一区二区三区| 人妻体内射精一区二区| 99久久国产精品免费一区二区| 精品一区二区三区中文字幕| 亚洲国产精品第一区二区| 国内精品视频一区二区三区八戒 | 久久国产精品无码一区二区三区| 亚洲中文字幕久久久一区| 久久精品中文字幕一区| 美女视频一区三区网站在线观看|