• electron怎么引入jquery不会冲突


    在开发Electron程序时,在引入jQueryBootstrap后,控制台报错:

    Uncaught TypeError: Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.
        at Object.jQueryDetection (bootstrap.min.js:6)
        at bootstrap.min.js:6
        at bootstrap.min.js:6
        at bootstrap.min.js:6

    而反复查看代码没发现问题,引用的顺序没有问题:

    <script src="js/jquery.min.js"></script>
    <script src="js/bootstrap.min.js"></script>

    后在网上找到了一些方法,解决了我的疑惑。

    方法一

    在引入jQuery之前,添加如下代码:

    <script>
        if (typeof module === 'object') {window.module = module; module = undefined;}
    </script>

    方法二

    使用require方式引入jquery

    window.$ = window.jQuery = require('./js/jquery.min.js')

    虽然问题是解决了,但是是什么引发了这个问题呢?

    经过深入了解,发现原来electron里面还是和浏览器有区别的。在electron里面使用的是CommonJS标准,这也是后端服务器采用的标准,而在jQuery中有如下代码:

    if ( typeof module === "object" && typeof module.exports === "object" ) {
      // set jQuery in `module`
    } else {
      // set jQuery in `window`
    }
    if (typeof module === "object") {
        window.jQuery = window.$ = module.exports;
    }
    //window.jQuery = window.$ = require('jquery');

    判断如果在CommonJS中,jQuery就绑定到module下,否者就绑定到window下,我们经常使用的$就是在window的下。

    Bootstrap是一个前端工具,它依赖jQuery,直接从window下有没有jQuery/$来判断有没有jQuery,而在这里就行不通了,因为jQuery是在module下的,所以就有了如上的两种方法,个人更倾向于第二种方法。

    有没有其他方法?

    方法三

    因为electron中集成了node相关的东西,可以把这个集成关闭或者把相关对象绑定到新的对象上:

    const win = new BrowserWindow({
         800,
        height: 600,
        webPreferences: {
          nodeIntegration: false    // 重点是这个
        }
      })

    上面这种方式,window对象下就没有module了。

    当然我们也可以把绑定的对象替换掉,这样也能使用node相关的API

    <head> 
    <script> 
        window.nodeRequire = require; 
        delete window.require;
        delete window.exports;
      delete window.module; 
    </script> 
    <script type="text/javascript" src="jquery.js"></script> 
    </head>

    这只是一种解决思路,不建议大家这么做。

    既然都谈到CommonJS了,有必要进一步了解前端的几个规范。

    CommonJs,AMD和CMD

    • CommonJSnodejs也就是服务器端广泛使用的模块化机制,模块必须通过module.exports 导出对外的变量或接口,通过require() 来导入其他模块的输出到当前模块作用域中,此方式是同步的
    • AMD 是 RequireJS 在推广过程中对模块定义的规范化产出,提前执行(异步加载:依赖先执行)+延迟执行
    • CMD 是 SeaJS 在推广过程中对模块定义的规范化产出,延迟执行(运行到需加载,根据顺序执行)

    CommonJS

    CommonJS模块加载是同步的,后面的模块必须等前面的加载完成才能执行。

    定义模块:
    
    // 模块 a.js
    const name = 'foo'
    
    module.exports = {
        name,
        text: 'bar'
    }
    加载模块:
    
    // 模块 b.js
    // 引用核心模块或者第三方包模块,不需要写完整路径
    const path = require('path');
    // 引用自定义模块可以省略.js
    const { name, text } = require('./a');
    
    console.log(name, text);
    // 输出 foo bar

    CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。看如下例子:

    // b.js
    let age = 1;
    setTimeout(() => {
      age = 18;
    }, 10);
    module.exports = {
      age
    }
    // a.js
    const b = require('./b');
    console.log(b.age);
    setTimeout(() => {
      console.log(b.age);
      console.log(require('./b').age);
    }, 100);
    
    // 执行:node a.js
    // 执行结果:
    // 1
    // 1
    // 1

    还有,CommonJS模块重复引入的模块并不会重复执行,再次获取模块只会获得之前获取到的模块的缓存。

    AMD

    全称:Asynchronous Module Definition,中文翻译:异步模块定义,javascript原生不支持这种规范,使用AMD规范进行页面开发需要用到对应的库函数,鼎鼎大名的就是RequireJS

    定义模块:

    // 独立模块
    define(function(){
        ...
        return {
            //返回接口
        }
    })
    
    // 非独立模块
    define(['foo','bar'],function(foo, bar){
        ...
        return {
            //返回接口
        }
    })

    独立模块即定义的模块不依赖其他模块,非独立模块就是会依赖其他模块。我们定义的模块依赖foobar,第二个参数是一个函数,仅当依赖加载成功后才会调用,函数的参数与前面的依赖数组一一对应,函数必须返回一个对象,给其他模块调用。

    加载模块:

    AMD加载模块也是用require,由于是异步的所以只能用回调函数的方式:

    require(['foo','bar'], function(foo,bar){
        ...
    })

    回调函数中才能使用依赖的模块,这里是在定义的时候加载模块了,相当于把依赖前置。

    require()里面可以配置一些参数:

    require.config({
        paths: {
            "backbone": "vendor/backbone",
            "underscore": "vendor/underscore"
        },
        shim: {
            "backbone": {
                deps: [ "underscore" ],
                exports: "Backbone"
            },
            "underscore": {
                exports: "_"
            }
        }
    });
    • paths: 指定模块的位置,可以是文件路径,也可以是一个网址
    • shim: 有些库不兼容AMD的写法,可以配置shim来解决,可以理解成“垫片”,帮助require.js加载非AMD规范的库

    CMD

    Common Module Definition通用模块定义,这个规范也是国内发展起来的,有个浏览器的实现SeaJSCMDAMD要解决的问题都是一样的,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同。

    和其他规范一样,CMD中也是一个模块一个文件:

    define(function(require, exports, module) {
    
      // 模块代码
    
    });

    require是可以把其他模块导入进来的一个参数;而exports是可以把模块内的一些属性和方法导出的;module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。

    AMD是依赖关系前置,在定义模块的时候就要声明其依赖的模块,CMD是按需加载依赖,只有在用到某个模块的时候再去require,看看CMD的例子:

    // model1.js
    define(function (require, exports, module) {
        console.log('model1 entry');
        exports.getHello = function () {
            return 'model1';
        }
    });
    
    // model2.js
    define(function (require, exports, module) {
        console.log('model2 entry');
        exports.getHello = function () {
            return 'model2';
        }
    });
    
    // main.js
    define(function(require, exports, module) {
        var model1 = require('./model1'); //在需要时声明
        console.log(model1.getHello());
        var model2 = require('./model2'); //在需要时声明
        console.log(model2.getHello());
    });
    
    <script src="sea.js"></script>
    <script>
        seajs.use('./main.js')
    </script>

    CommonJS主要用于服务端,模块文件都存在本地硬盘,所以加载起来比较快,不用考虑用异步加载,但是在浏览器中,受限于网络原因,更合理的方案应该是异步加载。为了方便模块化开发,这时武林中出现了AMDCMD两大门派,分别代表了两种不同的思想,一是依赖前置,二是按需加载依赖,各有利弊,这两大门派都像争夺武林盟主,按理说是要比武论高下的,但半路杀出个程咬金,选举委员会直接自己推了一个规范:ES Module,告知天下以后要听ES Module的,他才是大哥。

    这小子又是谁?

    ES Module

    ES modules(ESM)是 JavaScript 官方的标准化模块系统,能和CommonJS混合使用,意味着能在node环境下执行,因为他是标准,所以未来很多浏览器都会支持。

    模块定义:

    // module.js
    export function name() {
        return 'this is name';
    }
    
    export function foo() {
        return 'foooooo';
    }

    模块加载:

    // index.js
    import { name, foo } from './module.js';
    console.log(name(), foo());

    加载模块的方式还有很多种,比如:

    // 加载单个模块
    import {sum} from './example.js'
    
    // 加载多个
    import {sum,multiply} from './example.js'
    
    // 导入整个模块,别创建一个别名
    import * as example from './example.js'

    ESM中模块导出是值的引用,看如下例子:

    // b.js
    export let age = 1;
    
    setTimeout(() => {
        age = 2;
    }, 10);
    // a.js
    import { age } from './b.js';
    
    console.log(age);
    setTimeout(() => {
        console.log(age);
        import('./b.js').then(({ age }) => {
            console.log(age);
        })
    }, 100);
    
    // 执行结果:
    // 1
    // 2
    // 2

    import/export使用又一个限制,就是不能在其他语句/表达式的内部使用,比如if语句里面,所以一般都在最底部,原因是ESM使用javascript引擎静态分析。

    至此,ESM已经是事实上的盟主,使用该规范无论是node环境还是浏览器环境都能很好兼容,而且前端也不要再引入requirejssea.js来进行模块开发。

  • 相关阅读:
    模拟两位选手进行n羽毛球比赛(15分赛制)并计算模拟胜率
    Pyton实例
    Python图片处理
    jieba库的使用和好玩的词云
    Python汉诺塔问题
    多线程同时操作一个epoll_fd
    Linux tr命令
    iptables 深入分析
    Linux xtables
    Linux IPC 共享内存
  • 原文地址:https://www.cnblogs.com/luckyuns/p/16423580.html
Copyright © 2020-2023  润新知