如何保持数据函数和变量DRY
How to keep data functions and variables DRY?
我如何使这个Jquery干?
// Adding data to input depending on what div is clicked
$('#navninfoDiv').click(function() {
$('input#webhost_navninfo').data('myData', null);
});
$('#navninfoDivP').click(function() {
$('input#webhost_navninfo').data('myData', 'p');
});
$('navninfoDivV').click(function() {
$('#inputwebhost_navninfo').data('myData', 'V');
});
// Adding data to input depending on what div is clicked
$('#prisinfoDiv').click(function() {
$('#inputwebhost_prisinfo').data('myData2', null);
});
$('#prisinfoDivP').click(function() {
$('#inputwebhost_prisinfo').data('myData2', 'p');
});
$('#prisinfoDivV').click(function() {
$('#inputwebhost_prisinfo').data('myData2', 'V');
});
// Adding data to input depending on what div is clicked
$('#cableinfoDiv').click(function() {
$('#inputwebhost_cableinfo').data('myData3', null);
});
$('#cableinfoDivP').click(function() {
$('#inputwebhost_cableinfo').data('myData3', 'p');
});
$('#prisinfoDivV').click(function() {
$('#inputwebhost_cableinfo').data('myData3', 'V');
});
// Adding data to input on submit
$('#smt').click(function() {
// for input#webhost_navninfo
var myData = $('#webhost_navninfo').data('myData'),
val = $('#webhost_navninfo').val();
if (myData) {
$('#webhost_navninfo').val(myData + val);
}
// for input#webhost_prisinfo
var myData2 = $('#webhost_prisinfo').data('myData2'),
val2 = $('#webhost_prisinfo').val();
if (myData2) {
$('#webhost_prisinfo').val(myData2 + val2);
}
// for input#webhost_cableinfo
var myData3 = $('#webhost_cableinfo').data('myData3'),
val3 = $('#webhost_cableinfo').val();
if (myData3) {
$('#webhost_navninfo').val(myData3 + val3);
}
});
我如何擦干所有这些代码?我有更多的输入字段,大约50个。
这是我的HTML和jQuery没有数据函数:http://jsfiddle.net/z5qeX/2/
我在这个例子中给出的代码示例只是为了说明我想要的功能。它与jsfiddle中的HTML不匹配,但它是我稍后要添加的代码。这是我的简单解决方案,只需很少的脚本,只要您将几个数据属性添加到所有3种类型的div中,如下所述。此外,我们可以使用mydata
作为所有类型输入的数据属性名称,而不是使用mydata
, mydata2
和mydata3
。
下面是工作演示
标记
<div id="navninfoDiv" data-type="navninfo" data-info="">navninfo</div>
<div id="navninfoDivP" data-type="navninfo" data-info="p">navninfop</div>
<div id="navninfoDivV" data-type="navninfo" data-info="V">navninfoV</div>
<div id="prisinfoDiv" data-type="prisinfo" data-info="">prisinfo</div>
<div id="prisinfoDivP" data-type="prisinfo" data-info="p">prisinfop</div>
<div id="prisinfoDivV" data-type="prisinfo" data-info="V">prisinfoV</div>
<div id="cableinfoDiv" data-type="cableinfo" data-info="">cableinfo</div>
<div id="cableinfoDivP" data-type="cableinfo" data-info="p">cableinfop</div>
<div id="cableinfoDivV" data-type="cableinfo" data-info="V">cableinfoV</div>
<input type="text" id="webhost_navninfo" />
<input type="text" id="webhost_prisinfo" />
<input type="text" id="webhost_cableinfo" />
<input type="button" id="smt" value="Submit" />
Js
$(function(){
//Adding data to input
//This will attach click event handler to all the divs
//whose id contains 'infoDiv'
$('div[id*=infoDiv]').click(function() {
$('#webhost_'+$(this).data('type')).data('myData', $(this).data('info'));
});
// Setting value to input on submit
$('#smt').click(function() {
var $this;
//This will loop through all the input fields whose id starts '
//with 'webhost and prepend data('myData') to its value
$("input[id^=webhost]").each(function(){
$this = $(this);
$this.val(($this.data("myData") || '') + $this.val());
});
});
});
我希望这对你有帮助。
这是对您提供的代码的系统细化。还有其他的解决方案(比如ShankarSangoli的),它为你提供了需要修改HTML的好的替代方案,但这应该与你现在所拥有的完全一致。
这将在多个回合中完成,所以我可以解释发生了什么。
// pass 1 you have three sets of information, the difference is the
// div which has the listener, and the default data. (I've taken the liberty to
// make all of the names consistent.
$('#navninfoDiv').click(function() {
// based on your HTML, I believe that the input# is superfluous
$('#webhost_navninfo').data('myData', null);
});
$('#navninfoDivP').click(function() {
$('#webhost_navninfo').data('myData', 'p');
});
$('navninfoDivV').click(function() {
$('#webhost_navninfo').data('myData', 'V');
});
$('#prisinfoDiv').click(function() {
$('#webhost_prisinfo').data('myData2', null);
});
/* ... */
$('#cableinfoDiv').click(function() {
$('#webhost_cableinfo').data('myData3', null);
});
/* ... */
由于您使用的是命名约定,因此循环它实际上非常简单。首先,我们将把"data"部分放在一个循环中:
var defaults = [null, "P", "V"]
for( var i = 0; i < defaults.length; i++ )
{
var divID = '#navninfoDiv' + ( defaults[i]?defaults[i]:"" );
$(divID).click(function() {
$('#webhost_navninfo').data('myData', defaults[i]);
});
}
for( i = 0; i < defaults.length; i++ )
{
var divID = '#prisinfoDiv' + ( defaults[i]?defaults[i]:"" );
$(divID).click(function() {
$('#webhost_prisinfo').data('myData2', defaults[i]);
});
}
for( i = 0; i < defaults.length; i++ )
{
var divID = '#cableinfoDiv' + ( defaults[i]?defaults[i]:"" );
$(divID).click(function() {
$('#webhost_cableinfo').data('myData3', defaults[i]);
});
}
基于此,看起来我们仍然有一些重复的代码,如果我们也循环div的ID呢?
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
var defaults = [null, "P", "V"]
for( var j = 0; j < baseIDs.length; j++ )
{
for( var i = 0; i < defaults.length; i++ )
{
var divID = '#'+baseIDs[j]+'Div' + ( defaults[i]?defaults[i]:"" );
$(divID).click(function() {
var dat = i? 'myData': 'myData' + String( i + 1 );
$('#webhost_'+baseIDs[j]).data(dat, defaults[i]);
});
}
}
那看起来不太干净。我敢打赌,把所有这些中心的东西放在自己的小函数中并不难,这将使它更容易调试,也更干净:
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
var defaults = [null, "P", "V"]
for( var j = 0; j < baseIDs.length; j++ )
{
for( var i = 0; i < defaults.length; i++ )
{
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
assignClickListener(baseIDs[j], defaults[i], datLab);
}
}
function assignClickListener(base, defaults, datLab)
{
var divID = '#'+base+'Div' + ( defaults?defaults:"" );
$(divID).click(function() {
$('#webhost_'+base).data(datLab, defaults);
});
}
那么,现在我们已经完成了脚本的第一部分。让我们看看是否有类似的方法来查看脚本的第二部分。
// I'm going to omit this until we re-unite all of the code at the end.
$('#smt').click(function() {
// so you have the same looping structure here:
var myData = $('#webhost_navninfo').data('myData'),
val = $('#webhost_navninfo').val();
if (myData) {
$('#webhost_navninfo').val(myData + val);
}
var myData2 = $('#webhost_prisinfo').data('myData2'),
/* ... */
var myData3 = $('#webhost_cableinfo').data('myData3'),
val3 = $('#webhost_cableinfo').val();
if (myData3) {
// this looks like a mistake. I will assume that it is supposed
// to be webhost_cableinfo.
$('#webhost_navninfo').val(myData3 + val3);
}
});
既然上次循环运行得很好,为什么我们不再试着做同样的事情呢?
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
for( var i = 0; i < baseIDs.length; i++ )
{
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
var currentBase = baseIDs[i];
var myData = $('#webhost_'+currentBase).data(datLab),
val = $('#webhost_'+ currentBase).val();
if (myData) {
$('#webhost_' + currentBase).val(myData + val);
}
}
哦。看起来我遗漏了一些东西——我可以重用那个ID:
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
for( var i = 0; i < baseIDs.length; i++ )
{
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
// since this is actually the ID now, I've renamed the variable.
var currentID = '#webhost_'+baseIDs[i];
var myData = $(currentID).data(datLab),
val = $(currentID).val();
if (myData) {
$(currentID).val(myData + val);
}
}
嗯…我打赌我可以缓存更多的内容:
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
for( var i = 0; i < baseIDs.length; i++ )
{
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
// I can actually cache this entire element. I'll do that:
var currentElem = $('#webhost_'+baseIDs[i]);
var myData = currentElem.data(datLab),
// val = currentElem.val(); <!-- I don't need this value, I'll just
// calculate it inline.
if (myData) {
currentElem.val(myData + currentElem.val());
}
}
好了,现在我们准备把两者结合起来,看看效果如何:
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
var defaults = [null, "P", "V"]
for( var j = 0; j < baseIDs.length; j++ )
{
for( var i = 0; i < defaults.length; i++ )
{
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
assignClickListener(baseIDs[j], defaults[i], datLab);
}
}
function assignClickListener(base, defaults, datLab)
{
var divID = '#'+base+'Div' + ( defaults?defaults:"" );
$(divID).click(function() {
$('#webhost_'+base).data(datLab, defaults);
});
}
for( i = 0; i < baseIDs.length; i++ )
{
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
var currentElem = $('#webhost_'+baseIDs[i]);
var myData = currentElem.data(datLab),
if (myData) {
currentElem.val(myData + currentElem.val());
}
}
注意到bug了吗?注意到要删除重复代码的地方吗?
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
var defaults = [null, "P", "V"]
for( var j = 0; j < baseIDs.length; j++ )
{
for( var i = 0; i < defaults.length; i++ )
{
/*
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
I really don't like this pattern. I repeat it twice. We can fix that
*/
assignClickListener(baseIDs[j], defaults[i], getDataLabel(j));
}
}
// I left this part out. That's the bug.
$('#smt').click(function() {
// make i local here. Otherwise it could be destructive
for( var i = 0; i < baseIDs.length; i++ )
{
var currentElem = $('#webhost_'+baseIDs[i]);
var myData = currentElem.data(getDataLabel( i )),
if (myData) {
currentElem.val(myData + currentElem.val());
}
}
}
function assignClickListener(base, defaultData, datLab)
{
var divID = '#'+base+'Div' + ( defaultData?defaultData:"" );
$(divID).click(function() {
$('#webhost_'+base).data(datLab, defaultData);
});
}
function getDataLabel( i )
{
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
return datLab;
}
我可以看到最后一个东西,可以很容易地删除。我们一直在查$('#webhost_<id>')
。如果这需要改变呢?不,我觉得我们应该把那个也搬出去。当我们处理它时,我们不妨缓存它:
var baseIDs = [ 'navninfo', 'prisinfo', 'cableinfo' ];
var defaults = [null, "P", "V"]
for( var j = 0; j < baseIDs.length; j++ ) {
for( var i = 0; i < defaults.length; i++ ) {
assignClickListener(baseIDs[j], defaults[i], getDataLabel(j));
}
}
$('#smt').click(function() {
for( var i = 0; i < baseIDs.length; i++ ) {
var currentElem = getHostElement(baseIDs[i]);
var myData = currentElem.data(getDataLabel( i )),
if (myData) {
currentElem.val(myData + currentElem.val());
}
}
} ); // note: this was a bug in previous iteration. I missed the );
function assignClickListener(base, defaultData, datLab) {
var divID = '#'+base+'Div' + ( defaultData?defaultData:"" );
$(divID).click(function() {
getHostElement(base).data(datLab, defaultData);
});
}
var elementCache = {}
function getHostElement( baseLab ) {
if( !elementCache[ baseLab ] )
elementCache[ baseLab ] = $('#webhost_'+baseLab);
return elementCache[ baseLab ];
}
function getDataLabel( i ) {
var datLab = 'myData'
if( i ) datLab += String( i + 1 );
return datLab;
}
现在,结果只减少了大约50%的代码行,并且更容易测试,因为它有更少的直接重复,每个块的代码更容易理解。
您的代码似乎有一些不一致,所以我做了一些假设。例如,我不确定您是否总是指$('input#webhost_navninfo')
或$('#inputwebhost_navninfo')
。
var infoDivs = ['navninfo', 'prisinfo', 'cableinfo'];
// Adding data to input depending on what div is clicked
$.each(infoDivs, function(index, divBaseName) {
var dataIndex = index + 1;
$('#' + divBaseName).click(function() {
$('#inputwebhost_' + divBaseName).data('myData' + dataIndex, null);
});
$('#' + divBaseName + 'P').click(function() {
$('#inputwebhost_' + divBaseName).data('myData' + dataIndex, 'p');
});
$('#' + divBaseName + 'V').click(function() {
$('#inputwebhost_' + divBaseName).data('myData' + dataIndex, 'v');
});
});
$('#smt').click(function() {
$.each(infoDivs, function(index, divBaseName) {
var myDataIndex = index + 1;
var elem = $('#webhost_' + divBaseName);
var myData = elem.data('myData' + myDataIndex);
var val = elem.val();
if(myData) {
elem.val(myData + val);
}
});
});
如果你不关心myData
是如何编号的,只要信息是正确的,那么你可以去掉变量dataIndex
,在两种情况下都只使用index
。
你可以试试:
var config = {
"prefix" : {
"navinfo": "",
"prisinfo": "2",
"cableinfo": "3"
},
"map" : {
"": null, // Not a 100% sure about this. Worked on Chrome for me, but should try it in IE see if it works or chokes.
"P": "p",
"V": "v"
}
};
for (section in config['prefix']) {
for (m in config['map']) {
$('#' + section+ 'Div' + m ).click(function() {
$('input#webhost_navninfo').data('myData' + config['prefix'][section], null);
});
}
}
,并对其余部分做类似的处理。在$("#smt")中。单击。
最好只定义一次这些字面量。
var divP = 'P';
var divV = 'v';
对DOM元素引用做同样的事情可以避免jQuery一次又一次地识别元素。所以它也运行得更快。
var webHostNavInfo = $('#webhost_navninfo');
var inputWebHostNavInfo = $('#inputwebhost_navninfo');
下面是第一个pass。我不知道你想走多远,但正如arunkumar指出的那样,这可能都是数据驱动的。
一些可能有帮助的问题:
- 这些数据值是否需要不同的数据键?如果没有,可以压缩。
- 可以使用类(而不是id)来标识这些元素吗?如果是这样,所有的东西都可以被一次检测,并且(也许)可以消除循环。
- 你能说出你在这里检测的行为,并将其封装到插件中吗?如果是这样,这将澄清代码和因果关系。我不明白navninfo vs. prisinfo vs. cableinfo是什么,所以我不能在逻辑上做任何事情来共享代码。
后面是更小的代码。它当然可以更多地干涸(一个创建单击处理程序的函数),但在不了解上下文的情况下,我很犹豫要这样做:
var infoDivs = ['navninfo', 'prisinfo', 'cableinfo'];
// Adding data to input depending on what div is clicked
$.each(infoDivs, function(index, divBaseName) {
var key = 'myData' + (index + 1);
var $elem = $('#inputwebhost_' + divBaseName);
$('#' + divBaseName).click(function() {
$elem.data(key, null);
});
$('#' + divBaseName + 'P').click(function() {
$elem.data(key, 'p');
});
$('#' + divBaseName + 'V').click(function() {
$elem.data(key, 'v');
});
});
$('#smt').click(function() {
$.each(infoDivs, function(index, divBaseName) {
var $elem = $('#webhost_' + divBaseName);
var myData = $elem.data('myData' + (index + 1));
var val = $elem.val();
if(myData) {
$elem.val(myData + val);
}
});
});
这里的想法是对标记进行最小的更改,并使用最少的代码实现目标。
假设你有这样的标记:
<div id="navninfoDiv">navninfo</div>
<div id="navninfoDivP">navninfop</div>
<div id="navninfoDivV">navninfoV</div>
<div id="prisinfoDiv">prisinfo</div>
<div id="prisinfoDivP">prisinfop</div>
...
我在一个容器div中重新排列为:
- 利用高效的
.delegate()
- 使选择代码更容易阅读
<div id="container">
<div id="navninfoDiv">navninfo</div>
<div id="navninfoDivP">navninfop</div>
<div id="navninfoDivV">navninfoV</div>
<div id="prisinfoDiv">prisinfo</div>
<div id="prisinfoDivP">prisinfop</div>
<div id="prisinfoDivV">prisinfoV</div>
<div id="cableinfoDiv">cableinfo</div>
<div id="cableinfoDivP">cableinfop</div>
<div id="cableinfoDivV">cableinfoV</div>
</div>
<input type="text" id="webhost_navninfo" />
<input type="text" id="webhost_prisinfo" />
<input type="text" id="webhost_cableinfo" />
<input type="button" id="smt" value="Submit" />
JS:
// if all we need is to access the data during submit,
// we can store it in an object for faster access
var submitData = submitData || {};
$(function(){
$('#container').delegate('div', 'click', function(){
// figure out our delimiter
var delimiter = 'Div',
delimiterIndex = this.id.indexOf(delimiter);
// extract type
var type = this.id.substring(0, delimiterIndex);
// extract data
var data = this.id.substring(delimiterIndex + delimiter.length);
// optional - uncomment to store null in place of empty string
// data = (data == "") ? null : data;
// assign data to appropriate type (navinfo, prisinfo etc.)
// overwrite if already there
submitData[type] = { selector: '#webhost_' + type, data: data};
});
$('#smt').click(function() {
$.each(submitData, function(key, info){
// get the input selector and its value
var $inp = $(info.selector)
val = $inp.val();
// append to existing value
$inp.val(info.data + val);
})
// comment out to perform submit
return false;
});
});
点击现场演示 !
试图保持它简单易读,并做出了所有这些假设。我希望这能使你走上正确的道路。
我喜欢Shankar的回答太简单了,因为使用了数据属性。然而,我不喜欢那些讨厌的选择器。加上对.data
包的太多调用,这是我试图避免的开销。
- 将函数的上下文应用于javascript变量
- 无法导出函数expressjs/requestjs中的变量
- 函数参数中的数据与指定变量之间的任何性能差异
- 将PHP变量传递给jQuery时遇到问题
- 如何通过ajax刷新JSF填充的javascript变量
- 参数变量出现ngTable指令问题
- 通过javascript重定向html传递php变量
- 将jsp文件下拉列表中的选定项分配给一个java变量(比如String selection)
- 全局变量和全局对象的属性之间有什么区别吗
- 如何在Bootstrap Modal中为动态点击生成的变量设置jade属性
- 值对象在某个变量发生更改后发生更改
- Javascript变量赋值|
- AngularJS-在JSON选择器中使用变量名
- Javascript计数器变量未显示正确的值
- delete关键字在全局变量上的不同行为
- 如何在php变量中嵌入JQuery代码
- ReactJS映射:如何仅在url变量不为空时呈现html链接
- 如何保持数据函数和变量DRY
- 将变量传递给指令和DRY
- 动态访问全局未定义变量(D3中的示例),DRY