此时此刻,我正在用博客园推荐的TinyMCE编辑器写这个博客,忽然想起最近在项目中使用百度ueditor编辑器中的一些经历.因此记录在此,与你们分享.javascript
不得不说,百度ueditor是一款很好的在线编辑器,为开发者提供了诸多便利,你甚至能够用它来把word文档的内容按照必定的格式转换成html代码,而后再放进本身的项目中.php
1.咱们的项目中,用户在注册时有可能须要查看用户协议和隐私协议,而咱们的文案是将这两个协议的内容放在word文档中,做为苦逼的开发人员,你须要把这些文字展现在html页面上,而且保持必定的样式,例如首行缩进,行距等等;html
这里有两个解决方案:java
第一种------word文档能够直接转换成html.不错,是有这个功能,可是通过本人亲测,2010版本的并很差用,可是word2003还不错.浏览器
第二种------我当时采用的方法就是利用word与notepad++协做调好文档的格式,再将调好格式的文档内容拷贝到ueditor编辑器.生成html代码,而后C V大法,扔进须要展现的html页面,在浏览器预览进行微调就能够了.至于怎么生成html代码,你能够看到博客园TinyMCE编辑器的工具栏处,有一个写有html的按钮.ueditor也如此,点击便可生成html代码,编辑器
这两种方法,请你们自行去比较哪一种方便,哪一种适合你.....函数
2.该说说今天这篇博客的主题了,那就是在使用ueditor时,实例化编辑器遇到的问题.工具
来到百度ueditor官网,下载一个你须要的版本(java,php等),页面头部引入以下标签,ui
<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>lua
而后在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的那种快感吧~