在移动设备中忽略条件依赖

Posted

技术标签:

【中文标题】在移动设备中忽略条件依赖【英文标题】:Conditional dependency ignored in mobile 【发布时间】:2015-02-26 16:41:10 【问题描述】:

在构建网站的过程中,我们遇到了 VideoJS 和 Angular 之间的冲突,因此当 VideoJS 库存在时,Angular 模块不会在 ios7 中加载。这是一种极端情况,页面内容比外围视频重要得多,所以我们选择只为我们的移动用户 nix VideoJS 并使用图像后备。

现在,考虑一下来自 requirejs 模块的相关代码摘录:

log("checkpoint 1");

var videojs, $ = require('jquery');

if($(".home").length && $(window).outerWidth() > 768)
    log("checkpoint 2a");
    videojs = require('videojs');
    log("checkpoint 2b");

    // video init code here


log("checkpoint 3");

在任何移动设备中,日志都会返回:

> checkpoint 1
> checkpoint 3

这表明循环没有像预期的那样在移动设备中被渗透。然而,与此相反,videojs 库仍在加载中——这违背了有条件地包含它的整个目的。

我们已经确认这是唯一包含 videojs 库的地方,因为当 videojs = require('videojs'); 被注释掉时问题就消失了 - 该库没有出现在资源列表中,并且页面正常呈现。

我们只是在设置条件依赖时很差吗?是否有其他方法可以执行此操作,或者我们是否牢牢卡在 Require 的已知限制中?

【问题讨论】:

【参考方案1】:
videojs = require('videojs')

我敢打赌,这是源代码(非编译文件)中的一行,然后您使用 browserify(或发布应用程序之前的类似内容)进行编译。

当然,问题是您编译的文件总是需要 videojs(除非该行被注释掉),因为您的条件基于仅在运行时可用的行列式,而不是编译时。

所以,回答你的问题:

我们只是设置条件依赖关系不好?

是的。

可能有很多方法可以做到这一点,但我想到的一种是将 videojs 库作为单独的资产提供服务。您将使用(呃)用户代理解析来确定设备是否正在运行 iOS7 类似于以下内容(php 示例):

<?php if(!is_ios7())  //pseudo code - UA parsing in here. ?>
 <script src="/path/to/videojs"></script>
<?php  ?>

然后在您的主 js 文件中,您可以检测是否存在 videojs 全局变量,然后在需要时使用它。

【讨论】:

【参考方案2】:

对于生产和测试 ENV 以及移动/桌面版本使用可以使用这个加载器:(来自这个 git hub 项目https://github.com/BoilerplateMVC/Marionette-Require-Boilerplate/blob/master/public/index.html

    // Mobile/Desktop Detection script
            (function(ua, w, d, undefined) 
                // App Environment
                // ---------------
                //  Tip: Set to true to turn on "production" mode
                var production = true,
                        filesToLoad,
                //BoilerplateMVC Helper Methods
                        boilerplateMVC = 
                            loadCSS: function(url, callback) 
                                var link = d.createElement("link");
                                link.type = "text/css";
                                link.rel = "stylesheet";
                                link.href = url;
                                d.getElementsByTagName("head")[0].appendChild(link);
                                if(callback) 
                                    callback();
                                
                            ,
                            loadJS: function(file, callback) 
                                var script = d.createElement("script");
                                script.type = "text/javascript";
                                if (script.readyState)   // IE
                                    script.onreadystatechange = function() 
                                        if (script.readyState == "loaded"
 || script.readyState == "complete") 
                                            script.onreadystatechange = null;
                                            callback();
                                        
                                    ;
                                 else   // Other Browsers
                                    script.onload = function() 
                                        callback();
                                    ;
                                
                                if(((typeof file).toLowerCase()) === "object"
 && file["data-main"] !== undefined) 
                                    script.setAttribute("data-main", 
file["data-main"]);
                                    script.async = true;
                                    script.src = file.src;
                                 else 
                                    script.src = file;
                                
                                d.getElementsByTagName("head")[0].appendChild(script);
                            ,
                            loadFiles: function(production, obj, callback) 
                                var self = this;
                                if(production) 
                                    // Loads the production CSS file(s)
                                    self.loadCSS(obj["prod-css"], function() 
                                        // If there are production JavaScript files to load
                                        if(obj["prod-js"]) 
                                            // Loads the correct initialization file (which includes Almond.js)
                                            self.loadJS(obj["prod-js"], callback);
                                        
                                    );
                                 else 
                                    // Loads the development CSS file(s)
                                    self.loadCSS(obj["dev-css"], function() 
                                        // If there are development Javascript files to load
                                        if(obj["dev-js"]) 
                                            // Loads Require.js and tells Require.js to find the correct intialization file
                                            self.loadJS(obj["dev-js"], callback);
                                        
                                    );
                                
                            
                        ;
                // Mobile/Tablet Logic
                if((/iPhone|iPod|iPad|android|BlackBerry|Opera Mini|IEMobile/).test(ua)) 
                    // Mobile/Tablet CSS and JavaScript files to load
                    filesToLoad = 
                        // CSS file that is loaded when in development mode
                        "dev-css": "css/mobile.css",
                        // CSS file that is loaded when in production mode
                        "prod-css": "css/mobile.min.css",
                        // Require.js configuration file that is loaded when in development mode
                        "dev-js":  "data-main": "js/app/config/config.js", "src": "js/libs/require.js" ,
                        // JavaScript initialization file that is also loaded when in development mode
                        "dev-init": "js/app/init/MobileInit.js",
                        // JavaScript file that is loaded when in production mode
                        "prod-init": "js/app/init/MobileInit.min.js",
                        "prod-js":  "data-main": "js/app/config/config.js", "src": "js/libs/require.js" 
                    ;
                
                // Desktop Logic
                else 
                    // Desktop CSS and JavaScript files to load
                    filesToLoad = 
                        // CSS file that is loaded when in development mode
                        "dev-css": "css/desktop.css",
                        // CSS file that is loaded when in production mode
                        "prod-css": "css/desktop.min.css",
                        // Require.js configuration file that is also loaded when in development mode
                        "dev-js":  "data-main": "js/app/config/config.js", "src": "js/libs/require.js" ,
                        // JavaScript initialization file that is loaded when in development mode
                        "dev-init": "js/app/init/DesktopInit.js",
                        // JavaScript file that is loaded when in production mode
                        "prod-init": "js/app/init/DesktopInit.min.js",
                        "prod-js":  "data-main": "js/app/config/config.js", "src": "js/libs/require.js" 
                    ;
                
                boilerplateMVC.loadFiles(production, filesToLoad, function() 
                    if(!production && window.require) 
                        require([filesToLoad["dev-init"]]);
                     else if ( production ) 
                        require([filesToLoad["prod-init"]])
                    
                );
            )(navigator.userAgent || navigator.vendor || window.opera, window, document);

以及该项目中的其他逻辑:

    var App = new Backbone.Marionette.Application();

    function isMobile() 
        var userAgent = navigator.userAgent || navigator.vendor || window.opera;
        return ((/iPhone|iPod|iPad|Android|BlackBerry|Opera Mini|IEMobile/).test(userAgent));
    

    App.mobile = isMobile();


require(["App", "jquery", "routers/AppRouter", "controllers/MobileController", "backbone", "marionette", "jquerymobile", "backbone.validateAll"],
    function (App, $, AppRouter, AppController) 
        // Prevents all anchor click handling
        $.mobile.linkBindingEnabled = false;
        // Disabling this will prevent jQuery Mobile from handling hash changes
        $.mobile.hashListeningEnabled = false;

        App.appRouter = new AppRouter(
            controller:new AppController()
        );

        App.start();
    );

【讨论】:

以上是关于在移动设备中忽略条件依赖的主要内容,如果未能解决你的问题,请参考以下文章

Youtube iFrame API setPlaybackQuality 在移动设备上被忽略

企业不可忽略的问题——员工移动设备管理

WebView 总是在移动设备上出现 - 可能的错误

输入类型=“日期”占位符 - 移动设备

针对窄桌面而非移动设备的媒体查询

在网络移动设备上购买电子商务