javascript - 使用 IIFE 方法并将变量从一个文件传递到另一个文件
问题描述
我之前的一个问题是如何在多个 .js 文件之间组织代码。现在我有一个问题。
我在 d3.js 中有一张按国家划分的地图。当用户双击一个国家时,我想将一个变量传递给另一个js文件。
这是我的 html 文件index.hbs:
<html lang='en'>
<head>
<meta charset='utf-8'>
<script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
<script src='https://d3js.org/topojson.v2.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
<link href='/css/all.css' rel='stylesheet'/>
</head>
<body>
<div id='map'></div>
<script>
var viewData = {};
viewData.nuts0 = JSON.parse('{{json nuts0}}'.replace(/"/g, '"').replace(/</, ''));
viewData.CONFIG = JSON.parse('{{json CONFIG}}'.replace(/"/g, '"').replace(/</, ''));
</script>
<script src='/script/map.js' rel='script'/><{{!}}/script>
<script src='/script/other.js' rel='script'/><{{!}}/script>
</body>
</html>
地图.js:
var NAME=(function map() {
var my = {};
var CONFIG = viewData.CONFIG;
var nuts0 = viewData.nuts0;
// paths
var countries;
// width and height of svg map container
var width = CONFIG.bubbleMap.width;
var height = CONFIG.bubbleMap.height;
// to check if user clicks or double click
var dblclick_timer = false;
// create Hammer projection
var projectionCurrent = d3.geoHammer()
.scale(1)
.translate([width/2, height/2]);
var projectionBase = d3.geoHammer()
.scale(1)
.translate([width/2, height/2]);
// creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
var path = d3.geoPath().projection(projectionCurrent);
// creates the svg element that contains the map
var map = d3.select('#map');
var mapSvg = map.append('svg')
.attr('id', 'map-svg')
.attr('width', width)
.attr('height', height);
var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');
countries = topojson.feature(nuts0, nuts0.objects.nuts0);
projectionCurrent.fitSize([width, height], countries);
var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
.data(countries.features)
.enter()
.append('path');
mapSvgGCountryPath.attr('class', 'country')
.attr('fill', 'tomato')
.style('stroke', 'white')
.style('stroke-width', 1)
.attr('d', path)
.attr('id', function(c) {
return 'country' + c.properties.nuts_id;
})
.on('click', clickOrDoubleCountry);
function clickOrDoubleCountry(d, i) {
if(dblclick_timer) { // double click
clearTimeout(dblclick_timer);
dblclick_timer = false;
my.countryDoubleClicked = d.country; // <-- variable to pass
}
else { // single click
dblclick_timer = setTimeout(function() {
dblclick_timer = false;
}, 250)
}
}
return my;
}());
其他.js:
(function other(NAME) {
console.log('my:', NAME.my); // undefined
console.log('my:', NAME.countryDoubleClicked); // undefined
})(NAME);
我希望能够读取在map.js
文件中创建的 my 对象other.js
,然后能够my.countryDoubleClicked
从other.js
.
这段代码不起作用,我得到TypeError: NAME.my is undefined
.
解决方案
有几件事正在发生:
揭示变量
首先,您不会my
像NAME.my
在map.js中那样显示要显示的变量:
var NAME = (function map() {
var my = {};
//...
return my;
}());
这设置NAME
为my
,而不是设置NAME.my
为my
。如果你确实想这样做,你可以这样做:
var NAME = (function map() {
var my = {};
//...
return {
my: my
};
}());
您可以从类似这样的文章中阅读有关这种称为“显示模块模式”的技术的更多信息:http: //jargon.js.org/_glossary/REVEALING_MODULE_PATTERN.md
稍后使用函数运行代码
其次,正如其他人所提到的并且您已经意识到,由于代码other.js
会立即运行,因此它会在用户有机会点击某个国家/地区之前运行该代码。相反,您需要可以按需运行的代码(在这种情况下,当用户双击某物时)。在 JavaScript 中,这通常是通过分配或传递函数来完成的。为简单起见,我们可以分配一些东西my.doubleClickHandler
,然后在中调用该函数clickOrDoubleCountry
。为此,我将 country 作为传递给处理程序的参数,并将其分配给NAME.my.countryDoubleClicked
,但您可能只需要使用其中一个。
function clickOrDoubleCountry(d, i) {
if(dblclick_timer) { // double click
clearTimeout(dblclick_timer);
dblclick_timer = false;
my.countryDoubleClicked = d.country; // <-- variable to pass
if (my.doubleClickHandler) {
my.doubleClickHandler(d.country);
}
}
// ...
}
然后在 中other.js
,您将要运行的功能分配给NAME.my.doubleClickHandler
:
(function other(NAME) {
NAME.my.doubleClickHandler = function (country) {
// now this code runs whenever the user double clicks on something
console.log('exposed variable', NAME.my.countryDoubleClicked); // should be the country
console.log('argument', country); // should be the same country
});
})(NAME);
所以除了上面修改过的other.js之外,这是完整修改过的map.js:
var NAME=(function map() {
var my = {};
var CONFIG = viewData.CONFIG;
var nuts0 = viewData.nuts0;
// paths
var countries;
// width and height of svg map container
var width = CONFIG.bubbleMap.width;
var height = CONFIG.bubbleMap.height;
// to check if user clicks or double click
var dblclick_timer = false;
// create Hammer projection
var projectionCurrent = d3.geoHammer()
.scale(1)
.translate([width/2, height/2]);
var projectionBase = d3.geoHammer()
.scale(1)
.translate([width/2, height/2]);
// creates a new geographic path generator with the default settings. If projection is specified, sets the current projection
var path = d3.geoPath().projection(projectionCurrent);
// creates the svg element that contains the map
var map = d3.select('#map');
var mapSvg = map.append('svg')
.attr('id', 'map-svg')
.attr('width', width)
.attr('height', height);
var mapSvgGCountry = mapSvg.append('g').attr('id', 'nuts0');
countries = topojson.feature(nuts0, nuts0.objects.nuts0);
projectionCurrent.fitSize([width, height], countries);
var mapSvgGCountryPath = mapSvgGCountry.selectAll('path')
.data(countries.features)
.enter()
.append('path');
mapSvgGCountryPath.attr('class', 'country')
.attr('fill', 'tomato')
.style('stroke', 'white')
.style('stroke-width', 1)
.attr('d', path)
.attr('id', function(c) {
return 'country' + c.properties.nuts_id;
})
.on('click', clickOrDoubleCountry);
function clickOrDoubleCountry(d, i) {
if(dblclick_timer) { // double click
clearTimeout(dblclick_timer);
dblclick_timer = false;
my.countryDoubleClicked = d.country; // <-- variable to pass
if (my.doubleClickHandler) {
my.doubleClickHandler(d.country);
}
}
else { // single click
dblclick_timer = setTimeout(function() {
dblclick_timer = false;
}, 250)
}
}
return {
my: my
};
}());
如果您不想用于所有内容并希望直接从(例如,而不是)NAME.my
访问方法和变量,您可以使用原始的 return 语句,请记住不会有命名的变量。NAME
NAME.countryDoubleClicked
NAME.my.countryDoubleClicked
return my;
NAME.my
推荐阅读
- android - 如何从 Android 替换 Android UAMP 中的 JSON 音乐文件?
- c# - Unity 多个滑块不会同时更新
- javascript - 如何在 React Js (Node Js API) 中创建这种类型的 json 响应
- visual-studio - 我可以在 Visual Studio 中的折叠代码旁边放置注释或注释之类的东西吗?
- java - 使用 Spring 配置文件和 Maven 配置文件
- css - 带有 sass-loader 的 mini-css-extract-plugin 不输出 CSS 文件
- sql-server - SQL Server:看起来有序的唯一复合键
- python-3.x - 在函数python中声明变量
- python - Python中有没有办法检查播放音频的程序
- xcode - macOS 11.0.1 - Flutter 医生给出 cocopods 错误