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);
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($)。
这种写法还有一个好处是:此时$
变量为局部变量,不会对全局的$
造成影响
如果在执行到该代码时未引入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文件内部。