好久沒(méi)寫(xiě)技術(shù)文章了,慚愧慚愧。現(xiàn)在找到了新的目標(biāo),開(kāi)始加油了!
來(lái)一篇關(guān)于JavaScript的導(dǎo)入問(wèn)題,其實(shí)是個(gè)老問(wèn)題了,知道的同學(xué)看看就別笑了,不知道的同學(xué)就認(rèn)真聽(tīng)講了,呵呵。
大家都知道不管是靜態(tài)語(yǔ)言還是動(dòng)態(tài)腳本一般都有他們自己的導(dǎo)入方法,比如Java,在一個(gè)特定的運(yùn)行環(huán)境中(jar包或是規(guī)定的目錄結(jié)構(gòu)中)用import關(guān)鍵字來(lái)導(dǎo)入非本包中的類(lèi),注意這里還有個(gè)包的概念,就是說(shuō)把一組在某些方面相似的類(lèi)(如一起實(shí)現(xiàn)同一個(gè)功能、類(lèi)的性質(zhì)相同等)組織在一起,互相就不需要再導(dǎo)入了。
而JavaScript是在頁(yè)面里面用script標(biāo)簽引入的,并沒(méi)有導(dǎo)入的概念,就更沒(méi)有包的概念了(其實(shí)這也造成了名稱(chēng)空間的問(wèn)題)。最終的效果就是把所有的JavaScript代碼都引入到頁(yè)面里面就對(duì)了。在JavaScript被當(dāng)作一門(mén)很重要的web編程語(yǔ)言之前大家編寫(xiě)的JavaScript代碼相對(duì)較小,一般一兩個(gè)文件就足夠了,有幾個(gè)文件就用幾個(gè)標(biāo)簽引入就行。但是隨著JavaScript的重要性和實(shí)用性被充分發(fā)掘后,用JavaScript編寫(xiě)的表現(xiàn)層中間件、Ajax應(yīng)用、webGIS客戶(hù)端顯示系統(tǒng)等都已經(jīng)不是一個(gè)兩個(gè)文件能夠容納的了,或者說(shuō)不是這么簡(jiǎn)單的目錄結(jié)構(gòu)能夠解決的。
好比Openlayers(一個(gè)即將一統(tǒng)天下的webGIS客戶(hù)端顯示系統(tǒng))這樣一個(gè)完全由JavaScript編寫(xiě)的系統(tǒng),它目前的版本的源代碼已經(jīng)有100個(gè)左右的js文件,10多個(gè)文件目錄(當(dāng)然不是那種壓成一個(gè)文件的)。我們不可能100多個(gè)script標(biāo)簽來(lái)把它們?nèi)恳脒M(jìn)來(lái),這樣既不優(yōu)雅也難以維護(hù)。Openlayers就提供了一種比較好的解決方式,我們馬上來(lái)分析一下。不過(guò)在分析好的之前我們來(lái)看一個(gè)個(gè)人認(rèn)為比較壞的例子,其實(shí)很多早期的JavaScript系統(tǒng)都是使用這種方式。
這個(gè)比較壞的例子是取自一個(gè)知名地圖廠商提供的webGIS客戶(hù)端,不過(guò)這個(gè)webGIS客戶(hù)端已經(jīng)是3年前開(kāi)發(fā)的了,可能他們現(xiàn)在的已經(jīng)改掉了,僅僅作為一個(gè)教材,并沒(méi)有任何感情色彩。
它的做法是這樣的:
在頁(yè)面中引入一個(gè)名為abc_include.js(化名,呵呵,還是謹(jǐn)慎點(diǎn)好)的文件,在這個(gè)文件里面把其他的文件全部導(dǎo)入進(jìn)來(lái)。
1
2
<!--
3
//////////////////////////////////////////
4
// //
5
// //
6
// 包含所有引用的程序包 //
7
// //
8
// //
9
//////////////////////////////////////////
10
11
document.write('<script language="javascript" src="abc_js/abc_1.js"></script>');
12
document.write('<script language="javascript" src="abc_js/abc_2.js"></script>');
13
document.write('<script language="javascript" src="abc_js/abc_3.js"></script>');
14
document.write('<script language="javascript" src="abc_js/abc_4.js"></script>');
15
document.write('<script language="javascript" src="abc_js/abc_5.js"></script>');
16
document.write('<script language="javascript" src="abc_js/abc_6.js"></script>');
17
document.write('<script language="javascript" src="abc_js/abc_7.js"></script>');
18
document.write('<script language="javascript" src="abc_js/abc_8.js"></script>');
19
document.write('<script language="javascript" src="abc_js/abc_9.js"></script>');
20
document.write('<script language="javascript" src="abc_js/abc_10.js"></script>');
21
document.write('<script language="javascript" src="abc_js/abc_11.js"></script>');
22
document.write('<script language="javascript" src="abc_js/abc_12.js"></script>');
23
document.write('<script language="javascript" src="abc_js/abc_13.js"></script>');
24
document.write('<script language="javascript" src="abc_js/abc_14.js"></script>');
25
document.write('<script language="javascript" src="abc_js/abc_15.js"></script>');
26
document.write('<script language="javascript" src="abc_js/abc_16.js"></script>');
27
document.write('<script language="javascript" src="abc_js/abc_17.js"></script>');
28
document.write('<script language="javascript" src="abc_js/abc_18.js"></script>');
29
30
//-->

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

這些代碼其實(shí)很容易理解,就是把標(biāo)簽用JavaScript的方式寫(xiě)進(jìn)去,而不是直接寫(xiě)在html代碼中,這樣確實(shí)達(dá)到了一些目的,但是出現(xiàn)了一個(gè)很?chē)?yán)重的問(wèn)題。在頁(yè)面中包含的代碼其實(shí)就是<script language="javascript" src="abc_js/abc_1.js"></script>這樣的script標(biāo)簽,大家會(huì)發(fā)現(xiàn)這里的路徑都是abc_js/,也就是說(shuō)我調(diào)用這個(gè)系統(tǒng)的頁(yè)面必須與abc_js保持在同一目錄。同事在開(kāi)發(fā)的時(shí)候就犯了這樣的錯(cuò)誤,把頁(yè)面沒(méi)和它放在同一個(gè)目錄,叫我過(guò)去幫忙看看,我懷著對(duì)這個(gè)地圖廠商的崇拜和信任找了半個(gè)小時(shí),最后發(fā)現(xiàn)居然是這種問(wèn)題,完全不是一個(gè)負(fù)責(zé)任的廠商寫(xiě)的系統(tǒng),還是要小BS一下。
下面我們?cè)賮?lái)看看Openlayers是如何處理的,其實(shí)Openlayers的基本思想也是這樣的,最終也是為了把這些標(biāo)簽都寫(xiě)入進(jìn)去,但Openlayers完全解決了路徑的問(wèn)題,并且加入了瀏覽器的兼容,實(shí)現(xiàn)的更為優(yōu)雅。
1
/**//* Copyright (c) 2006 MetaCarta, Inc., published under the BSD license.
2
* See http://svn.openlayers.org/trunk/openlayers/release-license.txt
3
* for the full text of the license. */
4
5
/**//* @requires OpenLayers/BaseTypes.js
6
*/
7
8
////
9
/// This blob sucks in all the files in uncompressed form for ease of use
10
///
11
12
OpenLayers = new Object();
13
14
OpenLayers._scriptName = (
15
typeof(_OPENLAYERS_SFL_) == "undefined" ? "lib/OpenLayers.js"
16
: "OpenLayers.js" );
17
18
OpenLayers._getScriptLocation = function ()
{
19
var scriptLocation = "";
20
var SCRIPT_NAME = OpenLayers._scriptName;
21
22
var scripts = document.getElementsByTagName('script');
23
for (var i = 0; i < scripts.length; i++)
{
24
var src = scripts[i].getAttribute('src');
25
if (src)
{
26
var index = src.lastIndexOf(SCRIPT_NAME);
27
// is it found, at the end of the URL?
28
if ((index > -1) && (index + SCRIPT_NAME.length == src.length))
{
29
scriptLocation = src.slice(0, -SCRIPT_NAME.length);
30
break;
31
}
32
}
33
}
34
return scriptLocation;
35
}
36
37
/**//*
38
`_OPENLAYERS_SFL_` is a flag indicating this file is being included
39
in a Single File Library build of the OpenLayers Library.
40
41
When we are *not* part of a SFL build we dynamically include the
42
OpenLayers library code.
43
44
When we *are* part of a SFL build we do not dynamically include the
45
OpenLayers library code as it will be appended at the end of this file.
46
*/
47
if (typeof(_OPENLAYERS_SFL_) == "undefined")
{
48
/**//*
49
The original code appeared to use a try/catch block
50
to avoid polluting the global namespace,
51
we now use a anonymous function to achieve the same result.
52
*/
53
(function()
{
54
var jsfiles=new Array(
55
"OpenLayers/BaseTypes.js",
56
"OpenLayers/Util.js",
57
"Rico/Corner.js",
58
"Rico/Color.js",
59
"OpenLayers/Ajax.js",
60
"OpenLayers/Events.js",
61
"OpenLayers/Map.js",
62
"OpenLayers/Layer.js",
63
"OpenLayers/Icon.js",
64
"OpenLayers/Marker.js",
65
"OpenLayers/Marker/Box.js",
66
"OpenLayers/Popup.js",
67
"OpenLayers/Tile.js",
68
"OpenLayers/Feature.js",
69
"OpenLayers/Feature/Vector.js",
70
"OpenLayers/Feature/WFS.js",
71
"OpenLayers/Tile/Image.js",
72
"OpenLayers/Tile/WFS.js",
73
"OpenLayers/Layer/Image.js",
74
"OpenLayers/Layer/EventPane.js",
75
"OpenLayers/Layer/FixedZoomLevels.js",
76
"OpenLayers/Layer/Google.js",
77
"OpenLayers/Layer/VirtualEarth.js",
78
"OpenLayers/Layer/Yahoo.js",
79
"OpenLayers/Layer/HTTPRequest.js",
80
"OpenLayers/Layer/Grid.js",
81
"OpenLayers/Layer/MapServer.js",
82
"OpenLayers/Layer/MapServer/Untiled.js",
83
"OpenLayers/Layer/KaMap.js",
84
"OpenLayers/Layer/MultiMap.js",
85
"OpenLayers/Layer/Markers.js",
86
"OpenLayers/Layer/Text.js",
87
"OpenLayers/Layer/WorldWind.js",
88
"OpenLayers/Layer/WMS.js",
89
"OpenLayers/Layer/WMS/Untiled.js",
90
"OpenLayers/Layer/GeoRSS.js",
91
"OpenLayers/Layer/Boxes.js",
92
"OpenLayers/Layer/Canvas.js",
93
"OpenLayers/Layer/TMS.js",
94
"OpenLayers/Popup/Anchored.js",
95
"OpenLayers/Popup/AnchoredBubble.js",
96
"OpenLayers/Handler.js",
97
"OpenLayers/Handler/Point.js",
98
"OpenLayers/Handler/Path.js",
99
"OpenLayers/Handler/Polygon.js",
100
"OpenLayers/Handler/Feature.js",
101
"OpenLayers/Handler/Drag.js",
102
"OpenLayers/Handler/Box.js",
103
"OpenLayers/Handler/MouseWheel.js",
104
"OpenLayers/Handler/Keyboard.js",
105
"OpenLayers/Control.js",
106
"OpenLayers/Control/ZoomBox.js",
107
"OpenLayers/Control/ZoomToMaxExtent.js",
108
"OpenLayers/Control/DragPan.js",
109
"OpenLayers/Control/Navigation.js",
110
"OpenLayers/Control/MouseDefaults.js",
111
"OpenLayers/Control/MousePosition.js",
112
"OpenLayers/Control/OverviewMap.js",
113
"OpenLayers/Control/KeyboardDefaults.js",
114
"OpenLayers/Control/PanZoom.js",
115
"OpenLayers/Control/PanZoomBar.js",
116
"OpenLayers/Control/ArgParser.js",
117
"OpenLayers/Control/Permalink.js",
118
"OpenLayers/Control/Scale.js",
119
"OpenLayers/Control/LayerSwitcher.js",
120
"OpenLayers/Control/DrawFeature.js",
121
"OpenLayers/Control/Panel.js",
122
"OpenLayers/Control/SelectFeature.js",
123
"OpenLayers/Geometry.js",
124
"OpenLayers/Geometry/Rectangle.js",
125
"OpenLayers/Geometry/Collection.js",
126
"OpenLayers/Geometry/Point.js",
127
"OpenLayers/Geometry/MultiPoint.js",
128
"OpenLayers/Geometry/Curve.js",
129
"OpenLayers/Geometry/LineString.js",
130
"OpenLayers/Geometry/LinearRing.js",
131
"OpenLayers/Geometry/Polygon.js",
132
"OpenLayers/Geometry/MultiLineString.js",
133
"OpenLayers/Geometry/MultiPolygon.js",
134
"OpenLayers/Geometry/Surface.js",
135
"OpenLayers/Renderer.js",
136
"OpenLayers/Renderer/Elements.js",
137
"OpenLayers/Renderer/SVG.js",
138
"OpenLayers/Renderer/VML.js",
139
"OpenLayers/Layer/Vector.js",
140
"OpenLayers/Layer/GML.js",
141
"OpenLayers/Format.js",
142
"OpenLayers/Format/GML.js",
143
"OpenLayers/Format/KML.js",
144
"OpenLayers/Format/GeoRSS.js",
145
"OpenLayers/Format/WFS.js",
146
"OpenLayers/Format/WKT.js",
147
"OpenLayers/Layer/WFS.js",
148
"OpenLayers/Control/MouseToolbar.js",
149
"OpenLayers/Control/NavToolbar.js",
150
"OpenLayers/Control/EditingToolbar.js"
151
); // etc.
152
153
var allScriptTags = "";
154
var host = OpenLayers._getScriptLocation() + "lib/";
155
156
for (var i = 0; i < jsfiles.length; i++)
{
157
if (/MSIE/.test(navigator.userAgent) || /Safari/.test(navigator.userAgent))
{
158
var currentScriptTag = "<script src='" + host + jsfiles[i] + "'></script>";
159
allScriptTags += currentScriptTag;
160
} else
{
161
var s = document.createElement("script");
162
s.src = host + jsfiles[i];
163
var h = document.getElementsByTagName("head").length ?
164
document.getElementsByTagName("head")[0] :
165
document.body;
166
h.appendChild(s);
167
}
168
}
169
if (allScriptTags) document.write(allScriptTags);
170
})();
171
}
172
OpenLayers.VERSION_NUMBER="$Revision: 3198 $";
173


2

3

4

5


6

7

8

9

10

11

12

13

14

15

16

17

18



19

20

21

22

23



24

25



26

27

28



29

30

31

32

33

34

35

36

37


38

39

40

41

42

43

44

45

46

47



48


49

50

51

52

53



54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156



157



158

159

160



161

162

163

164

165

166

167

168

169

170

171

172

173

這個(gè)文件可以在Openlayers最新的版本中找到,它除了定義了一個(gè)名稱(chēng)空間外最重要的作用就是完成了需要引入代碼的導(dǎo)入工作。
大家都應(yīng)該不難看懂這些代碼到底做了些什么,還是把實(shí)現(xiàn)的基本過(guò)程說(shuō)一遍。首先我們會(huì)在頁(yè)面里面包含一個(gè)主文件,如<script src="../lib/OpenLayers.js"></script>,OpenLayers._getScriptLocation方法首先找到這個(gè)標(biāo)簽,取出src屬性里面的內(nèi)容../lib/OpenLayers.js,這個(gè)時(shí)候根據(jù)定義好的_scriptName--lib/OpenLayers.js找出它之前的location目錄../,這樣不管前面是怎么樣的目錄,我們只要確定了location目錄就可以順利的導(dǎo)入其他的文件了,也就是說(shuō)只要知道其他文件與lib/OpenLayers.js的相對(duì)位置,我們就可以順利的導(dǎo)入了。 jsfiles中定義了所有需要導(dǎo)入的文件,然后下面就用一個(gè)for循環(huán)集體導(dǎo)入,貌似這又是一個(gè)什么設(shè)計(jì)模式,呵呵。確實(shí)比X廠商的代碼優(yōu)雅了許多。導(dǎo)入的for循環(huán)里面也做了瀏覽器的兼容,這年頭不做好瀏覽器的兼容哪里敢稱(chēng)真正的js系統(tǒng)。這里又要順便提請(qǐng)各位同仁們?cè)趯?xiě)稍復(fù)雜的JavaScript程序的時(shí)候最好多考慮兼容問(wèn)題,如果你怕麻煩其實(shí)建議也更推薦使用象mootools、prototpye等這樣的js庫(kù)。因?yàn)橹荒茉贗E下跑的程序在今天看來(lái)真是遜掉了,并且你也無(wú)情的打擊了Firefox用戶(hù)們。
其實(shí)一切在代碼里都明白了,所以推薦大家多看看優(yōu)秀開(kāi)源項(xiàng)目的源代碼,可以學(xué)到很多好東西。
真的好久不寫(xiě)技術(shù)文章了,寫(xiě)出來(lái)的東西連我自己都不太清楚講了些什么,需要繼續(xù)加油!
就是我裝了geoserver,引用的是geoserver里面的http://127.0.0.1:8080/geoserver/openlayers/OpenLayers.js。。這個(gè)js文件。
但是有些類(lèi)是無(wú)法定義的(如:OpenLayers.Format.GML,OpenLayers.Layers.Vector等),好像這個(gè)js文件并不能把其他js文件引入進(jìn)來(lái)。
我該怎么解決這問(wèn)題呢?請(qǐng)樓主幫忙,我郵箱:hand1024@126.com