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

时间:2011-08-16 16:28:06

标签: javascript jquery-ui jquery-plugins jquery

如何让这个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不匹配,但它是我想要将其添加到以后的代码。

7 个答案:

答案 0 :(得分:12)

这是我的简单解决方案,脚本非常少,只要您将所有3种类型的div添加几个数据属性,如下所述。此外,我们可以使用mydata作为所有类型输入的数据属性名称,而不是使用mydata2mydata3mydata

以下是工作 demo

<强>标记

<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());
        });
    });
});

我希望这会对你有所帮助。

答案 1 :(得分:11)

这是您提供的代码的完美改进。还有其他解决方案(如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);
});
/* ... */

由于您使用的是命名约定,因此实际上很简单。首先,我们将“数据”部分放在循环中:

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());
    }
}

注意错误?注意删除重复代码的地方?

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%的代码行,并且它更容易测试,并且由于它的直接重复次数较少,因此该代码的每个 piece 都更容易理解。

答案 2 :(得分:2)

你的代码似乎有些不一致,所以我做了一些假设。例如,我不确定您是否总是指$('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两种情况。

答案 3 :(得分:0)

你可以尝试:

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”)中。点击位。

答案 4 :(得分:0)

一次只定义所有这些文字是个好主意。

var divP = 'P';
var divV = 'v';

对DOM元素引用执行相同的操作会使jQuery不再一次地识别元素。所以它运行得更快。

var webHostNavInfo = $('#webhost_navninfo');
var inputWebHostNavInfo = $('#inputwebhost_navninfo');

答案 5 :(得分:0)

以下是第一关。我不确定你想走多远,但正如arunkumar指出的那样,它可能都是数据驱动的。

一些可能有用的问题:

  • 您是否需要为每个数据值使用不同的数据键?如果没有,可以压缩它。
  • 您可以使用类(而不是ID)来识别这些元素吗?如果是这样,一切都可以立即检测,并且(可能)消除了循环。
  • 你可以在这里命名这个行为,并将其封装到一个插件中吗?如果是这样,那将澄清代码和因果关系。我不明白whta navninfo与prisinfo对比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);
        }
    });
});

答案 6 :(得分:0)

这里的想法是对标记进行最小的更改,并以最少的代码实现目标。

假设您有以下标记:

<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;
    });
});

点击 Live Demo

试图保持简单易读,并做出所有这些假设。我希望这会让你朝着正确的方向前进。

我非常喜欢Shankar的答案,因为使用了数据属性。但是,我不喜欢那些讨厌的选择者。另外,对.data行李的调用过多,这是我试图避免的开销。