如何保持数据函数和变量DRY

How to keep data functions and variables DRY?

本文关键字:变量 DRY 函数 何保持 数据      更新时间:2023-09-26

我如何使这个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, mydata2mydata3

下面是工作演示

标记

<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()
  • 使选择代码更容易阅读
HTML:

 <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包的太多调用,这是我试图避免的开销。