zoukankan      html  css  js  c++  java
  • 第14章 跨浏览器开发技巧

    1. 跨浏览器注意事项

    • 在选择兼容哪些浏览器时要考虑:
      • 目标受众的期望和需要(由项目确定)
      • 浏览器的市场份额
      • 浏览器支持所需的工作量

    不应以牺牲质量赢取覆盖率

    2. 五大开发问题

    2.1 浏览器的bug和差异

    • 代码必须完全符合浏览器提供的特性。
    • 这需要完整的测试工具,足以覆盖代码和常用的和不常用的用例

    2.2 浏览器的bug修复

    • 为解决浏览器当前bug使用特殊技巧,将来浏览器发布新版本修复了bug,就可能会出现问题
    • 面对浏览器的不一致性,通常需要(通过用户代理字符串)检测当前浏览器的名字
    • 在确定某一功能是否时潜在的错误时,使用规范进行验证

    2.3 外部代码和标记

    • 任何可重用的代码必须与围绕它的代码共存
    • 我们的代码不仅必须能够经受得住可能写的很糟糕的外部代码,还必须得克服环境对代码的不利影响

    实现代码健壮性的策略

    • 代码封装
      • 封装是指代码(如同)放在容器里,从广义上讲,是一种限制访问其他对象组件的语言机制
      • 尽可能少地使用全局变量,最好仅限一个
      • 为了保证代码的封装,需要避免其他操作,如修改已经存在的变量、函数原型甚至DOM元素
    • 模范代码
      • 当我们的代码与不可控的代码同时运行是,为了安全,需要假设最糟糕的情况
    • 应对ID滥用(贪婪ID问题)
      • 大部分浏览器具有一些反特性,这些特性使得原始元素与添加在元素上的id或name属性产生关联,当id或name属性与已有的属性产生冲突时,就会出现意外
      • 这是为了兼容过去的浏览器的处理方法,老式浏览器不具备获取DOM元素的方法
      • 要避免编写有可能与标准属性发生冲突的过于简单的id和name属性
      • 开发过程中尤其要避免submit值,以免出现bug
    <form id="form" action="/conceal">
        <input type="text" id="action">
        <input type="submit" id="submit">
    </form>
    <script>
        // 预期返回form标签的action属性,返回的却是input标签对象
        console.log(document.getElementById("form").action);
        // <input type="text" id="action">
        document.getElementById("form").submit();
        // Uncaught TypeError: document.getElementById(...).submit is not a function
    
        // 原因:浏览器将<form>元素内所有input标签都作为表单form的属性
        // 添加到form属性的名称是input元素的id或name属性
        // 当form本身的属性与input元素的id或name属性冲突时
        // form本身的属性就被input元素的id或name属性替换了
        // from.submit属性也发生了同样的情况
    </script>
    
    • 样式和脚本的加载顺序
      • 将外部样式表单防止在外部脚本文件之前,确保CSS规则在代码执行时已经可用

    2.4 浏览器的回归

    • 因浏览器的bug或不向后兼容的API发生变化导致代码不可预期地中断了,即过去使用的特性不再运行了
    • 预期的变化
      • 一些API发生的可预见性的变化,可以提前检测并处理(使用if判断标准API和专有API是否有效)
      • 面对不可预期的变化,最佳实践时在浏览器发行的版本中模拟测试,以快速发现问题

    2.4 浏览器缺失的功能

    3. 实现策略

    3.1 安全的跨浏览器修复方法

    • 安全的跨浏览器修复方法有两个重要的特点:
      • 在其他浏览器上没有副作用
      • 不使用浏览器或特性检查
    // ignore negative width and height values(来之jQuery)
    if ((key == "width" || key == "height") && parseFloat(value) < 0) value = undefined;
    // 将width或height值设置为负数时,在IE某些版本会报错,在其他版本或其他浏览器会被忽略
    // 这行代码会被大多数浏览器无任何影响,只对抛出错误的IE浏览器产生作用
    
    // 代码来自jQuery
    // input元素的type属性本身作为DOM的一部分,在IE浏览器内部是不允许修改的,修改会抛出异常
    // jQuery给出中间方案,所有浏览器上都不允许修改input的type属性,并抛出统一的异常信息
    if (name == "type" && elem.nodeName.toLowCase() == "input" && elem.parentNode) throw "type attribute can't be changed"; 
    // jQuery团队认为:一致的API、一致的行为,比开发跨浏览器代码更重要
    

    3.2 特性检测和垫片(polyfill)

    • 检测某一对象或对象属性是否存在,如果存在,则假设提供了内置方法
    • 通常,特性检测用于在多种API中做出选择,这些API提供相同或相识的功能
    • 对于浏览器缺失的特性,通常使用垫片(polyfill)
    • 垫片是浏览器备用模式,即如果浏览器不支持某个特定的功能,就提供自己的实现
    // 如果浏览器不支持find方法(ES6新增)
    // 以下是MDN提供的垫片
    if (!Array.prototype.find) {    // 特征检测
        // 定义find的实现
        Array.prototype.find = function(predicate) {
            if (this == null) {
                throw new TypeError("find called on null or undefined");
            }
            if (typeof predicate !== "function") {
                throw new TypeError("predicate must be a function");
            }
            var list = Object(this);
            // 确保length是非负整数
            // >>> 是补零右移运算符,将第一个操作数向右移动指定的位数,丢弃多余的部分
            var length = list.length >>> 0;
            var thisArg = arguments[1];
            var value;
    
            // 查找数组中满足指定条件的第一个元素
            for (var i = 0; i < length; i++) {
                value = list[i];
                if (predicate.call(thisArg, value, i, list)) {
                    return value;
                }
            }
            return undefined;
        }
    }
    
    • 如果特征检测不通过可以:
      • 进一步检测,找出可以使用的JS提供一个简版体验
      • 完全不使用JS,回到不用脚本的HTML页面
      • 将用户重定向到一个普通版网站

    3.3 不可测试的浏览器问题

    • 绑定事件处理器
      • 浏览器中,无法以编程的方式确定一个事件处理器是否被绑定,我们无法删除一个元素上绑定的所有事件处理器,除非我们维护所有创建的事件处理器的引用
    • 事件触发
      • 浏览器中,无法检测事件是否触发,可以确定浏览器是否支持事件绑定,但不可能知道浏览器是否会触发一个事件,在几个地方会引起问题:
        • 如果在页面加载完成后,会动态加载脚本,脚本试图将一个监听器绑定到等待窗口加载,而事实上,这个事件已经发生了,要执行的代码可能永远处于等待状态
        • 脚本希望使用自定义事件代替浏览器提供的事件,只有在实践中才能知道事件是否会被触发,事先无法确认
    • 浏览器崩溃
      • 在老版本的safari中使用Unicode字符创建正则表达式会造成浏览器崩溃
    • 不一致的API
    • API性能
      • 某些API在有的浏览器运行快,在有的浏览器上运行慢

    4. 减少假设

    • 编写跨浏览器、可重用的代码是一场关于假设的战役,要通过合理的检测和程序编写,减少代码中的假设
  • 相关阅读:
    数组的学习(一)
    Servlet是线程安全吗?
    MySql用户管理:添加用户、授权、删除用户
    泛型(二)
    泛型(一)
    Spring MVC
    spring框架
    mybatis基础
    Hibernate 基础
    Java局部类
  • 原文地址:https://www.cnblogs.com/hycstar/p/14059024.html
Copyright © 2011-2022 走看看