此時此刻,我正在用博客園推薦的TinyMCE編輯器寫這個博客,突然想起最近在項目中使用百度ueditor編輯器中的一些經歷.所以記錄在此,與大家分享.
不得不說,百度ueditor是一款很好的在線編輯器,為開發者提供了諸多便利,你甚至可以用它來把word文檔的內容按照一定的格式轉換成html代碼,然后再放進自己的項目中.
1.我們的項目中,用戶在注冊時有可能需要查看用戶協議和隱私協議,而我們的文案是將這兩個協議的內容放在word文檔中,作為苦逼的開發人員,你需要把這些文字展示在html頁面上,並且保持一定的樣式,例如首行縮進,行距等等;
這里有兩個解決方案:
第一種------word文檔可以直接轉換成html.不錯,是有這個功能,但是經過本人親測,2010版本的並不好用,但是word2003還不錯.
第二種------我當時采用的方法就是利用word與notepad++協作調好文檔的格式,再將調好格式的文檔內容拷貝到ueditor編輯器.生成html代碼,然后C V大法,扔進需要展示的html頁面,在瀏覽器預覽進行微調就可以了.至於怎么生成html代碼,你可以看到博客園TinyMCE編輯器的工具欄處,有一個寫有html的按鈕.ueditor也如此,點擊即可生成html代碼,
這兩種方法,請大家自行去比較哪種方便,哪種適合你.....
2.該說說今天這篇博客的主題了,那就是在使用ueditor時,實例化編輯器遇到的問題.
來到百度ueditor官網,下載一個你需要的版本(java,php等),頁面頭部引入如下標簽,
<script type="text/javascript" charset="utf-8" src="ueditor.config.js"></script>
<script type="text/javascript" charset="utf-8" src="ueditor.all.js"> </script>//這里為了方便看源碼,就不引用min.js了
<script type="text/javascript" charset="utf-8" src="lang/zh-cn/zh-cn.js"></script>
然后在html body標簽里面寫下如下代碼,你的ueditor應該就實例化成功了(我的頁面上有至少2個ueditor編輯器,先將它定義為編輯器頁面)
<body>
<script id="editor" type="text/plain" style="width:1024px;height:500px;"></script>
<script id="editor1" type="text/plain" style="width:1024px;height:500px;"></script>
<script>
var editor=UE.getEditor('')
var editor1=UE.getEditor('')
</script>
</body>
隨后,當我在第一次進入該頁面時,采用編輯器內置的方法setContent,給編輯器設置初始值(成功了):
editor.ready(function(){//監聽編輯器實例化完成的事件
console.log('編輯器1實例化完成')
editor.setContent('嘿嘿')
})
editor.ready(function(){
console.log('編輯器2實例化完成')
editor1.setContent('哈哈')
})
但是當我點擊瀏覽器的后退鍵返回上一個頁面(或者是點擊頁面上自己設置的后退按鈕返回上一個頁面)后,再一次進入到編輯器頁面,同樣調用
editor.setContent('嘿嘿')
editor1.setContent('哈哈')
的方法,瀏覽器控制台就報錯了 Cannot set property 'innerHTML' of null .意思就是需要賦值的對象是null(但為什么沒有報undefined呢?答案接下來分析)
而且奇葩的是,editor編輯器內容賦值成功,但是editor1賦值失敗.
思前想后,還是去看看ueditor的源碼吧.
UE.getEditor = function (id, opt) {
var editor = instances[id];
if (!editor) {
editor = instances[id] = new UE.ui.Editor(opt);
editor.render(id);
}
return editor;
};
源碼里的instances是一個初始化的空對象
代碼的意思就是:先去頁面找是否存在已經實例化的編輯器對象,如果沒有,就新生成一個編輯器.否則直接將頁面上找到的那個編輯器給返回.再聯想到剛才的報錯Cannot set property 'innerHTML' of null(而不是undefined,而且控制台也沒有輸出編輯器2實例化完成),那么真相只有一個! 那就是當你在一次來到編輯器頁面時,編輯器早已經存在,都已經存在的編輯器,自然不會觸發ready事件,所以自然不能觸發卸載ready事件里的setContent事件了.
好奇的小伙伴一定會想到,既然編輯器已經存在了,那么我們把setContent函數調到ready事件外,不就行了嗎!!!! 然而,並沒有任何luan用.....(設置setTimeout也不行)
按照我的猜想,此時當你第二次或者第三第四....次進入編輯器頁面,雖然頁面上存在這第一次你進入該頁面時的那個實例化好的編輯器,但是現在的它,功能並不完整了,你可以理解成汽車沒了發動機,殘疾了哎.
好了,找到了問題的根本,那么我們就來解決問題吧,方法也有兩個:
1.我的頁面既然有返回的按鈕,那么我只需要在每次點擊返回的時候,將頁面上的ueditor對象銷毀了,這樣一來,下次再進入到此頁面,就會重新實例化一個功能健全的ueditor了,
2.上面的解決辦法是從表象上去組織可能錯誤的發生,可以說是治標不治本,因為一些用戶的操作習慣是直接點擊瀏覽器的后退按鈕回到上一個頁面,下次進入到編輯器頁面,同樣會遇到之前的問題.當然大家也可以利用js動態去判斷瀏覽器的地址,從而決定應該何時銷毀編輯器對象,相信這個方法也是可以的.
不過我想說的是,我們就來點簡單粗暴的方法吧,ok,再回到ueditor源碼
UE.getEditor = function (id, opt) {
var editor = instances[id];
if (!editor) {
editor = instances[id] = new UE.ui.Editor(opt);
editor.render(id);
}
return editor;
};
我們可以跳過上面代碼的判斷,每一次直接根據js傳來的id,生成一個全新的ueditor對象.所以上述代碼可以改成:
UE.getEditor = function (id, opt) {
UE.delEditor(id);
var editor = new UE.ui.Editor(opt);
editor.render(id);
return editor;
};
最后附上銷毀ueditor的一個方法:(UE.delEditor('editor'))
UE.delEditor = function (id) {
var editor;
if (editor = instances[id]) {
editor.key && editor.destroy();
delete instances[id]
}
};
最后與大家共勉一句話:每當你擼代碼累了的時候,想想你上次解決困擾已久的bug的那種快感吧~