我正在尝试从不同的文件组织JS代码.我正在使用D3.js并且我创建了3个可视化对象,用户可以进行交互.例如,如果将鼠标悬停在第一个可视化的元素上,我想相应地更改第二个和第三个.
此过程使用此代码.
index.html:
<body>
<span id='elem1' class='el'></span>
<span id='elem2' class='el'></span>
<span id='elem3' class='el'></span>
<script src='page1.js' rel='script'></script>
<script src='page2.js' rel='script'></script>
<script src='page3.js' rel='script'></script>
</body>
Run Code Online (Sandbox Code Playgroud)
page1.js:
var PAGE1 = (function page1() {
// object to export
var moduleObj = {};
var elem1 = d3.select('#elem1')
.append('svg')
.append('g')
.append('rect')
.attr('id', 'elem1rect')
.attr('width', 50)
.attr('height', 50)
.attr('fill', '#FF5733');
elem1.on('click', function() {
var elemClicked = 'elem1';
console.log('PAGE1 // Click on:', elemClicked);
if(moduleObj.clickElem1ToPage2Handler) {
moduleObj.clickElem1ToPage2Handler(elemClicked);
}
if(moduleObj.clickElem1ToPage3Handler) {
moduleObj.clickElem1ToPage3Handler(elemClicked);
}
});
return moduleObj;
}());
Run Code Online (Sandbox Code Playgroud)
page2.js:
(function page2() {
var elem2 = d3.select('#elem2')
.append('svg')
.append('g')
.append('rect')
.attr('id', 'elem2rect')
.attr('width', 50)
.attr('height', 50)
.attr('fill', '#FFC300');
elem2.on('click', function() {
var elemClicked = 'elem2';
console.log('PAGE2 // Click on:', elemClicked);
});
PAGE1.clickElem1ToPage2Handler = function(clickFrom) {
console.log('PAGE2 // Page2 received click from:', clickFrom);
};
})();
Run Code Online (Sandbox Code Playgroud)
page3.js:
(function page3() {
var elem3 = d3.select('#elem3')
.append('svg')
.append('g')
.append('rect')
.attr('id', 'elem3rect')
.attr('width', 50)
.attr('height', 50)
.attr('fill', '#DAF7A6');
elem3.on('click', function() {
var elemClicked = 'elem3';
console.log('PAGE3 // Click on:', elemClicked);
});
PAGE1.clickElem1ToPage3Handler = function(clickFrom) {
console.log('PAGE3 // Page3 received click from:', clickFrom);
};
})();
Run Code Online (Sandbox Code Playgroud)
然而,现在,我希望能够做反向,即通过将鼠标移到第二个可视化的元素上,修改第一和第三个可视化.同样,如果将鼠标悬停在第三个可视化的元素上,则会更改第一个和第二个可视化元素.
在这两种情况下,我遇到了一个问题:使用之前使用的相同策略不再起作用.我修改了page1.js和page2.js.
page1.js:
var PAGE1 = (function page1() {
// object to export
var moduleObj = {};
var elem1 = d3.select('#elem1')
.append('svg')
.append('g')
.append('rect')
.attr('id', 'elem1rect')
.attr('width', 50)
.attr('height', 50)
.attr('fill', '#FF5733');
elem1.on('click', function() {
var elemClicked = 'elem1';
console.log('PAGE1 // Click on:', elemClicked);
if(moduleObj.clickElem1ToPage2Handler) {
moduleObj.clickElem1ToPage2Handler(elemClicked);
}
if(moduleObj.clickElem1ToPage3Handler) {
moduleObj.clickElem1ToPage3Handler(elemClicked);
}
});
PAGE2.clickElem2ToPage1Handler = function(clickFrom) {
console.log('PAGE1 // Page1 received click from:', clickFrom);
};
return moduleObj;
}());
Run Code Online (Sandbox Code Playgroud)
page2.js:
var PAGE2 = (function page2() {
// object to export
var moduleObj = {};
var elem2 = d3.select('#elem2')
.append('svg')
.append('g')
.append('rect')
.attr('id', 'elem2rect')
.attr('width', 50)
.attr('height', 50)
.attr('fill', '#FFC300');
elem2.on('click', function() {
var elemClicked = 'elem2';
console.log('PAGE2 // Click on:', elemClicked);
if(moduleObj.clickElem2ToPage1Handler) {
moduleObj.clickElem2ToPage1Handler(elemClicked);
}
});
PAGE1.clickElem1ToPage2Handler = function(clickFrom) {
console.log('PAGE2 // Page2 received click from:', clickFrom);
};
return moduleObj;
})();
Run Code Online (Sandbox Code Playgroud)
生成的错误是:
ReferenceError: PAGE2 is not defined (page1.js:27:2)
TypeError: PAGE1 is undefined (page2.js:24:2)
TypeError: PAGE1 is undefined (page3.js:17:2)
Run Code Online (Sandbox Code Playgroud)
这是整个(工作)代码.
有没有办法处理所有情况(可能无需更改整个结构)?谢谢
小智 5
为了满足您不彻底改变整个结构的要求,我认为最简单的解决方案是采用事件驱动的通信架构.
您可以创建这样的自定义事件:
d3Event = document.createEvent('Event');
d3Event.initEvent('d3TestClick', true, true);
Run Code Online (Sandbox Code Playgroud)
然后,当您的某个元素与以下内容进行交互时,您可以调度此自定义事件:
elem1.on('click', function() {
var elemClicked = 'elem1';
console.log('PAGE1 // Click on:', elemClicked);
document.getElementById("elem1").dispatchEvent(d3Event);
});
Run Code Online (Sandbox Code Playgroud)
并且还为每个组件添加事件处理程序,以便在另一个组件触发事件时:
document.getElementById("elem2").addEventListener('d3TestClick', function (e) {
console.log('PAGE1 // Page1 received click from: Page2', e);
}, false);
document.getElementById("elem3").addEventListener('d3TestClick', function (e) {
console.log('PAGE1 // Page1 received click from: Page3', e);
}, false);
Run Code Online (Sandbox Code Playgroud)
PS我相信,你的方法或我的建议也不遵循最佳实践,因为它将组件紧密地耦合在一起,阻碍了可扩展性.
我认为解决这个问题的最佳方法是组件不知道是否存在任何其他组件并且由全局过滤器控制.通过这种方式,您可以拥有无限的组件,并且他们都可以以自己的方式对全局过滤器所说的内容做出反应.
在Vanilla JS中实现这一目标感觉就像是一项艰巨的任务.我可以建议使用一个框架,例如AngularJS吗?
希望这可以帮助 :)