如何通过javascript更改其中一个来交换值?

时间:2016-01-26 13:12:42

标签: javascript jquery

有三个字段的数字从1到3.我试图这样做,如果一个人只使用箭头,那么应该总是一个“1”,一个“2”和一个“3”。为什么它不总是有效,我怎么能让它起作用呢?

jQuery(document).ready(function($) {
  var prevNumber;
  $(".numbers").focus(function() {
    prevNumber = $(this).val();
  }).change(function() {
    curNumber = $(this).val();
    $('.numbers[value="' + curNumber + '"]:not(:focus)').first().val(prevNumber);
    prevNumber = curNumber;
  });
});
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

这是jsfiddle

4 个答案:

答案 0 :(得分:6)

为什么这种方法不起作用

value 属性未连接到输入值。我知道这听起来令人惊讶。 :-) value属性是输入的默认值。它不会更改(除非您使用setAttribute("value", x);.defaultValue = x;进行更改)。

您的选择器使用属性

$('.numbers[value="' + curNumber + '"]')...

因此,它将适用于输入,其值未被用户更改,但一旦输入就会失败,选择错误的输入。

如何修复它

您可以通过同时设置defaultValuevalue来更改默认值和值(确保同时更新已更改的defaultValue),就像这样(见评论):

jQuery(document).ready(function($) {
  var prevNumber;
  $(".numbers").focus(function() {
    prevNumber = $(this).val();
  }).change(function() {
    // Get the element wrapper
    var $this = $(this);
    
    // Get the current value
    var curNumber = $this.val();
    
    // Make sure the default value on this element is updated
    this.defaultValue = curNumber;
    
    // Update both the value and default value on the other
    // input that used to have this number
    $('.numbers[value="' + curNumber + '"]:not(:focus)').first().val(prevNumber).prop("defaultValue", prevNumber);
    prevNumber = curNumber;
  });
});
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

我会做什么(也许 - 你的方法在我身上发展)

我想我会在不试图记住状态的情况下接近它,例如,仅在change:获取更改的数字,然后将任何其他数字分配给其兄弟姐妹。见评论:

var numbers = $(".numbers").map(function() { return this.value; }).get();
jQuery(document).ready(function($) {
  $(".numbers").change(function() {
    // Get a wrapper for this input
    var $this = $(this);
    // Get this number
    var thisNumber = $this.val();
    // Get the unused numbers
    var unused = numbers.filter(function(num) { return num != thisNumber; });
    // Assign them to the siblings, in order
    $this.siblings().val(function(index) {
      return unused[index];
    });
  });
});
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

我保留了一般性,而不是假设值只有1,2和3(而不是假设只有三个数字)。

答案 1 :(得分:2)

代码中的问题是“value”属性包含输入的初始值。使用以下选择器时:

$('.numbers[value="' + curNumber + '"]:not(:focus)')

您正在选择最初具有给定值的元素,而现在没有此值。 请尝试使用此选择器,一切正常:

$('.numbers:not(:focus)').filter(function(index, element){ 
    return $(element).val() == curNumber; 
  })

这是jsfiddle。 ;)

答案 2 :(得分:1)

我想为您提供一个更精细的解决方案,可以在您的应用程序增长时帮助您:您应该将JS值存储在控制它的<input />之外(这样,添加多个{{1或者修改代码中的值变得更容易。最重要的是你应该有一个独立于DOM的单个可信数据存储,它总是处于有效状态(在这种情况下:没有重复)。

鉴于你的问题(值应该是唯一的,只有交换应该是可能的),它更容易处理它作为纯JS问题(并且不要尝试在jQuery中做所有事情 - 虽然我同意它&# 39;一个伟大的lib,它不一定是所有东西的最佳工具。)

以下是我评论的解决方案:

&#13;
&#13;
<input>
&#13;
jQuery(document).ready(function($) {

  // This array the current values of the inputs
  var numbers = [1, 2, 3];

  // numbers should not be modified directly but trough
  // setNumber: this function ensures that numbers is ALWAYS
  // a swap of the original value ([1, 2, 3]).
  // When a value is set, this function returns the previous
  // index of the value
  function setNumber(index, newVal) {
    // find other index
    var prevIndex = numbers.indexOf(newVal);
    if (prevIndex < 0) {
      alert('Invalid value, please enter 1, 2 or 3');
    }
    // swap
    numbers[prevIndex] = numbers[index];
    numbers[index] = newVal;
    return prevIndex;
  }

  // This function updates the inputs to ensure
  // that their displayed value match the one stored in numbers
  function updateNumbersView() {
    $(".numbers").each(function(idx, elem) {
      elem = $(elem);
      if (parseInt(elem.val(), 10) !== numbers[idx]) {
        elem.val(numbers[idx]);
      }
    });
  }

  $(".numbers").change(function() {
    var self = $(this);
    var curNumber = parseInt(self.val(), 10);
    var curIndex = $(".numbers").index(self);
    if (curNumber === numbers[curIndex]) {
      return false; // no change
    }
    
    // update model:
    var changedIndex = setNumber(curIndex, curNumber);
    
    // updateView:
    $('.numbers').eq(changedIndex).val(numbers[changedIndex]);
    
    // or to be more generic (ie. multiple inputs for the same value):
    // updateNumbersView();
    
  });

});
&#13;
&#13;
&#13;

答案 3 :(得分:1)

我会通过向每个节点添加另一个属性来解决这个问题。

&#13;
&#13;
jQuery(document).ready(function($) {
    var $numbers = $('.numbers'),
        off = false;
    $numbers.each(function () {
        this.prev = this.value;
    });
    $numbers.change(function () {
        var source = this;
        if (off) return; // this algorithm is already running
        off = true;
        $numbers.each(function () {
            if (this !== source && this.value === source.value) { // if conflict
                this.prev = this.value = source.prev; // swap with old value
            }
        });
        this.prev = this.value; // update for next time
        off = false; // re-enable
    });
});
&#13;
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
&#13;
&#13;
&#13;