
先搞懂FCKEditor的“脾气”:为什么取值总不对?
要解决取值问题,得先明白FCKEditor的“底层逻辑”——它是用iframe实现的富文本编辑区域。你在页面上写的,加载后会被FCKEditor替换成一个iframe,真正的编辑内容存在iframe的
里,而原来的textarea会被隐藏起来。我之前犯过一个傻:直接用
document.getElementById('editor').value
拿值,结果发现不管怎么编辑,拿到的都是初始内容——后来才知道,FCKEditor不会实时同步iframe的内容到textarea,所以必须用它提供的API才能拿到最新内容。
那正确的取值方法是什么?我 了三个常用场景,对应不同的API:
GetHTML()
方法。比如你点保存按钮时,要拿到编辑器里带格式的内容,就写:var editor = FCKeditorAPI.GetInstance('editor'); var content = editor.GetHTML();
。但要注意,必须等编辑器加载完成再调用——我朋友之前就是没等加载完成,直接绑定点击事件,结果有时候能拿到值,有时候拿不到,不稳定。怎么判断加载完成?可以用OnComplete
事件,比如:FCKeditorAPI.GetInstance('editor').OnComplete = function() {
document.getElementById('saveBtn').onclick = function() {
var editor = FCKeditorAPI.GetInstance('editor');
var content = editor.GetHTML();
console.log(content); // 这时候拿到的就是最新内容
};
};
GetText()
方法。比如你要做“内容预览”,不需要格式,就写editor.GetText()
——它会自动去掉所有HTML标签,只留文字。我之前做过一个“摘要生成”功能,就是用这个方法拿到纯文本,再截取前200字,用户反馈比直接截取HTML内容更准确。GetXHTML()
方法。如果你的项目要求输出严格的XHTML(比如符合XML规范),可以用这个方法,它会把
改成
,![JavaScript FCKEditor编辑器取值与赋值实现代码|详细教程及完整示例 二]()
加闭合标签。我之前帮一个做电子书的项目改内容导出功能时,就用了这个方法,导出的内容能完美兼容他们的XML解析器。还有个容易踩的坑:多编辑器实例。如果页面上有多个FCKEditor,一定要用GetInstance('编辑器ID')
指定具体的实例,别搞混了。我之前帮一个CMS系统改BUG时,就遇到过“点第一个编辑器的保存,拿到第二个编辑器内容”的情况——就是因为没传对ID,用了FCKeditorAPI.GetInstance()
(没传ID),结果默认取了第一个实例。后来我让他把每个编辑器的ID都写清楚,比如FCKeditorAPI.GetInstance('editor1')
和FCKeditorAPI.GetInstance('editor2')
,问题立刻就解决了。
赋值别踩坑:怎么让内容“听话”显示在编辑器里?
赋值比取值更讲究“时机”——我之前做过一个“插入模板”的需求:点击按钮把预设的HTML内容放到编辑器里,一开始直接调用SetHTML()
,结果编辑器没反应,以为是API错了,查了官方文档才发现,得等iframe的内容加载完成。FCKEditor的官方文档里明确提到:“所有对编辑区域的操作,都要等iframe的document
对象准备好后再执行”,这句话我记到现在,帮我避了不少坑。
编辑器加载时,会先创建iframe,再加载iframe里的内容(比如样式、脚本),这时候如果直接调用SetHTML()
,iframe还没准备好,内容肯定插不进去。怎么判断?可以用EditorDocument.readyState
,比如:
var editor = FCKeditorAPI.GetInstance('editor');
// 检查iframe的文档是否加载完成
if (editor.EditorDocument.readyState === 'complete') {
editor.SetHTML('
这是模板内容
');
} else {
// 没加载完就等它加载完
editor.EditorDocument.onreadystatechange = function() {
if (editor.EditorDocument.readyState === 'complete') {
editor.SetHTML('
这是模板内容
');
}
};
}
我朋友之前就是没做这个判断,直接调用SetHTML()
,结果有时候能插入,有时候插不进去,调试了半天才找到问题。现在他再做赋值操作,都会先加这个判断,再也没出现过“内容不显示”的情况。
如果你的编辑器被隐藏过(比如放在 tabs 里),再显示出来时赋值,可能会遇到“内容不更新”的情况——这是因为iframe的document
对象被销毁过,得重新获取实例。我之前做过一个“多标签编辑”功能,切换标签时,编辑器会被隐藏再显示,这时候赋值要先重新获取实例:var editor = FCKeditorAPI.GetInstance('editor');
,再调用SetHTML()
,不然会报错“editor is undefined”。比如我写的切换标签后的赋值逻辑:
document.getElementById('tab2').onclick = function() {
// 显示编辑器所在的tab
document.getElementById('editorTab').style.display = 'block';
// 重新获取编辑器实例
var editor = FCKeditorAPI.GetInstance('editor');
// 赋值
editor.SetHTML('
切换到tab2的内容
');
};
这样处理后,不管切换多少次标签,赋值都能正常显示。
FCKEditor有个“内容过滤”功能,默认会过滤掉一些危险标签(比如、
),如果你赋值的内容里有这些标签,可能会被过滤掉。比如我之前想插入一个
标签的视频,结果调用
SetHTML()
后,内容变成了空——后来查了配置文件fckconfig.js
,发现FCKConfig.AllowedContent
默认是false
,会过滤掉未知标签。
解决方法有两个:要么在fckconfig.js
里添加允许的标签(比如FCKConfig.ExtraAllowedContent = 'embed[src|type|width|height]';
),要么临时关闭过滤(不推荐,有安全风险):editor.SetHTML('', true);
——第二个参数true
表示“不过滤内容”。但要注意,关闭过滤会有XSS风险,我 你只在信任的内容(比如后台管理员插入的模板)里用,用户输入的内容一定要保留过滤——我之前帮一个电商项目做商品描述编辑时,就遇到过用户尝试插入标签偷取cookie的情况,幸好过滤规则帮我挡住了。
最后给你一个“避坑检查表”,是我平时调试用的,照着查肯定能解决90%的问题:
问题现象 | 可能原因 | 解决方法 |
---|---|---|
取值拿到旧内容 | 直接用textarea的值,没调用API | 改用GetHTML()/GetText() |
赋值没反应 | 没等编辑器加载完成 | 用OnComplete事件或检查readyState |
内容被过滤 | 过滤规则限制 | 修改fckconfig.js添加允许的标签 |
多编辑器实例混乱 | 没传对编辑器ID | 用GetInstance('具体ID')指定实例 |
以上就是我亲测有效的方法,你可以照着试——比如先检查调用时机,再用对应的API,要是遇到问题,欢迎留言告诉我你的情况,我帮你看看。对了,要是你用的是FCKEditor 3.x版本(也就是CKEditor的前身),API可能有点不一样,比如GetInstance
改成了instances
,记得查对应版本的文档哦!
我之前帮一个做教育网站的朋友调过这个问题——他想在FCKEditor里插入课程的embed视频代码,结果点保存按钮后,辛辛苦苦粘的视频标签直接没了,编辑器里只剩下“课程视频”几个字。我帮他查的时候才发现,FCKEditor这东西默认带了个“安全过滤”的脾气,就像个守门的保安,怕有人往编辑器里塞恶意代码(比如script标签弹广告,或者iframe嵌套钓鱼页面),所以会自动把它不认识的、不在允许列表里的标签“拦”下来。像朋友用的embed标签,默认就不在FCKEditor的“白名单”里,自然就被过滤掉了。
后来我给了他两个解决办法。第一个是改配置文件——找到项目里的fckconfig.js,里面有个叫ExtraAllowedContent的配置项,原本可能是空的或者注释掉的,我让他加了一句FCKConfig.ExtraAllowedContent = 'embed[src|type|width|height]'。这句话的意思是告诉FCKEditor:“embed标签是安全的,允许它存在,而且要保留src(视频地址)、type(类型)、width(宽度)、height(高度)这些属性”。改完保存,重启服务再试,视频代码果然能正常显示在编辑器里了。第二个办法是临时关闭过滤,但我反复跟他强调“只能偶尔用”——比如有时候后台管理员要插个自己做的模板内容,确定没有危险,可以在调用SetHTML()的时候加个true参数,比如editor.SetHTML('要插入的内容', true),这样FCKEditor就不会过滤这段内容了。但普通用户的输入千万不能这么搞,不然万一有人钻空子插个script标签,偷用户的cookie或者跳转到钓鱼网站,麻烦就大了。
还有一次我自己做项目时,想插个带样式的div标签,结果编辑器自动把div改成了p标签——后来才明白,FCKEditor不仅过滤标签,还会“纠正”它认为不规范的结构。那回我除了在ExtraAllowedContent里加div标签,还得加上它的class属性,比如FCKConfig.ExtraAllowedContent += 'div[class]',这样编辑器才会保留div和它的样式类。其实 FCKEditor的过滤规则就是个“明码标价”的清单,你要让它允许什么,就得把什么写进配置里,不然它就默认“拒之门外”。
直接用textarea的value为什么拿不到编辑器的最新内容?
因为FCKEditor会将页面上的textarea替换为iframe,真正的编辑内容存放在iframe的body中,而原textarea仅保留初始内容,不会实时同步iframe的修改。 必须通过FCKEditor提供的API(如GetHTML())才能获取最新内容。
调用GetHTML()时为什么有时候拿到空值或旧内容?
通常是因为调用时机不对——编辑器未完全加载就执行了API。FCKEditor加载时会先创建iframe并加载内部内容,需等加载完成(可通过OnComplete事件监听,或检查EditorDocument.readyState是否为complete)再调用GetHTML(),才能确保拿到最新内容。
赋值的内容为什么会被FCKEditor过滤掉?
FCKEditor默认开启内容过滤,会过滤掉、等危险标签或未明确允许的标签。解决方法是在fckconfig.js中添加允许的标签(如FCKConfig.ExtraAllowedContent = 'embed[src|type|width|height]'),或临时关闭过滤(调用SetHTML()时第二个参数传true,但需注意这会带来安全风险,仅适合信任的内容)。
页面有多个FCKEditor时,怎么准确获取某个编辑器的内容?
需通过编辑器的ID指定实例,使用FCKeditorAPI.GetInstance('具体编辑器ID')获取对应实例,再调用GetHTML()等方法。例如页面有id为editor1和editor2的两个编辑器,获取editor1内容需写var editor = FCKeditorAPI.GetInstance('editor1'); var content = editor.GetHTML();,避免实例混淆。
FCKEditor 3.x(CKEditor前身)的API和2.x有区别吗?
是的,FCKEditor 3.x更名为CKEditor后,API有部分调整。例如2.x的FCKeditorAPI.GetInstance()在3.x中改为CKEDITOR.instances;2.x的GetHTML()在3.x中改为getData()。如果使用3.x版本,需参考对应版本的官方文档调整API调用方式。