jQuery 根据浏览器返回不同的顶部和左侧值

标签 jquery css animation css-position

我用 jQuery 创建了一个动画,附在这个问题上。问题是动画在以下浏览器中看起来与预期不同(见下图):

  • 火狐 49.0
  • Safari 10.0

Firefox. Not as intended!

我还尝试了其他一些浏览器,动画看起来符合预期(见下图):

  • Chrome 版本 53.0.2785.143
  • 歌剧 40.0.0.230817323

Chrome. Intended animation. Starting from the middleline and moving to the middle of the boxes

jQuery 似乎为元素提供了略微不同的位置(M1、M2、..)。如果您查看代码段中的 js 代码,我会在那里计算从起点到例如M1盒子。此信息存储在 pathsFromStartToMachines 数组中。例如,如果我将计算出的航路点记录到 M1 框中,我将根据浏览器获得略有不同的结果。

  • 火狐 -[0] 左:140px 上:143px -[1] 左:225px 上:143px
  • Chrome -[0] 左:140px 上:143px -[1] 左:228px 上:143px

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {

  $scope.machineWidth = Number($('.machine').css('width').replace(/px/, ""));
  $scope.machineHeight = Number($('.machine').css('height').replace(/px/, ""));
  //regex transform string like '343px solid rgb(47,79,79)' into '343'
  $scope.machineBorder = Number($('.machine').css('border').replace(/px\s\w+\s\w+\S\d+\S\s*\d+\S\s*\d+\S/, ""));
  $scope.machineTotalHeight = Number($scope.machineHeight + 2 * $scope.machineBorder);
  $scope.machineTotalWidth = Number($scope.machineWidth + 2 * $scope.machineBorder);

  $scope.middleLineWidth = Number($('#middleLine').css("width").replace(/px/, ""));
  $scope.middleLineTop = Number($('#middleLine').css("top").replace(/px/, ""));
  $scope.middleLineLeft = Number($('#middleLine').css("left").replace(/px/, ""));

  $scope.thicknessHorizontalLine = Number($('.horizontal').css('border-bottom').replace(/px\s\w+\s\w+\S\d+\S\s*\d+\S\s*\d+\S/, ""));

  $scope.palletHeight = 10;
  $scope.palletWidth = 30;

  $scope.startPositionMiddleLine = {
    top: $scope.middleLineTop - $scope.palletHeight,
    left: $scope.middleLineLeft
  };

  $scope.machines = [];
  $('.machine').each(function(index) {
    var id = $(this).attr("id");
    var top = Number($(this).css("top").replace(/px/, ""));
    var left = Number($(this).css("left").replace(/px/, ""));
    $scope.machines.push({
      id: id,
      top: top,
      left: left
    });
  });

  //calculate paths from start to each machine
  var pathsFromStartToMachines = [];
  for (var i = 0; i < $scope.machines.length; i++) {
    var id = $scope.machines[i].id;
    var top = undefined;
    if ($("#" + id).hasClass('first-machine-line')) {
      top = $scope.machines[i].top + $scope.machineTotalHeight;
    } else {
      top = $scope.machines[i].top - $scope.palletHeight;
    }
    var left = $scope.machines[i].left + $scope.machineTotalWidth / 2;


    var waypoints = [];
    waypoints.push($scope.startPositionMiddleLine); //starting point middleLine
    waypoints.push({
      top: $scope.middleLineTop - $scope.palletHeight,
      left: left - $scope.palletWidth / 2
    }); //waypoint on middleLine
    waypoints.push({
      top: top,
      left: left - $scope.palletWidth / 2
    });

    var path = {
      id: id,
      waypoints: waypoints
    };
    pathsFromStartToMachines.push(path)
  }

  $scope.pallets = [];

  $scope.createNewPallet = function(type, position) {
    //generate random unique id
    var id = "pallet" + generateId();
    //check if id is not already in use
    while ($scope.pallets.indexOf(id) !== -1) {
      id = "pallet" + generateId();
    }
    //add pallet to DOM
    $('#mainContainer').append('<div class="pallet" id="' + id + '" style="display:none; top:' + position.top + 'px; left:' + position.left + 'px;"></div>');
    $scope.pallets.push(id);

    //pallet fade in
    $('#' + id).fadeIn("50000");
    return id;
  };

  $scope.movePallet = function(palletId, destinationId) {
    //query path to machine. Notice that $.grep returns an array
    var path = $.grep(pathsFromStartToMachines, function(obj) {
      return obj.id === destinationId;
    });
    for (var i = 0; i < path[0].waypoints.length; i++) {
      var waypoint = path[0].waypoints[i];
      $('#' + palletId).animate({
        left: waypoint.left + 'px',
        top: waypoint.top + 'px'
      }, "slow"); //instead of slow you can use e.g. {duration: 2000}
    }
    $('#' + palletId).fadeOut("slow", function() {
      $('#' + palletId).remove();
    });
  };

  $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m1");
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m5");
  }, 1500);
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m2");
  }, 3000);
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m4");
  }, 4500);
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m3");
  }, 6000);


  function generateId() {
    //generates a random number between 1 and 10000
    return Math.floor((Math.random() * 10000) + 1);
  }
});
#mainContainer > div {
  position: absolute;
}
#mainContainer {
  position: relative;
  width: 700px;
  height: 400px;
  border: 3px solid slategrey;
  background-color: whitesmoke;
}
div.machine {
  width: 60px;
  height: 60px;
  border: 3px solid darkslategray;
  border-radius: 12px;
  text-align: center;
  vertical-align: middle;
  line-height: 60px;
  background-color: lightslategray;
  color: whitesmoke;
  font-family: Verdana, Helvetica, sans-serif;
}
.first-machine-line {
  top: 10%;
}
.second-machine-line {
  top: 50%;
}
#m1 {
  left: 30%;
}
#m2 {
  left: 50%;
}
#m3 {
  left: 70%;
}
#m4 {
  left: 30%;
}
#m5 {
  left: 50%;
}
.line {
  border: 0;
  background: lightgrey;
}
.horizontal {
  border-bottom: 2px dashed dimgrey;
}
.vertical {
  border-left: 2px dashed dimgrey;
}
#middleLine {
  width: 70%;
  top: calc((50% - 10% - 66px) / 2 + 10% + 66px);
  left: 20%;
}
.vertical-line {
  height: calc((50% - 10% - 66px) / 2);
}
.vertical-line-first-machine-line {
  top: calc(10% + 66px);
}
.vertical-line-second-machine-line {
  top: calc(10% + 66px + (50% - 10% - 66px) / 2);
}
#M1toMiddle {
  left: calc(30% + 66px / 2);
}
#M2toMiddle {
  left: calc(50% + 66px / 2);
}
#M3toMiddle {
  left: calc(70% + 66px / 2);
}
#M4toMiddle {
  left: calc(30% + 66px / 2);
}
#M5toMiddle {
  left: calc(50% + 66px / 2);
}
.pallet {
  width: 30px;
  height: 10px;
  background-color: dimgrey;
  border-radius: 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body ng-app="myApp" ng-controller="myCtrl">
  <div id="mainContainer" class="relative">

    <div class="machine first-machine-line" id="m1">M1</div>
    <div class="machine first-machine-line" id="m2">M2</div>
    <div class="machine first-machine-line" id="m3">M3</div>

    <div class="machine second-machine-line" id="m4">M4</div>
    <div class="machine second-machine-line" id="m5">M5</div>

    <div class="line horizontal" id="middleLine"></div>
    <div class="line vertical vertical-line vertical-line-first-machine-line" id="M1toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-first-machine-line" id="M2toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-first-machine-line" id="M3toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-second-machine-line" id="M4toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-second-machine-line" id="M5toMiddle"></div>

  </div>
</body>

更新:这是@ConnorsFan 在 safari(版本 10.0)中提供的解决方案的屏幕截图 enter image description here

最佳答案

“机器”div 的边框宽度在 Firefox 中未正确报告。你应该替换:

$scope.machineBorder = Number($('.machine').css('border').replace(/px\s\w+\s\w+\S\d+\S\s*\d+\S\s*\d+\S/, ""));

$scope.machineBorder = Number($('.machine').css('borderTopWidth').replace(/px/, ""));

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {

  $scope.machineWidth = Number($('.machine').css('width').replace(/px/, ""));
  $scope.machineHeight = Number($('.machine').css('height').replace(/px/, ""));
  //regex transform string like '343px solid rgb(47,79,79)' into '343'
  $scope.machineBorder = Number($('.machine').css('borderTopWidth').replace(/px/, ""));
  $scope.machineTotalHeight = Number($scope.machineHeight + 2 * $scope.machineBorder);
  $scope.machineTotalWidth = Number($scope.machineWidth + 2 * $scope.machineBorder);

  console.log($scope.machineBorder);
 
  $scope.middleLineWidth = Number($('#middleLine').css("width").replace(/px/, ""));
  $scope.middleLineTop = Number($('#middleLine').css("top").replace(/px/, ""));
  $scope.middleLineLeft = Number($('#middleLine').css("left").replace(/px/, ""));

  $scope.thicknessHorizontalLine = Number($('.horizontal').css('border-bottom').replace(/px\s\w+\s\w+\S\d+\S\s*\d+\S\s*\d+\S/, ""));

  $scope.palletHeight = 10;
  $scope.palletWidth = 30;

  $scope.startPositionMiddleLine = {
    top: $scope.middleLineTop - $scope.palletHeight,
    left: $scope.middleLineLeft
  };

  $scope.machines = [];
  $('.machine').each(function(index) {
    var id = $(this).attr("id");
    var top = Number($(this).css("top").replace(/px/, ""));
    var left = Number($(this).css("left").replace(/px/, ""));
    $scope.machines.push({
      id: id,
      top: top,
      left: left
    });
  });

  //calculate paths from start to each machine
  var pathsFromStartToMachines = [];
  for (var i = 0; i < $scope.machines.length; i++) {
    var id = $scope.machines[i].id;
    var top = undefined;
    if ($("#" + id).hasClass('first-machine-line')) {
      top = $scope.machines[i].top + $scope.machineTotalHeight;
    } else {
      top = $scope.machines[i].top - $scope.palletHeight;
    }
    var left = $scope.machines[i].left + $scope.machineTotalWidth / 2;


    var waypoints = [];
    waypoints.push($scope.startPositionMiddleLine); //starting point middleLine
    waypoints.push({
      top: $scope.middleLineTop - $scope.palletHeight,
      left: left - $scope.palletWidth / 2
    }); //waypoint on middleLine
    waypoints.push({
      top: top,
      left: left - $scope.palletWidth / 2
    });

    var path = {
      id: id,
      waypoints: waypoints
    };
    pathsFromStartToMachines.push(path)
  }

  $scope.pallets = [];

  $scope.createNewPallet = function(type, position) {
    //generate random unique id
    var id = "pallet" + generateId();
    //check if id is not already in use
    while ($scope.pallets.indexOf(id) !== -1) {
      id = "pallet" + generateId();
    }
    //add pallet to DOM
    $('#mainContainer').append('<div class="pallet" id="' + id + '" style="display:none; top:' + position.top + 'px; left:' + position.left + 'px;"></div>');
    $scope.pallets.push(id);

    //pallet fade in
    $('#' + id).fadeIn("50000");
    return id;
  };

  $scope.movePallet = function(palletId, destinationId) {
    //query path to machine. Notice that $.grep returns an array
    var path = $.grep(pathsFromStartToMachines, function(obj) {
      return obj.id === destinationId;
    });
    for (var i = 0; i < path[0].waypoints.length; i++) {
      var waypoint = path[0].waypoints[i];
      $('#' + palletId).animate({
        left: waypoint.left + 'px',
        top: waypoint.top + 'px'
      }, "slow"); //instead of slow you can use e.g. {duration: 2000}
    }
    $('#' + palletId).fadeOut("slow", function() {
      $('#' + palletId).remove();
    });
  };

  $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m1");
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m5");
  }, 1500);
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m2");
  }, 3000);
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m4");
  }, 4500);
  setTimeout(function() {
    $scope.movePallet($scope.createNewPallet(1, $scope.startPositionMiddleLine), "m3");
  }, 6000);


  function generateId() {
    //generates a random number between 1 and 10000
    return Math.floor((Math.random() * 10000) + 1);
  }
});
#mainContainer > div {
  position: absolute;
}
#mainContainer {
  position: relative;
  width: 700px;
  height: 400px;
  border: 3px solid slategrey;
  background-color: whitesmoke;
}
div.machine {
  width: 60px;
  height: 60px;
  border: 3px solid darkslategray;
  border-radius: 12px;
  text-align: center;
  vertical-align: middle;
  line-height: 60px;
  background-color: lightslategray;
  color: whitesmoke;
  font-family: Verdana, Helvetica, sans-serif;
}
.first-machine-line {
  top: 10%;
}
.second-machine-line {
  top: 50%;
}
#m1 {
  left: 30%;
}
#m2 {
  left: 50%;
}
#m3 {
  left: 70%;
}
#m4 {
  left: 30%;
}
#m5 {
  left: 50%;
}
.line {
  border: 0;
  background: lightgrey;
}
.horizontal {
  border-bottom: 2px dashed dimgrey;
}
.vertical {
  border-left: 2px dashed dimgrey;
}
#middleLine {
  width: 70%;
  top: calc((50% - 10% - 66px) / 2 + 10% + 66px);
  left: 20%;
}
.vertical-line {
  height: calc((50% - 10% - 66px) / 2);
}
.vertical-line-first-machine-line {
  top: calc(10% + 66px);
}
.vertical-line-second-machine-line {
  top: calc(10% + 66px + (50% - 10% - 66px) / 2);
}
#M1toMiddle {
  left: calc(30% + 66px / 2);
}
#M2toMiddle {
  left: calc(50% + 66px / 2);
}
#M3toMiddle {
  left: calc(70% + 66px / 2);
}
#M4toMiddle {
  left: calc(30% + 66px / 2);
}
#M5toMiddle {
  left: calc(50% + 66px / 2);
}
.pallet {
  width: 30px;
  height: 10px;
  background-color: dimgrey;
  border-radius: 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body ng-app="myApp" ng-controller="myCtrl">
  <div id="mainContainer" class="relative">

    <div class="machine first-machine-line" id="m1">M1</div>
    <div class="machine first-machine-line" id="m2">M2</div>
    <div class="machine first-machine-line" id="m3">M3</div>

    <div class="machine second-machine-line" id="m4">M4</div>
    <div class="machine second-machine-line" id="m5">M5</div>

    <div class="line horizontal" id="middleLine"></div>
    <div class="line vertical vertical-line vertical-line-first-machine-line" id="M1toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-first-machine-line" id="M2toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-first-machine-line" id="M3toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-second-machine-line" id="M4toMiddle"></div>
    <div class="line vertical vertical-line vertical-line-second-machine-line" id="M5toMiddle"></div>

  </div>
</body>


在 Safari 中测试时,线条定位不正确,托盘的起始位置位于窗口顶部。通过用 CSS 中的简单值替换 calc(...) 表达式,我获得了预期的布局和行为。结果可见this jsfiddle .例如这个样式类:

#middleLine {
  width: 70%;
  top: calc((50% - 10% - 66px) / 2 + 10% + 66px);
  left: 20%;
}

替换为:

#middleLine {
  width: 70%;
  top: 38.5%;
  left: 20%;
}

如果需要更精细的计算,另一种方法是计算代码中的值并使用 css jQuery 方法设置位置样式属性。

关于jQuery 根据浏览器返回不同的顶部和左侧值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40081526/

相关文章:

javascript - 如何使用 fabric.js Canvas 切换/选择/删除自定义形状

javascript - 更简单或更好的方法来检查 jqxgrid 是否没有要显示的数据(为空)?

jQuery:激活/悬停第一个选项卡

javascript - 响应标签的透明背景

java - 动态壁纸,帧动画,滞后

jquery - XMLHttpRequest 无法使用 jQuery 加载 URL

javascript - 是否有可能css显示:block after jquery display:none?

javascript - JQuery 搜索框自动建议 - 如何使用箭头键从建议中进行选择,同时仍保持对输入字段的关注

html - 带有CSS动画的元素方向控制

Jquery 切换自定义动画