我正在构建一个简单的锻炼计划应用程序,但我想简化 Javascript/jQuery 代码

Posted

技术标签:

【中文标题】我正在构建一个简单的锻炼计划应用程序,但我想简化 Javascript/jQuery 代码【英文标题】:I'm building a simple workout program app, but I want to simplify the Javascript/jQuery code 【发布时间】:2019-01-16 07:13:18 【问题描述】:

这是我的代码

 $('#addmaxes').on('click',function()
dlMax = $('#dlcurrentmax-input').val().trim();
ftsqMax = $('#ftsqcurrentmax-input').val().trim();
per = 95;
dlTrainingMax = (dlMax * per) / 100;
frsqTrainingMax = (ftsqMax * per) / 100;
per= 75;
var weekDl = (dlTrainingMax * per) / 100;
var rnWeekDl = Math.floor(weekDl);
per2= 60;
var weekDef = (dlTrainingMax * per2) / 100;
var rnDefWeek = Math.floor(weekDef);
var weekSq = (frsqTrainingMax * per2) / 100;
var rnWeekSq = Math.floor(weekSq);
var newDivOne = $('<div>');
var newDivTwo = $('<div>');
newDivOne.addClass('trainingProgram');
newDivTwo.addClass('trainingProgram');
newDivOne.html('<h3>Week 1');
newDivTwo.html('Deadlift (75%): 3x5 at ' + rnWeekDl + '<br/>Deficit Deadlift (60%): 8x3(90sec rest between sets) at ' + rnDefWeek + '<br/>Front Squat (60%): 3x8 at ' + rnWeekSq + '<br/>Stiff-leg deadlift: 3x8 ' + '<br/>Bent over rows: 3x8' + '<br/>Lat pulldowns:  3x12');

$('#program').append(newDivOne);
$('#program').append(newDivTwo);
); 

所以基本上我多次复制并粘贴此函数并更改每个函数中添加的 html 以显示该周的锻炼。(因此每个复制的函数代表一个锻炼周) 我发现简化代码的一种方法是创建一个对象数组,如下所示:

const PERCENT_FOR_MAX = 95;
var percentagesPerWeek = [

deadlift: 75,
frontSquat: 50,
,

deadlift: 80,
frontSquat: 65,
,
/// etc
];

然后像这样在我的函数中添加一个 for 循环:

$('#addmaxes').on('click',function()
for(var i = 0; i < percentagesPerWeek.length; i++) 
dlMax = $('#dlcurrentmax-input').val().trim();
ftsqMax = $('#ftsqcurrentmax-input').val().trim();
dlTrainingMax = (dlMax * PERCENT_FOR_MAX) / 100;
frsqTrainingMax = (ftsqMax * PERCENT_FOR_MAX) / 100;
var deadliftPercent = percentagesPerWeek[i].deadlift;
var weekDl = (dlTrainingMax * deadliftPercent) / 100;
var rnWeekDl = Math.floor(weekDl);
var frontSquatPercent = percentagesPerWeek[i].frontSquat;
var weekDef = (dlTrainingMax * frontSquatPercent) / 100;
var rnDefWeek = Math.floor(weekDef);
var weekSq = (frsqTrainingMax * frontSquatPercent) / 100;
var rnWeekSq = Math.floor(weekSq);
var newDivOne = $('<div>');
var newDivTwo = $('<div>');
newDivOne.addClass('trainingProgram');
newDivTwo.addClass('trainingProgram');
newDivOne.html('<h3>Week 2</h3>');
newDivTwo.html('Deadlift ('+deadliftPercent+'%): 3x5 at ' + rnWeekDl +
  '<br/>Deficit Deadlift (65%): 8x3(90sec rest between sets) at ' + rnDefWeek +
  '<br/>Front Squat ('+frontSquatPercent+'%): 3x8 at ' + rnWeekSq +
  '<br/>Stiff-leg deadlift: 3x8 ' +
  '<br/>Bent over rows: 3x8' +
  '<br/>Lat pulldowns:  3x12'
);
$('#program').append(newDivOne);
$('#program').append(newDivTwo);
);

但我遇到的问题是每个函数中的 html 每周都将是相同的,我需要每周对其进行自定义,因为锻炼会发生变化。我怎样才能做到这一点。我是网络开发的新手,只做了一个月。所以如果我的上下文没有意义,我很抱歉,这也是我第一次在这个论坛上发帖。提前致谢。 :)

【问题讨论】:

【参考方案1】:

如果您才刚刚开始学习 javascript,请尽量避免使用 jQuery——在现代 Web 浏览器上进行 Web 开发并不需要它。此外,原生浏览器 API 的性能更高。

您的点击处理函数不必显式包含在事件侦听器中。 关注点分离 (SoC) 原则指出,您应该避免在设计/代码中将不同的关注点放在一起。这意味着您应该将处理事件的函数与触发处理程序的事件侦听器分开。

您应该将处理程序设置为您传入的命名函数,如下所示。

var addMaxesHandler = function(event) 
  // handle the '#addmaxes' click event here

  // assuming you need integer values
  var dlMax = Math.parseInt(document.getElementById('dlcurrentmax-input').value, 10);
  var ftsqMax = Math.parseInt(document.getElementById('ftsqcurrentmax-input').value, 10);
  var presentationData = doTheCalculations(percentagesPerWeek, dlMax, ftsqMax);

  presentTheResults(presentationData);
;

// attach the listener to the HTML element
var el = document.getElementById('addmaxes');
el.addEventListener('click', addMaxesHandler);

这也意味着如果您想使用removeEventListener(),您可以稍后将其删除。您不能使用匿名函数来执行此操作。

还记得单一职责原则 (SRP) 吗?在您的情况下,您应该让您的函数只执行一项任务和一项任务 - 不要将计算与演示文稿混合。不断将问题分解成更小的部分,并将结果组合在一起。

function doTheCalculations(dataArr, dl, ftsq) 

  // need a container for holding the results of calculations
  var calculationResults = [];

  // iterate through the 'percentagesPerWeek' array
  dataArr.forEach(function(values, index)
    // values is the array element e.g.  deadlift: 75, frontSquat: 50 
    // index is the array index e.g. 0 for the first element of the array
    calculationResults.push(doTheMathsFunc(values, dl, ftsq));
  );

  return calculationResults;

我还没有实现它,但doTheMathsFunc() 应该执行计算并返回一个对象或数组,其中包含要在演示文稿中使用的值。此时,您返回了另一个可用于创建 HTML 的对象数组。

function presentTheResults(resultsArr) 
  // this function will iterate through the array and build the HTML

  // use DocumentFragment object for efficiency
  var fragment = document.createDocumentFragment();

  // get some HTML content
  resultsArr.forEach(function(result, index)
    var weekFragment = getWeekHtmlBlock(result, (index + 1));
    fragment.appendChild(weekFragment);
  );

  // get a handle on the DOM container element
  var container = document.getElementById('program');

  // add the DocumentFragment to the DOM
  container.appendChild(fragment);

该函数只是将 HTML 片段拼接在一起并将结果附加到 DOM。 HTML 片段由另一个函数 getWeekHtmlBlock() 创建。

// build the block of HTML content for the week
function getWeekHtmlBlock(content, week) 
  // content : object containing the information
  // week : the week number
  var fragment = document.createDocumentFragment();
  // create HTML elements
  var outerDiv = document.createElement('div');
  var innerDiv = document.createElement('div');
  // add the CSS class
  outerDiv.classList.add('trainingProgram');
  // add the H3 tag : e.g. 'Week 1'
  var h3 = document.createElement('h3');
  h3.textContent = "Week " + week;
  outerDiv.appendChild(h3);
  // iterate through the 'content' object and build the HTML elements
  // these should be appended to 'innerDiv'

  // TO DO !
  innerDiv.appendChild( getInstructionsHtml(content, week) );

  // append the HTML elements
  outerDiv.appendChild(innerDiv);
  fragment.appendChild(outerDiv);
  // return the HTML
  return fragment;

希望现在您明白了 - 使用函数继续解决较小的问题。

如果您需要更改每周显示的说明,那么创建一个包含每个说明的对象数组可能是个好主意。数组的第一个元素将包含第一周的指令,依此类推。

Template literals/Template strings 是 ES2015 的一个特性,所以你现在应该可以利用它们了。 Deconstructing assignment 也是 ES2015 中添加的 JavaScript 特性。

// example array of instructions
var weeklyInstructionsArray = [
  [`Deadlift ($deadliftPercent%): 3x5 at $rnWeekDl`,
  `Deficit Deadlift (65%): 8x3 (90sec rest between sets) at $rnDefWeek`,
  `Front Squat ($frontSquatPercent%): 3x8 at $rnWeekSq`,
  `Stiff-leg deadlift: 3x8`,
  `Bent over rows: 3x8`,
  `Lat pulldowns: 3x12`]
];

function getInstructionsHtml(data, weekNum) 

  var instructions = weeklyInstructionsArray[weekNum-1];

  // Using deconstructing assignment
  // NOTE: The variable names must match those in the template literals above
  var deadliftPercent, rnWeekDl, rnDefWeek, frontSquatPercent, rnWeekSq = data;

  // stitch the array of template literals together in a single text node
  var htmlContent = document.createTextNode( instructions.join('<br/>') );

  return htmlContent;


希望这个答案足够详细,可以向您展示如何解决问题。

【讨论】:

以上是关于我正在构建一个简单的锻炼计划应用程序,但我想简化 Javascript/jQuery 代码的主要内容,如果未能解决你的问题,请参考以下文章

如何将默认反应上下文值设置为来自 Firestore 的数据?

使用 Prisma 的 MySQL 锻炼应用模式

核心数据架构设计

核心数据:以一对多关系存储有序值

使用 pthread 进行锻炼,但我的代码中有一些意外行为

在 MVVM 方法中简化 ICommand/RelayCommand