2

angular中使用了webpack做为依赖管理器,相较于以前在html中使用<script type="text/javascript" src="xxxx"的方式,使用webpack可以实现使在需要某些依赖的时候才进行加载。性能虽然好,但在使用一些历史的依赖于jquery的依赖时往往会出现找不到jquery的问题。

情景

假设当前项目需要iCheck插件,此插件依赖于jquery

引用jQuery

javascript中,可以通过向window对象上添加属性的方式来实现全局变量。比如:

var a = 'hello';
window.test = a;
console.log(test);

image.png

jquery可以通过npm来进行安装,安装完成后可以使用import语句将其引入到当前的项目中。想到项目中随处使用$jQuery的关键字,则需要将$jquery声明为全局变量。打开angular中启动模块app.moudle.ts并向其中加入以下代码:

import * as jq from 'jquery';  ➊
declare var window: any; ➋

window.jQuery = jq; ➌
window.$ = jq; ➍
  • ➊ 从jquery中引入jquery,并将值赋予jq
  • ➋ 声明window的类型为any,以防在其上添加全局变量时发生错误
  • ➌ 添加全局变量jQuery
  • ➍ 添加全局变量$



只所以这样使用是由于jquery最后的几行代码如下,有兴趣的可以继续研究下
if ( !noGlobal ) { ➊
    window.jQuery = window.$ = jQuery; 
}

return jQuery; ➋
}));
  • ➊ 使用import引用时noGlobal的值为true
  • ➋ 将jQuery做为返回值返回


如此一来便可以在项目中使用$jQuery了。但由于typeScript是强类型的,所以在其它使用到$的地方还需要声明$的类型为任意类型。

declare var $: any;
console.log($);

引用iCheck

iCheck官方未给出使用npm安装的方法。我们下载js文件后放到项目的任意文件中。iCheck并未像jquery一样进行相应的return,所以也就不能像使用引入jquery一样来进行引用了。这种情况则可以使用require方法来解决。假设当前icheck文件的存储地址为:./../bower_components/iCheck/icheck,则可以在成功引用jquery后使用以下代码引用icheck

import * as $ from 'jquery';
declare var window: any;
declare var require: any; ➊

window.jQuery = $;
window.$ = $;

require('./../bower_components/iCheck/icheck'); ➋
  • ➊ 定义require变量类型为any
  • ➋ 使用require引用特定位置的文件

引用其它依赖

有些依赖已经可以通过npm进行安装,则引用起来就很简单了。只需要使用以下语句则可以完成引用:

require('依赖名');

总结

在angular中使用jquery时,主要解决的是向window中添加全局变量的问题。当window中存在$全局变量后,便可以在其它需要jquery功能的地方使用$()方法。当window中存在jQuery全局变量后,其它依赖于该jQuery的第三方依赖便可以成功的执行。

大多依赖于jquery的库会有以下格式:

(function($★) {
   // 功能代码
})(window.jQuery || window.Zepto);
  • ➊ 如果window.jQuery已定义,则将★的值设置为window.jQuery并立即执行function($)。
  • ➋ 如果window.jQuery未这义、window.Zepto已定义,则将★的值设置为window.Zepto并立即执行function($)。
  • ➌ 如果window.jQuery、window.Zepto均未定义,则将★的设置设置为undefined并立即执行function($)。

image.png

这种写法还有一个好处是:此时$变量为局部变量,不会对全局的$造成影响

如果在执行到该代码时未引入window.jQuery,则window.jQuery、window.Zepto的值均为undefined,此时执行function($){ 依赖于$的功能代码 }的功能代码时便会发生在undefined上调用xxx的错误。解决该错误的方法是在执行这段代码前将jQuery添加到window中。也就是本文的解决的方案。

require与import

那么为什么引入jquery时使用的是import,而引用iCheck使用的是require呢。这是由jquery与iCheck的功能特点以及require及import的特点所决定的:

名称 功能特点 示例代码
jquery 定义对象,返回对象 return jQuery
iCheck 执行了匿名函数 (function(){ 这里是功能代码 })()
名称 功能 必然执行 作用域 执行时机
require('icheck') 将icheck的代码复制到当前位置 应用上下文 立即执行
import * as $ from 'jquery'; 声明变量$的来源 jquery.js文件内部 使用$时执行

以示例代码为例:我们需要jquery中的返回的jQuery对象,所以需要import来进行引入(import * as $ from 'jquery';)此时$的值为jQuery。对于iCheck而言我们需要执行该匿名函数,所以使用require('iCheck')

简单来说:require等于复制一份相同的js代码放在require代码所在的位置上,所以js代码的作用域为上下文;import等于创建一个js文件的引用(快捷方式),只有使用该引用时才会尝试找js文件要内容,此时js文件执行的作用域为此js文件内部。


潘杰
3.1k 声望238 粉丝