麻烦与数学在Javascript中,当元素点击 [英] Trouble with math in Javascript, when elements clicked
问题描述
未解决
上次更新时间:下午4:15
我在
我有三个类别供人们选择:性别,年龄,种族。每个人都有自己的一套选项男/女; 35岁以下,36-64岁,65岁以上;白人,黑人,土着人,梅蒂斯人和亚洲人。
当点击其中一个选项时,数字应该从 var total
(这是MLA的数量)。我为这些数字设置了全局变量,这些变量将位于我的 index.html
文件中的 span.number
更改为说:有数量的MLA符合你的人口统计。
我被卡住了
a)我正在寻找一种更有效的方法来做Javascript中的数学运算,现在它非常好玩。如果您查看 scripts.js
中的Gender选项,我创建了一个变量 var resultMale = total - female
但是
在生成 span.number
时依赖于之前选择的选项的结果而不会很漂亮。
b)我试过使用管道布尔值,但我不清楚第二个类别Age,它包含
var resultLow = resultMale || resultFemale - (中+高)
它将如何知道在性别类别中点击/选择了什么,以便它可以做适当的数学运算。 scripts.js
$(function(){
// Numbers
var total = 56
var male = 41;
var female = 15;
var low = {}
var middle = {}
var high = {}
var white = 41
var black = 0;
var aboriginal = null;
var metis = null;
var asian = null;
// MLAs
var MLAs = [
{
Name:Nancy Allan,
Age:62,
Constuency: 圣Vital,
派对:NDP,
性别:女性,
种族:白色
},
{
Name:James Allum,
Age:null,
Constuency:Fort Garry-Riverview,
Party:NDP ,
性别:男性,
种族:Whi te
,
{
Name:Rob Altemeyer,
Age:null,
Constuency:Wolseley,
派对:NDP,
性别:男性,
种族:白色
}]
//选项#1:Gender
$(.G1).click(function(){
$(。G2)。toggleClass(disabled);
$(。headshot)。not(。Female)。toggleClass(opacity);
var resultMale = total - 女性;
$(。number)。html(resultMale);
});
$ b $(.G2).click(function(){
$(。G1)。toggleClass(disabled);
$(。headshot ).not(。Male)。toggleClass(opacity);
var resultFemale = total - male
$(。number)。html(resultFemale);
});
//选项2:年龄
$(.A1).click(function(){
$(。A2)。toggleClass(disabled );
$(。A3)。toggleClass(disabled);
$(。Low)。toggleClass(show);
var resultLow = resultMale || resultFemale - (middle + high);
$(。number)。html(?);
});
$ b $(.A2).click(function(){
$(。A1)。toggleClass(disabled);
$(。A3 ).toggleClass(disabled);
$(。Medium)。toggleClass(show);
var resultMiddle = resultMale || resultFemale - (low + high) ;
$(。number)。html(?);
});
$(.A3).click(function(){
$(。A1)。toggleClass(disabled);
$(。A2 ).toggleClass(disabled);
$(.High)。toggleClass(show);
var resultHigh = resultMale || resultFemale - (low + middle) ;
$(。number)。html(?);
});
$ b // OLD
$(.E1).click(function(){
$(.White).toggleClass(show);
var resultWhite = resultLow || resultMiddle || resultHigh - (black + aboriginal + metis + asian);
$(。number)。html(resultWhite);
}) ;
$ b $(.E2).click(function(){
$(.Black).toggleClass(show);
var resultBlack = resultLow || resultMiddle || resultHigh - (white + aboriginal + metis + asian);
$(。number)。html(0);
});
$(.E3).click(function(){
$(.Aboriginal).toggleClass(show);
var resultAboriginal = resultLow || resultMiddle || resultHigh - (white + black + metis + asian);
$(。number)。html(null);
});
$ b $(.E4).click(function(){
$(.Metis).toggleClass(show);
var resultMetis = resultLow || resultMiddle || resultHigh - (white + black + aboriginal + asian);
$(。number)。html(null);
});
$ b $(.E5).click(function(){
$(.Asian).toggleClass(show);
var resultAsian = resultLow || resultMiddle || resultHigh - (white + black + aboriginal + metis);
$(。number)。html(null);
});
$ b $选项#3:种族
// $(input [name ='ethnicity'])on(change,function(){
/ ($ checkbox.length> = 2)
// {
// var $ uncheckedbox = $(input [name ='ethnicity']:not(:checked));
// $ .each($ uncheckedbox,function(){
// $(this).attr(disabled,disabled);
//});
//}
// else
// {
// $(input [name ='ethnicity'])。removeAttr(disabled);
//}
//});
//显示带有MLA信息的弹出窗口
$(。headshot)。click(function(){
var idx = $(this).index() - 1;
$(。tooltip)。fadeIn(slow);
$(。tooltipName)。html(MLAs [idx] .Name);
$(。tooltipParty)。html(MLAs [idx] .Party);
$(。tooltipConstuency)。html(MLAs [idx] .Constuency);
$(。tooltipEthnicity ).html(MLAs [idx] .Ethnicity)+,;
$(。tooltipAge)。html(MLAs [idx] .Age);
});
//反弹并显示结果
$(。rect)。click(function(){
console.log(Bounce test);
$(。others)。fadeIn(slow);
$(。others)。effect(bounce,
{times:3},600);
});
//点击
$(。crossContainer)隐藏页脚。click(function(){
$(footer)。slideUp(slow ,function(){
console.log(没有反馈让我们难过。);
});
});
//隐藏信用
$(。credits)。hide();
});
index.html(包括span.number)
<! - 三个选项读者可以点击 - >
< section class =interactive clearfix>
< section class =selectionid =selection>
< div class =gender>
< p class =category>性别< / p>
< div class =options>
< p class =rect G1>男性< / p>
< p class =rect G2>女性< / p>
< / div><! - /.options - >
< / div><! - /.gender - >
< div class =age>
< p class =category>年龄< / p>
< div class =options>
< p class =rect A1>在35< / p>
< p class =rect A2> 36-64< / p>
< p class =rect A3> 65 +< / p>
< / div><! - /.options - >
< / div><! - /.age - >
< div class =ethnicity>
< p class =category>种族< span> *< span>< / p>
< div class =options>
< p class =rect E1 E>白色< / p>
< p class =rect E2 E>黑色< / p>
< p class =rect E3 E>原住民< / p>
< p class =rect E4 E> Metis< / p>
< p class =rect E5 E>亚洲< / p>
< / div><! - /.options - >
< / div><! - / .ethnicity - >
< / section>
< section class =others>
< h2>有< span class =number> 56< / span>适合您的人口统计的MLA< / h2>
< figcaption class =special>(不包括Pas的单个空位。)< / figcaption>
< / section>
做你想做的事。您可以在 jsFiddle 下面和这里找到代码。 (旧版本的jsfiddle,新版本见下面的编辑。)
它基本上是在做和安迪建议的。对于计算,我已经使用 UnderscoreJS 为当前点击选择的匹配键/值对使用其中
方法。然后很容易得到总长度的选择。
在演示中,我为男性,女性和民族做了这个。它应该和其他选项一样。
编辑07.02.2015
我改进了代码。现在您可以在列表中激活多个过滤器。此外,减法被删除,因为过滤的列表总是包含具有长度属性的项目数。
代码正在工作,但仍有一些要改进的地方: p>
-
removeFilter
需要更改以轻松删除过滤器,方法是指定过滤器参数 -
setFilter
改进:if(index == -1){
并非真正需要,因为在添加新过滤器之前,过滤器总是被移除。 - 为每个无线电组添加重置按钮。目前,只有一个全部重置按钮。
- 使用AngularJS更新DOM会更好,因为脚本始终在每次过滤器更改时重新创建DOM。 >
- 也许在AngularJS中,您可以检查是否有用于ng-repeat的过滤器来执行类似的行为。 >也有可能我没有测试过滤器的任何组合是否正常工作,因为我只有三个列表项目。所以你必须用代码做更多的测试。
我将代码更新到最新版本,这里是 jsFiddle 。
更多代码解释16.02.2015
功能
refreshList
和setTotal
用于更新DOM。
过滤器函数
性别
,种族
和age
在应用过滤器后返回新数组。
数组
activeFilters
存储当前选择的过滤器。它存储过滤函数,以便可以通过遍历这个数组来调用它们。稍后再详细介绍。
setFilter
方法是设置过滤器。它将过滤器添加到activeFilters
数组中,然后应用过滤器。
applyFilter 函数可能是最难理解的。它遍历 activeFilters
数组中的每个项目。如果您有两个有效的过滤器(这里是gender& ethnic),则数组activeFilters将如下所示:
activeFilters = [{
method:function(array,gender){...},
param:'male'
},{
method:function(array,ethnic){...} ,
param:'white'
}];
使用
activeFilters [0] .method(MLAs,'male')
你可以手动调用性别过滤器。这就是$ .each循环在循环内所做的这个
是{method:...,param:...}
。因此,使用this.method(filtered,this.param)
过滤器将应用于变量filtered
。
在循环之后,每个活动过滤器将被应用到数组中。
var $ total = $('#total'); var $ MLA_List = $('#MLA_List'); // MLAsvar MLAs = [{Name:Nancy Allan,Age:62,Constuency:St. Vital,Party ,性别:女性,种族:白色},{姓名:詹姆斯Allum,年龄:34,强化:加里堡江景 NDP,性别,男性,种族,黑色},{姓名:Rob Altemeyer,年龄:36,强健:Wolseley NDP,性别:男性,种族:白色}]; var filteredMLAs = MLAs.slice(0); // copy MLAsvar total = filteredMLAs.length; var refreshList = function(){var list = filteredMLAs; setTotal(list.length); $ MLA_List.empty(); $ .each(list,function(index,value){$ MLA_List.append($('< li />').text(list [index] .Name));});}; var setTotal = function (value){$ total.text(value);}; //过滤方法var gender = function(数组,性别){//console.log('gender filter called!',gender); return _.where(array,{Gender:gender});}; var ethnicity = function(array,ethnic){//console.log('ethnic filter called!',array,ethnic);返回_.where(array,{Ethnicity:ethnic});}; var age = function(array,ageRange){// 35,36-64,65+ return _.filter(array,function(MLA) {//console.log(MLA.Age); switch(ageRange){case 35:return(MLA.Age< = 35); case 36:return(MLA.Age> = 35&& MLA.Age < = 64); case 65:return(MLA.Age> = 65);}; return false;});}; var activeFilters = []; var setFilter = function(method,param){var newFilter = {方法:方法,参数:参数}; var matchedFilter = _.find(activeFilters,newFilter),index = activeFilters.indexOf(matchedFilter); if(index == -1){activeFilters.push(newFilter); } applyFilter();}; var removeFilter = function(method,param){var filter = {method:method,param:param}; var index = activeFilters.indexOf(_。find(activeFilters,filter)); if(index> -1){activeFilters.splice(index,1); } applyFilter(); //重新应用过滤器来更新列表}; var applyFilter = function(){var filtered = MLAs.slice(0); $ .each(activeFilters,function(){filtered = this.method(filtered,this.param);}); filteredMLAs =过滤?过滤:[]; click(function(){//console.log(this.id); removeFilter(gender,this.id =='Male'?'Female'); :'Male'); //删除不活动的过滤器setFilter(gender,this.id);}); $('#White,#Black')。click(function(){//console.log(this.checked ); if(this.checked)setFilter(ethnicity,this.id); //'White'); else removeFilter(ethnicity,this.id); (),); $('。Age')。click(function(){removeFilter(age,35); //改进移除所需过滤器,例如移除所有年龄过滤器removeFilter(age,36) ; removeFilter(age,65); setFilter(age,parseInt(this.value));}); $('#reset')。click(function(){//console.log('reset form'); activeFilters = []; $(':checkbox,:radio')。attr('checked',false); applyFilter();}); $(function(){refreshList();});
< script src =https://cdnjs.cloudflare.com/ajax/ libs / underscore.js / 1.7.0 / underscore-min.js>< / script>< script src =https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery .min.js>< / script> There< span id =total>< / span> < ul id =MLA_List>< / ul>< hr />< p>点击以过滤:< / p>< input type =radioid =Male男性< /输入><输入类型=复选框id =白色 > white< / input>< input type =checkboxid =Black> black< / input>< input type =radioclass =Age > 35< / input>< input type =radioclass =Agename =agevalue =36> 36-64< / input>< input type = Agename =agevalue =65> 65 +< / input>< button id =reset> reset< / button><! - < a href =#女性< / a>< a href =#id =white>白色< /& a> - >
Unsolved
Last updated: 4:15 p.m.
Where I'm at
I have three categories for people to choose: Gender, Age, Ethnicity. Each with their own set of options Male/Female; under 35, 36-64, 65+; White, Black, Aboriginal, Metis and Asian, respectively.
When one of the options is clicked, the number should subtract from
var total
(which is the number of MLAs). I've set global variables for the numbers, which changes thespan.number
located in myindex.html
file to say, "There are x-number of MLAs that fit in your demographic."Where I'm stuck
a) I'm looking for a more efficient way of doing the math in Javascript, right now it's pretty janky. If you look at the Gender option in
scripts.js
, I've created a variablevar resultMale = total - female
but it gets a lot less pretty when generatingspan.number
relies on the result of the previously selected option.b) I've tried using the pipe boolean, but I'm unclear about how in the second category "Age", which includes
var resultLow = resultMale || resultFemale -(middle + high)
how it will know what has been clicked/chosen in category "Gender" so that it can do the proper math.scripts.js
$(function() { // Numbers var total = 56 var male = 41; var female = 15; var low = {} var middle = {} var high = {} var white = 41 var black = 0; var aboriginal = null; var metis = null; var asian = null; // MLAs var MLAs = [ { "Name": "Nancy Allan", "Age": 62, "Constuency": "St. Vital", "Party": "NDP", "Gender": "Female", "Ethnicity": "White" }, { "Name": "James Allum", "Age": null, "Constuency": "Fort Garry-Riverview", "Party": "NDP", "Gender": "Male", "Ethnicity": "White" }, { "Name": "Rob Altemeyer", "Age": null, "Constuency": "Wolseley", "Party": "NDP", "Gender": "Male", "Ethnicity": "White" }] // Option #1: Gender $( ".G1" ).click(function() { $(".G2").toggleClass("disabled"); $(".headshot").not(".Female").toggleClass("opacity"); var resultMale = total - female; $(".number").html(resultMale); }); $( ".G2" ).click(function() { $(".G1").toggleClass("disabled"); $(".headshot").not(".Male").toggleClass("opacity"); var resultFemale = total - male $(".number").html(resultFemale); }); // Option #2: Age $( ".A1" ).click(function() { $(".A2").toggleClass("disabled"); $(".A3").toggleClass("disabled"); $(".Low").toggleClass("show"); var resultLow = resultMale || resultFemale - (middle + high); $(".number").html("?"); }); $( ".A2" ).click(function() { $(".A1").toggleClass("disabled"); $(".A3").toggleClass("disabled"); $(".Medium").toggleClass("show"); var resultMiddle = resultMale || resultFemale - (low + high); $(".number").html("?"); }); $( ".A3" ).click(function() { $(".A1").toggleClass("disabled"); $(".A2").toggleClass("disabled"); $(".High").toggleClass("show"); var resultHigh = resultMale || resultFemale - (low + middle); $(".number").html("?"); }); // OLD $( ".E1" ).click(function() { $( ".White" ).toggleClass("show"); var resultWhite = resultLow || resultMiddle || resultHigh - (black + aboriginal + metis + asian); $(".number").html(resultWhite); }); $( ".E2" ).click(function() { $( ".Black" ).toggleClass("show"); var resultBlack = resultLow || resultMiddle || resultHigh - (white + aboriginal + metis + asian); $(".number").html("0"); }); $( ".E3" ).click(function() { $( ".Aboriginal" ).toggleClass("show"); var resultAboriginal = resultLow || resultMiddle || resultHigh - (white + black + metis + asian); $(".number").html(null); }); $( ".E4" ).click(function() { $( ".Metis" ).toggleClass("show"); var resultMetis = resultLow || resultMiddle || resultHigh - (white + black + aboriginal + asian); $(".number").html(null); }); $( ".E5" ).click(function() { $( ".Asian" ).toggleClass("show"); var resultAsian = resultLow || resultMiddle || resultHigh - (white + black + aboriginal + metis); $(".number").html(null); }); // Option #3: Ethnicity // $("input[name='ethnicity']").on("change", function() { // var $checkedbox = $("input[name='ethnicity']:checked"); // if($checkedbox.length >= 2) // { // var $uncheckedbox = $("input[name='ethnicity']:not(:checked)"); // $.each($uncheckedbox,function() { // $(this).attr("disabled", "disabled"); // }); // } // else // { // $("input[name='ethnicity']").removeAttr("disabled"); // } // }); // Shows a popup with MLA information $(".headshot").click(function(){ var idx = $(this).index() - 1; $(".tooltip").fadeIn("slow"); $(".tooltipName").html(MLAs[idx].Name); $(".tooltipParty").html(MLAs[idx].Party); $(".tooltipConstuency").html(MLAs[idx].Constuency); $(".tooltipEthnicity").html(MLAs[idx].Ethnicity) + ","; $(".tooltipAge").html(MLAs[idx].Age); }); // Bounce and show result $(".rect").click(function(){ console.log("Bounce test"); $(".others").fadeIn("slow"); $(".others").effect( "bounce", {times:3}, 600 ); }); // This hides the footer on click $(".crossContainer").click(function(){ $("footer").slideUp("slow", function(){ console.log("No feedback makes us sad."); }); }); // This hides the credits $(".credits").hide(); });
index.html (includes span.number)
<!-- Three options readers can click --> <section class="interactive clearfix"> <section class="selection" id="selection"> <div class="gender"> <p class="category">Gender</p> <div class="options"> <p class="rect G1">Male</p> <p class="rect G2">Female</p> </div><!-- /.options --> </div><!-- /.gender --> <div class="age"> <p class="category">Age</p> <div class="options"> <p class="rect A1">Under 35</p> <p class="rect A2">36-64</p> <p class="rect A3">65+</p> </div><!-- /.options --> </div><!-- /.age --> <div class="ethnicity"> <p class="category">Ethnicity<span>*<span></p> <div class="options"> <p class="rect E1 E">White</p> <p class="rect E2 E">Black</p> <p class="rect E3 E">Aboriginal</p> <p class="rect E4 E">Metis</p> <p class="rect E5 E">Asian</p> </div><!-- /.options --> </div><!-- /.ethnicity --> </section> <section class="others"> <h2>There are <span class="number">56</span> MLAs that fit in your demographic</h2> <figcaption class="special">(Does not include the single vacant seat for the Pas.)</figcaption> </section>
解决方案If I've understood it correctly the following demo should do what you want. You can find the code below and here at jsFiddle. (old version of the jsfiddle, new version see edit below.)
It's basically doing what andi suggested. For "calculation" I have used UnderscoreJS to find the matching key/value pair for the currently clicked selection with the
where
method. Then it's easy to get the total of the selection with the length.In the demo I have done it for male, female and ethnic. It should work exactly like that for the other options.
Edit 07.02.2015
I have improved the code. Now you can activate multiple filters at your list. Also the subtraction is removed because the filtered list holds always the number of items with the length property.
The code is working but there are still some points to improve:
removeFilter
needs to be changed to easily remove the filter with-out specifing the filter parametersetFilter
improvment:if ( index == -1 ) {
is not really required because the filters are always removed before adding a new filter.- add reset buttons for each radio group. At the moment, there is only a "reset all" button.
- Using AngularJS for updating the DOM would be better because the script is always recreating the DOM at every filter change.
- Maybe with AngularJS you could check if there are filters for ng-repeat to do a similar behavior.
It's also likely that I haven't tested if any combination of the filter is working correctly, because I have only three list items. So you have to do more tests with the code.
I updated the code here to the latest version and here is the jsFiddle.
More code explanations 16.02.2015
The functions
refreshList
andsetTotal
are used to update the DOM.The filter functions
gender
,ethnicity
andage
are returning the new array after the filter is apply.The array
activeFilters
is storing the currently selected filters. It stores the filter functions so they can be called by iterating through this array. More details to this later.The
setFilter
method is setting the filter. It adds the filter to theactiveFilters
array and then it applies the filter.The
applyFilter
function is probably the hardest to understand. It iterates through each item of theactiveFilters
array. If you have two active filters (here gender & ethnic) the array activeFilters will look like this:activeFilters = [{ method: function(array, gender){...}, param: 'male' }, { method: function (array, ethnic){...}, param: 'white' }];
With
activeFilters[0].method(MLAs,'male')
you could call the gender filter manually. That's what the $.each loop is doing inside the loopthis
is{method: ..., param: ...}
. So withthis.method(filtered, this.param)
the filter will be applied to the variablefiltered
. After the loop every active filter will be applied to the array.var $total = $('#total'); var $MLA_List = $('#MLA_List'); // MLAs var MLAs = [{ "Name": "Nancy Allan", "Age": 62, "Constuency": "St. Vital", "Party": "NDP", "Gender": "Female", "Ethnicity": "White" }, { "Name": "James Allum", "Age": 34, "Constuency": "Fort Garry-Riverview", "Party": "NDP", "Gender": "Male", "Ethnicity": "Black" }, { "Name": "Rob Altemeyer", "Age": 36, "Constuency": "Wolseley", "Party": "NDP", "Gender": "Male", "Ethnicity": "White" }]; var filteredMLAs = MLAs.slice(0); // copy MLAs var total = filteredMLAs.length; var refreshList = function () { var list = filteredMLAs; setTotal(list.length); $MLA_List.empty(); $.each(list, function (index, value) { $MLA_List.append($('<li/>').text(list[index].Name)); }); }; var setTotal = function (value) { $total.text(value); }; // filter methods var gender = function (array, gender) { //console.log('gender filter called!', gender); return _.where(array, { "Gender": gender }); }; var ethnicity = function (array, ethnic) { //console.log('ethnic filter called!', array, ethnic); return _.where(array, { "Ethnicity": ethnic }); }; var age = function(array, ageRange) { //under 35, 36-64, 65+ return _.filter(array, function(MLA) { //console.log(MLA.Age); switch(ageRange) { case 35: return ( MLA.Age <= 35 ); case 36: return ( MLA.Age >= 35 && MLA.Age <= 64); case 65: return ( MLA.Age >= 65 ); }; return false; }); }; var activeFilters = []; var setFilter = function (method, param) { var newFilter = { method: method, param: param }; var matchedFilter = _.find(activeFilters, newFilter), index = activeFilters.indexOf(matchedFilter); if ( index == -1 ) { activeFilters.push(newFilter); } applyFilter(); }; var removeFilter = function(method, param) { var filter = { method: method, param: param }; var index = activeFilters.indexOf(_.find(activeFilters, filter)); if (index > -1) { activeFilters.splice(index, 1); } applyFilter(); // re-apply filter to update list }; var applyFilter = function () { var filtered = MLAs.slice(0); $.each(activeFilters, function () { filtered = this.method(filtered, this.param); }); filteredMLAs = filtered ? filtered: []; refreshList(); }; $('#Male, #Female').click(function () { //console.log(this.id); removeFilter(gender, this.id=='Male'? 'Female': 'Male'); // remove not active filter setFilter(gender, this.id); }); $('#White, #Black').click(function () { //console.log(this.checked); if ( this.checked ) setFilter(ethnicity, this.id); //'White'); else removeFilter(ethnicity, this.id); //'White'); }); $('.Age').click(function() { removeFilter(age, 35); // improvement of remove filter required, e.g. remove all age filters removeFilter(age, 36); removeFilter(age, 65); setFilter(age, parseInt(this.value)); }); $('#reset').click(function(){ //console.log('reset form'); activeFilters = []; $(':checkbox, :radio').attr('checked', false); applyFilter(); }); $(function () { refreshList(); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> There are <span id="total"></span> MLAs matching. <ul id="MLA_List"></ul> <hr/> <p>click to filter:</p> <input type="radio" id="Male" name="gender">male</input> <input type="radio" id="Female" name="gender">female</input> <input type="checkbox" id="White">white</input> <input type="checkbox" id="Black">black</input> <input type="radio" class="Age" name="age" value="35">under 35</input> <input type="radio" class="Age" name="age" value="36">36-64</input> <input type="radio" class="Age" name="age" value="65">65+</input> <button id="reset">reset</button> <!-- <a href="#" id="male">male</a> <a href="#" id="female">female</a> <a href="#" id="white">white</a> -->
这篇关于麻烦与数学在Javascript中,当元素点击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!