
简介这份文档围绕动易 SiteWeaver 6.8 后台编辑器在 IE9、IE10、IE11 下无法正常使用的问题展开面向仍需维护旧版站点后台的站长、前端与后台开发人员重点解决浏览器升级后编辑与浏览异常带来的维护困扰。压缩包内共 1 个 doc 文件大小约 21KB内容以问题说明、涉及文件定位和兼容修改要点为主便于对照现有程序快速排查。文档梳理了直接覆盖相关文件与手动调整后台编辑器脚本、文章管理及会员中心页面等两种处理路径并给出兼容标记的补充思路同时提示修改前做好备份对旧系统维护场景有较强参考价值。目前已有 937 人学习查看适合需要定位 SW 后台编辑器兼容问题、减少反复试错并保留一份可查依据的技术人员留存备用文档结构简明也便于旧项目交接和兼容性排查时快速翻阅。1. 一台只剩 IE 的机器编辑器打不开这件事到底卡在哪上个月帮朋友看一个内网后台情况很典型整层办公电脑统一跑 IE11登录进去点「发布文章」编辑器区域一片空白工具栏按钮点下去毫无反应换成 Chrome 反而正常。这套后台是若干年前用 ASP 写的 SW 6.8 建站系统编辑器是随系统带的老版本富文本组件问题既不在服务器也不在权限而是编辑器脚本里那段拿 UA 嗅探浏览器版本的老代码在 IE9、IE10、IE11 上直接走偏甚至抛异常初始化链条断在第一步。这份 53KB 的补丁包干的事很明确改三个 ASP 文件、补四行代码让后台编辑器和会员中心投稿编辑器在 IE9、IE10、IE11 下重新能用。适合两类人看还在维护这类老 ASP 站点、短期没法推倒重来的开发者以及想搞明白「UA 嗅探 → 文档模式 → 编辑器初始化」这条链路到底怎么断的、怎么接回去的人。2. 故障链路拆解一行正则如何让整个编辑器停摆2.1 版本嗅探那两行到底在做什么编辑器加载时会先建一个全局的BrowserInfo对象把浏览器判型和主次版本号塞进去后面所有分支判断——用哪套 DOM 操作、事件怎么绑、设计区怎么初始化——全靠这几个字段。老代码写得很直白// 老版本编辑器里的浏览器嗅探简化后 var BrowserInfo new Object(); BrowserInfo.IsIE (navigator.appName Microsoft Internet Explorer); BrowserInfo.MajorVer navigator.appVersion.match(/MSIE (.)/)[1]; BrowserInfo.MinorVer navigator.appVersion.match(/MSIE .\.(.)/)[1];两行正则各抓一个字符。第一行/MSIE (.)/抓MSIE后面紧跟的那一个字符第二行/MSIE .\.(.)/抓小数点后的那一个字符。在 IE6、IE7、IE8 时代版本号是个位数MSIE 8.0抓出来就是主版本 8、次版本 0逻辑完全成立。问题在于这个写法的前提是「版本号永远是个位数」而浏览器厂商显然不打算遵守这个约定。第二行更要命的地方是它没有做空值保护。String.prototype.match匹配失败时返回的是null而null[1]在 JS 里会直接抛TypeError: Cannot read property 1 of null。这不是「返回 undefined 然后走默认分支」那种温和失败是硬中断。2.2 IE10 被识别成 1.xIE11 干脆抛异常把三款浏览器的navigator.appVersion摊开看问题一目了然浏览器navigator.appVersion 片段旧正则匹配结果IE94.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)主 9 / 次 0正常IE104.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)主 1 / 次 0错IE115.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Geckonull抛异常IE10 的坑是隐性的/MSIE (.)/只吃一个字符MSIE 10.0里它抓到的是1于是主版本被判定为 1次版本判定为 0编辑器以为自己跑在 IE1 上后续所有版本分支全部走错工具栏绑不上命令表现出来就是「能看见界面但点了没反应」。IE11 的坑是显性的从 IE11 开始微软为了绕开当年铺天盖地的 UA 嗅探代码把 UA 里的MSIE字样彻底去掉换成Trident/7.0加rv:11.0末尾还挂了个like Gecko。于是所有基于MSIE的正则全部匹配失败match返回null紧接着[1]取值抛错。真正致命的是第三层老式页面里的脚本是同步顺序执行的同一个script块内任何一个顶层语句抛出未捕获异常这个块后面的代码一行都不会跑跨块的其他脚本如果依赖前面定义的全局变量也会连带失败。编辑器初始化函数没被调用设计区 iframe 没被创建工具栏的事件监听没挂上——最后呈现给用户的就是一块空白。很多人第一次遇到会以为是服务端 500 或者权限问题翻半天日志其实前端第一行就崩了。2.3 文档模式让 IE11 自己把 MSIE 交出来搞清楚了根因修复思路有两条。一条是把嗅探逻辑彻底重写不依赖MSIE字样另一条更省事——让 IE11 主动退回兼容状态把MSIE还回来。IE8 之后引入了「文档模式」documentMode的概念浏览器内核版本和渲染模式解耦同一个 IE11 可以用 IE7 的渲染规则跑页面。触发方式就是X-UA-Compatible响应头或 meta 声明。关键在于当页面被声明为IEEmulateIE7或者站点被加进兼容性视图列表时IE11 报告的navigator.userAgent会变回兼容形式里面重新带上MSIE 7.0Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko这一句是整个补丁能成立的物理基础。因为 UA 里MSIE回来了ua.match(/msie ([\d.])/)就能匹配到虽然拿到的是7.0而不是11.0但编辑器本来就需要老代码路径判成 7 恰恰是它想要的。所以补丁的两处改动是配套的、缺一不可JS 里改嗅探保证不抛异常ASP 里输出 meta 保证 UA 里有东西可嗅。只改一边IE11 下照样白板。顺带把页面结构也理一下后台文章编辑页Admin_Article.asp是外壳编辑器组件通过 iframe 或脚本引入挂进来。文档模式声明写在外壳页上覆盖整个文档树编辑器脚本拿到的navigator.userAgent就是外壳页那一份。所以 meta 必须写在承载编辑器的那一层页面上写到别的页面上去没用。3. 改动清单与目录结构三个 ASP 文件构成的最小补丁面3.1 站点骨架改动落在哪几个入口这类 ASP 建站系统的目录结构高度固定后台、会员中心、编辑器三块分开管改之前先把落点认清楚webroot/ ├── Editor.asp # 编辑器组件入口内嵌版本嗅探逻辑 ├── Admin/ │ ├── Admin_Index.asp # 后台框架首页左侧菜单 右侧内容区 │ └── Admin_Article.asp # 后台文章新增/编辑页编辑器在这里被加载 ├── User/ │ └── User_Article.asp # 会员中心投稿页前台用户侧的编辑器 └── Editor/ # 编辑器静态资源目录js/css/图片补丁只碰四个文件Editor.asp改 JS 嗅探和事件绑定、Admin_Article.asp、Admin_Index.asp加文档模式声明、User_Article.asp会员中心同款处理。编辑器静态资源目录一个字节都不用动这一点很重要——很多补丁包动辄替换整目录反而把自定义过的皮肤和工具栏配置一起覆盖掉了。需要留意的坑是Admin_Index.asp后台框架页本身不加载编辑器但它决定了整个后台框架的文档模式。有些老版本的后台用的是 frameset 或者 iframe 嵌套父框架的文档模式会影响子框架的初始化时序所以这个文件也要一起改。3.2 覆盖式与手改式两种落地方式的取舍补丁给了两条路整包覆盖或者手工改四行。这不是「哪个更好」的问题是「你的现场是什么样」的问题。维度覆盖式替换文件手改式编辑原文件耗时备份后几分钟完成逐文件查找替换约 20 分钟风险会覆盖掉历次二次开发的内容只动目标代码其余原样保留适用纯原版、从未改过后台做过模板定制、加过字段、改过权限逻辑回滚用备份文件原样覆盖回去需要自己记录改了哪几处一线的血泪经验是只要这个站被人动过一次就别用覆盖式。老 ASP 站点的后台文件里往往塞满了历年加的小功能——自定义字段、附件上传钩子、审核流程判断覆盖一下全没了而且因为没版本管理找都找不回来。我一般会先做两件事再动手把整个Admin目录和Editor.asp打个压缩包命名带上日期然后对目标文件做一次全文搜索确认要改的代码串在文件里出现的次数和预期一致。3.3 四处改动的语义对照把每一处改动的「原样 → 改成 → 为什么」列清楚改的时候照着对比盲抄代码靠谱得多文件位置/查找串改动内容作用Editor.aspBrowserInfo.MajorVer ...两行注释或删除换成 UA 整串匹配修复 IE10 版本号截断、IE11 抛异常Editor.aspelement.YUSERONCLICK两处按 IE 版本分流成onclick(event)修复 IE9 下工具栏命令不触发Admin_Article.aspResponse.Write meta ... charsetgb2312之后追加一行输出X-UA-Compatible让编辑页进入 IE7 文档模式Admin_Index.asp同上同上让后台框架页同样进入兼容模式User_Article.aspmeta http-equivContent-Type ... /之后追加一行静态 meta修复会员中心编辑器注意Admin_Article.asp和Admin_Index.asp里那行 Content-Type 是 ASP 用Response.Write拼出来输出的不是静态 HTML所以追加的 meta 也必须用Response.Write拼且要处理 ASP 里的双引号转义。User_Article.asp反过来是静态 HTML直接写 meta 标签就行。这两种写法混了就会报语法错。4. 逐文件落地四段代码的改法与验证4.1 Editor.asp替换版本嗅探顺带想清楚为什么能跑用记事本或任意支持 ANSI 编码的编辑器打开Editor.asp先全文搜索BrowserInfo.MajorVer。找到后把这两行注释掉行首加//或直接删除替换成下面这段// 原代码注释保留方便日后回溯 // BrowserInfo.MajorVer navigator.appVersion.match(/MSIE (.)/)[1] ; // BrowserInfo.MinorVer navigator.appVersion.match(/MSIE .\.(.)/)[1] ; // 新写法UA 转小写后整段匹配一次拿到完整版本串 var ua navigator.userAgent.toLowerCase(); BrowserInfo.MajorVer ua.match(/msie ([\d.])/)[1];参数说明[\d.]是贪婪匹配数字和小数点MSIE 7.0会整体捕获成7.0MSIE 10.0会捕获成10.0不再有只吃一个字符的问题。toLowerCase()是为了兼容某些浏览器把 UA 写成大写的情况虽然实际很少见但加上不亏。这里必须说清楚一个容易被误读的点这两行本身并没有解决 IE11。IE11 原生 UA 里没有msie字样ua.match(/msie ([\d.])/)返回的还是null下一行的[1]照样抛异常。它能跑通靠的是 4.3 里那个文档模式声明——页面进入 IE7 兼容模式后IE11 报告的 UA 变成... MSIE 7.0; Windows NT 6.1; Trident/7.0 ...正则匹配到7.0取到主版本 7编辑器走老代码路径一切正常。所以这两处改动是有依赖关系的改动顺序不能颠倒着测。如果只改 JS 不输出 meta在 IE11 下打开后台仍然白板而且因为异常位置换了一行报错信息看着像是新引入的 bug很容易让人怀疑人生。我一般会把 meta 先加上再改 JS这样每改一步都能看到进展。4.2 YUSERONCLICK两处一模一样的事件绑定改造继续在Editor.asp里搜索YUSERONCLICK。这是一个老式事件绑定的产物编辑器把要执行的命令串存进元素的自定义属性运行时用eval拼出来执行。老 IE 下拼的是anonymous()IE9 之后引擎行为变了这套写法不再触发表现出来就是工具栏按钮点下去没反应。这个查找串在文件里出现两次两处都要改。很多人只改第一处改完发现部分按钮能用了、部分还是死的回头查半天。改成if (navigator.appVersion.match(/MSIE (7|8|9|10|11|12)\./i) ! null) { // IE7~IE12改用 onclick(event)把事件对象透传进去 if (element.YUSERONCLICK) eval(element.YUSERONCLICK onclick(event)); } else { // 其他浏览器保持原逻辑 if (element.YUSERONCLICK) eval(element.YUSERONCLICK anonymous()); }参数说明/MSIE (7|8|9|10|11|12)\./i是捕获组加转义小数点匹配MSIE 7.到MSIE 12.这一段。注意它匹配的仍然是有MSIE字样的 UA所以这行在 IE11 原生模式下返回null会走到else分支——这又一次印证了文档模式是前置条件。onclick(event)里的event是当前作用域里的事件对象eval拼出来的表达式相当于调用元素的onclick(event)把事件参数带进去命令才能拿到执行上下文。如果嫌这个正则覆盖面不够可以换成/MSIE \d\./i效果一样且不用枚举版本号只是和原始补丁长得不一样对照排查时容易对不上。4.3 Admin_Article.asp 与 Admin_Index.aspASP 里拼一行 meta打开Admin/Admin_Article.asp搜索这一行Response.Write meta http-equivContent-Type contenttext/html; charsetgb2312 vbCrLf在它下面紧跟着插入一行 强制 IE9/10/11 进入 IE7 文档模式恢复 UA 中的 MSIE 标识 Response.Write meta http-equivX-UA-Compatible contentIEEmulateIE7 vbCrLf参数说明ASP 的Response.Write用双引号包裹字符串字符串内部的字面双引号要用两个双引号转义所以写成X-UA-Compatible最终浏览器收到的 HTML 是meta http-equivX-UA-Compatible contentIEEmulateIE7 。末尾那个空格不加也行加着是为了和原文件风格一致。vbCrLf是 VBScript 的换行常量保持输出可读。Admin_Index.asp做同样处理查找串和插入串完全一致。改完这两个文件后台的编辑页和框架页都会声明文档模式。有一个位置约束必须强调X-UA-Compatible在文档里的位置很挑IE 要求它出现在head开始之后、任何非 meta 元素之前实际实现是页面前 1024 字节内。补丁把它放在 Content-Type 那一行后面这两行都是 meta前一后一位置是合法的。但如果你的页面在 Content-Type 之前还有link relstylesheet或者一大段 HTML 注释这行就会被 IE 直接忽略而且不报任何错。这种情况在避坑一节还会再提。4.4 User_Article.asp会员中心侧的同款处理后台改完只是治了一半。会员中心前台用户投稿/评论用的是另一套页面User/User_Article.asp里面是静态 HTML不是 ASP 输出。搜索meta http-equivContent-Type contenttext/html; charsetgb2312 /在下面追加一行meta http-equivX-UA-Compatible contentIEEmulateIE7 /这里没有Response.Write和转义问题直接写标签。写完后 IE10/IE11 下会员中心的编辑器也能正常显示设计区和工具栏。两处都改是因为它们加载的是同一套编辑器组件只是承载页面不同——组件本身的行为一致页面声明的文档模式不一致结果就不一样。改完记得用编辑器保存时保持文件编码为 ANSI/GB2312。用 Windows 记事本另存很容易不小心存成 UTF-8ASP 页面一混编码中文标题和栏目名立刻变乱码而且因为乱码位置散落在各处排查起来比重装一遍还费时间。4.5 改完必做的三步验证第一步清缓存。IE 对页面和渲染模式的缓存很顽固改完文件不清缓存直接刷新看到的可能还是旧结果。关闭所有 IE 窗口清理临时文件或者干脆用 InPrivate 窗口开一次。第二步看文档模式。F12 打开开发者工具在「文档模式」那一栏确认显示的是7IE7 标准如果是Edge或者11说明 meta 没生效回去查 4.3 的位置问题。第三步看版本号。后台任意页面开控制台跑一句navigator.userAgent确认输出里带MSIE 7.0。如果带的是Trident/7.0; rv:11.0而没有 MSIE同样说明文档模式没切过去。三步都对再去点「发布文章」设计区应该能正常出现工具栏的加粗、插入图片、源码切换都能响应。IE9 和 IE10 上重复一遍这两款本来就是兼容模式的原生支持者一般不会有额外问题。5. 避坑与排查改完还是打不开的五种情况5.1 现象文档模式显示了 7但页面还是白板原因通常是改错了文件。这类系统常有虚拟目录或多套后台入口浏览器实际访问的Admin_Article.asp和你正在编辑的那个不是同一份。解决在浏览器地址栏确认当前 URL 路径对照磁盘目录找到真实文件或者在页面里临时加一句!-- patch-test --刷新看源码里有没有没有就是改错地方了。5.2 现象JS 改完控制台报Cannot read property 1 of null原因还是 UA 里没有msie说明文档模式没生效正则匹配返回null。解决先确认 4.3 的 meta 是否真的输出了——右键查看页面源代码搜X-UA-Compatible搜不到就是 ASP 那行没执行可能插在了% %块外面或者被条件分支跳过。搜到了但文档模式仍是 Edge检查它前面有没有非 meta 元素。5.3 现象编辑器出来了但工具栏按钮点了没反应原因只改了 4.1 的版本嗅探漏了 4.2 的两处YUSERONCLICK。解决全文搜索YUSERONCLICK确认出现次数为 2 且两处都改成了分支写法。这里有个容易骗过自己的地方只改第一处时部分按钮比如加粗、斜体恰好能工作插入图片、源码切换这类依赖事件对象的命令才失效看起来像「部分功能坏了」实际是改漏了。5.4 现象meta 加了位置也对还是被忽略原因是 HTTP 响应头里已经设置过X-UA-Compatible。IE 的优先级是 HTTP 头高于 meta头里写了IEedge页面里写IEEmulateIE7也白搭。解决F12 网络面板看响应头或者找 IIS 的 HTTP 响应头配置、站点根目录的web.config把已有的那条删掉或改成IEEmulateIE7。5.5 现象后台好了会员中心投稿页仍然不行原因是只改了Admin目录漏了User/User_Article.asp。这两处用的是同一套编辑器组件但不同的承载页面后台修好不代表前台修好。解决按 4.4 补上静态 meta清缓存重开。顺带建议在这个阶段做一次全站扫描把所有加载编辑器的页面列出来避免还有第三个、第四个入口没覆盖到。6. 二次开发把一次性补丁沉淀成可维护的兼容层补丁改完能跑但它本质上是一次「就地打补丁」——四行代码散落在四个文件里下次换台服务器、加个新后台入口又得重来一遍。如果这套系统还要继续维护一两年值得花半天把它做成兼容层。第一条路线是收敛文档模式声明。把Response.Write meta http-equivX-UA-Compatible contentIEEmulateIE7 vbCrLf抽成一个单独文件比如inc/ua_compat.asp在所有后台页面顶部!--#include fileinc/ua_compat.asp--。这样以后要调文档模式只改一处不用满目录搜字符串。第二条路线是把 JS 嗅探函数化彻底摆脱对文档模式的依赖。这是我在同类老系统上更推荐的做法因为它让编辑器在 IE11 原生模式下也能跑不必为了兼容放弃整站的现代渲染能力// 不依赖文档模式的版本判定先找 MSIE再找 Trident/rv function detectIEVersion(ua) { ua (ua || navigator.userAgent).toLowerCase(); var m ua.match(/(?:msie\s|trident\/.*?rv:)([\d.])/); return m ? parseInt(m[1], 10) : 0; // 非 IE 返回 0 } var BrowserInfo {}; BrowserInfo.MajorVer detectIEVersion(); BrowserInfo.IsIE BrowserInfo.MajorVer 0;参数说明(?:msie\s|trident\/.*?rv:)是非捕获分组两种模式二选一——老版本命中msieIE11 命中trident/...rv:.*?是非贪婪匹配保证从Trident/走到最近的rv:就停parseInt把11.0转成11方便后面做数值比较。改成这个版本之后YUSERONCLICK那处的判断也可以从枚举版本号换成BrowserInfo.MajorVer 7。选择哪条路线取决于这套站还要活多久场景推荐路线理由只求今天能发文不做别的改动就地打补丁 文档模式改动面最小风险可控还要继续加功能、改模板收敛 include 函数化嗅探一次投入后续不再重复踩坑计划迁移到新框架只打补丁不做深度改造迁移成本已经摆在那别在旧船上雕花验证方法也很直接函数化改造完之后把X-UA-Compatible临时注释掉用 IE11 原生模式打开后台控制台跑detectIEVersion()应该返回11编辑器照样能用——这就说明兼容层真的立住了而不是靠文档模式兜着。有个细节我吃过亏YUSERONCLICK那两处如果只换成函数判定而没保留else分支的anonymous()非 IE 浏览器会直接不绑定事件Chrome 下工具栏全哑。改这类分支逻辑时我现在的习惯是先把两个分支都打上console.log跑一遍确认走了哪条再把日志删掉。从那以后每次动这种「一半 IE 一半其他」的分支判断我都强制在 Chrome 和 IE11 各点一遍所有工具栏按钮再收工省下的返工时间远比验证花的多。希望帮到你。本文还有配套的精品资源点击获取