1. 程式人生 > >說說 JavaScript 表單指令碼之富文字編輯功能

說說 JavaScript 表單指令碼之富文字編輯功能

富文字編輯,即所見即所得(What You See Is What You Get)。這個技術的本質是在頁面中嵌入一個包含空 HTML 頁面的 iframe。通過 designMode 屬性(設定為 on),這個頁面就可以被編輯,編輯物件是這個頁面的 <body> 元素的 HTML
程式碼。

iframe 中使用一個簡單的 HTML 頁面就可以作為內容:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Blank Page for Rich Text Editing</title
>
</head> <body> <script type="text/javascript"></script> </body> </html>

只有在頁面完全載入後才能設定 designMode 屬性,所以要使用 onload 事件來設定這一屬性:

<iframe name="richedit" style="height: 100px;width:100px;" src="blank.htm"></iframe>

<script type="text/javascript">

    EventUtil.addHandler(window, "load"
, function () { frames["richedit"].document.designMode = "on"; })
</script>

開啟後會看到一個類似文字框的可編輯區域。

1 使用 contenteditable 屬性

把 contenteditable 屬性設定給頁面中的任何一個元素後,使用者就可以立即編輯這個元素咯,是不是很方便呀:

<div class="editable" id="richedit" contenteditable></div>

在某個元素上設定 contenteditable 屬性,也可以開啟或關閉編輯模式:

var div = document.getElementById("richedit");
richedit.contenteditable = "true";

contenteditable 屬性有三個值:

說明
true 開啟
false 關閉
inherit 繼承自父元素

五大瀏覽器都支援 contenteditable 屬性。移動裝置的瀏覽器中,iOS 5+ 的 Safari 和 Android 3+ 的 Webkit 也支援這個屬性。

2 操作富文字

使用 document.execCommand() 可以與富文字編輯器進行互動。它接受 3 個引數:要執行的命令名稱、是否為當前命令提供使用者介面(為保證跨瀏覽器,通常設定為 false)以及命令引數。下面列出支援最多的命令:

命令 值(第 3 個引數) 說明
backcolor 顏色字串 設定文件的背景色。
bold null 將選擇的文字轉換為粗體。
copy null 將選擇的文字複製到剪貼簿。
createlink URL 字串 將選擇的文字轉換為連結,然後指向指定的 URL。
cut null 將選擇的文字剪貼到剪貼簿。
delete null 刪除選擇的文字。
fontname 字型名稱 將選擇的文字改為指定的字型。
fontsize 1 ~ 7 將選擇的文字改為指定的字型大小。
forecolor 顏色字串 將選擇的文字改為指定的顏色。
formatblock 需要包圍當前文字塊的 HTML 標籤 使用指定的 HTML 標籤來包裹指定的文字塊。
indent null 縮排文字。
inserthorizontalrule null 在游標處插入一個 <hr> 元素。
insertimage 影象的 URL 在游標處插入一個影象。
insertorderedlist null 在游標處插入一個<ol> 元素。
insertunorderedlist null 在游標處插入一個<ul> 元素。
insertparagraph null 在游標處插入一個<p> 元素。
italic null 將選擇的文字改為斜體。
justifycenter null 在游標處的文字塊居中對齊。
justifyleft null 在游標處的文字塊左對齊。
outdent null 減少縮排。
paste null 將剪貼簿中的內容貼上到選擇的文字。
removeformat null 移除包圍當前文字塊的 HTML 標籤,這是撤銷 formatblock 命令的操作。
selectall null 選中所有文字。
underline null 為選中的文字新增下劃線。
unlink null 移除文字連結,這是撤銷 createlink 命令的操作。

注意:與剪貼簿相關的命令在不同的瀏覽器中差別很大!Opera 沒有實現任何與剪貼簿相關的命令,Firefox 會在預設情況下禁止這些命令。Safari 和 Chrome 實現了 cut 和 copy,但沒有實現 paste。雖然不能使用 document.execCommand() 執行這些命令,但可以通過快捷鍵來實現同樣的功能。

可以使用這些命令來改變富文字區域的外觀:

 <form method="post" action="javascript:alert('Form submitted!')" id="myForm">
    <div id="divSimple">
        <input type="button" value="Bold">
        <input type="button" value="Italic">
        <input type="button" value="createLink">
        <input type="button" value="h1">
        <input type="button" value="enabled">
        <input type="button" value="state">
        <input type="button" value="commandValue">
        <input type="button" value="setBackground">
        <!--<input type="button" value="Underline">-->
        <!--<input type="button" value="Indent">-->
        <!--<input type="button" value="Outdent">-->
        <!--<input type="button" value="Copy">-->
        <!--<input type="button" value="Cut">-->
        <!--<input type="button" value="Paste">-->
    </div>
    <div id="richedit" style="height: 100px;width: 300px;border: dashed"
         contenteditable></div>

    <button type="sumbit">sumbit</button>
    <input type="hidden" id="comments">
</form>
 ```

 ```
 <script type="text/javascript">

    (function () {

        var simple = document.getElementById("divSimple");
        EventUtil.addHandler(simple, "click", function (event) {
            event = EventUtil.getEvent(event);
            var target = EventUtil.getTarget(event);

            if (target.type = "button") {
                switch (target.value) {
                    case "Bold"://粗體
//                        document.execCommand(target.value.toLowerCase(), false, null);
                        document.execCommand("bold", false, null);
                        break;
                    case "Italic"://斜體
                        document.execCommand("italic", false, null);
                        break;
                    case "createLink"://建立連結
                        document.execCommand("createlink", false, "http://www.163.com");
                        break;
                    case "h1"://格式化為 h1
                        document.execCommand("formatblock", false, "<h1>");
                        break;
                    case "enabled"://是否可以針對當前選擇的文字執行某個命令
                        console.log(document.queryCommandEnabled("bold"));
                        break;
                    case "state"://是否已將指定命令應用到了選擇的文字
                        console.log(document.queryCommandState("bold"));
                        break;
                    case "commandValue"://取得執行命令時傳入的值
                        console.log(document.queryCommandValue("fontsize"));
                        break;
                    case "setBackground"://新增黃色背景(富文字選區操作)
                        var selection = document.getSelection();

                        //取得選擇的文字
                        var selectedText = selection.toString();

                        //取得代表選區的範圍
                        var range = selection.getRangeAt(0);

                        //突出顯示已經選擇的文字
                        var span = document.createElement("span");
                        span.style.backgroundColor = "yellow";
                        range.surroundContents(span);
                        break;

                }
            }
        });


    })();
</script>

注意:雖然所有的瀏覽器都支援這些命令,但它們生成的 HTML 文字並不相同!比如執行 bold 命令後,IE 和 Opera 會使用 <strong> 標籤包圍文字,而 Safari 和 Chrome 使用的是 <b> 標籤,在 Firefox 中使用的是 <span> 標籤!

queryCommandEnabled() 方法是用來檢查某個命令是否適用於當前選中的文字,或者是否能在當前游標處執行該命令。它接受一個引數,即要檢測的命令。返回布林值:


var result = frames["richedit"].document.queryCommandEnabled("bold");

這個命令其實並不可靠,比如在 Firefox 中禁用剪下操作的情況下,這個命令仍會返回 false。

queryCommandState() 方法用於確定某個命令是否已經應用到所選中的文字:


var result = frames["richedit"].document.queryCommandState("bold");

那些富文字編輯器就是根據這個方法返回的值來更新粗體、斜體的按鈕狀態的。

queryCommandValue() 可以取得執行命令時傳入的值(就是 document.execCommand() 方法的第 3 個值):


var fontSize = frames["richedit"].document.queryCommandValue("fontsize");//7

# 3 富文字選區

使用 iframe 的 getSelection() 方法可以獲取實際選中的文字。它會返回當前選中文字的 Selection 物件。每個 Selection 物件都有這些屬性:

屬性名 說明
anchorNode 選區起點所在的節點。
anchorOffset 到達選區起點之前所跳過的 anchorNode 的字元數量。
focusNode 選區終點所在的節點。
isCollapsed 選區起點與終點是否重合。
rangeCount 選區中包含的 DOM 範圍的數量。

這些屬性其實沒有多少價值,我們再看看 Selection 物件所擁有的方法:

方法名 說明
addRange(range) 把指定的 DOM 範圍新增到選區中。
collpase(node, offset) 把選區摺疊到指定節點中相應偏移量位置。
collapseToEnd() 把選區摺疊到終點。
collapseToStart() 把選區摺疊到起點。
deleteFromDocument() 從文件中刪除選區中的文字,這與 執行 document.execCommand(“delete”, false, null) 命令的結果相同。
extend(node offset) 把 focusNode 和 focusOffset 移動到指定偏移量來擴充套件選區。
getRangeAt(index) 返回索引對應選區中的 DOM 範圍。
removeAllRanges() 從選區中移除所有 DOM 範圍,沒有了範圍,選區也會被移除。
removeRange(range) 從選區中移除指定的 DOM 範圍。
selectAllChildren(node) 清除選區,然後選擇指定節點的所有節點。
toString() 返回選區所包含的文字內容。

這些方法很實用,可以使用它們來管理選區:

var selection = document.getSelection();

//取得選擇的文字
var selectedText = selection.toString();

//取得代表選區的範圍
var range = selection.getRangeAt(0);

//突出顯示已經選擇的文字
var span = document.createElement("span");
span.style.backgroundColor = "yellow";
range.surroundContents(span);

上面這段程式碼會把被選擇的文字新增上黃色的背景:

上黃色的背景

4 表單和富文字

因為富文字編輯使用的是 iframe,所以它並不屬於表單。所以自然不會被自動提交給伺服器,因此需要手工處理。可以新增一個隱藏欄位,把它的值設定為從 iframe 中提取出的 富文字內容:

<input type="hidden" id="comments">
...
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "submit", function (event) {//把富文字域的值新增到表單
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);

    target.elements["comments"].value = document.getElementById("richedit").innerHTML;
    console.log(target.elements["comments"].value);
})