AngularJS scope.watch以非常慢的速度触发并错过更改

taq*_*bcn 2 javascript css android angularjs angularjs-scope

我试图将变量从控制我的侧边菜单抽屉的控制器(基于https://github.com/driftyco/ionic-ion-drawer)传递给内容的指令,以能够更改内容的不透明度侧边菜单的打开程度是成比例的。

我的第一个尝试是使用$ scope。$来完成此操作,请使用类似以下内容的方法来观察抽屉.style.transport.translate3d: 如何获得translate3d的绝对值? 但是没有成功,所以我改变了方式来获取抽屉控制器使用的当前变量。

现在的问题是,从价值20或30的outX更改中只能触发一个控制台手表。我已经看到在Codepen中最糟糕的情况是$ watch永远不会被触发,但是在直接从IntelliJ或android设备加载的浏览器中,我在日志中看到了这一点:

    Starting drag
c_menu.js:166 Offset: 16
c_menu.js:227 48 16 32 -418
c_menu.js:227 49 16 33 -417
c_menu.js:227 50 16 34 -416
c_menu.js:227 51 16 35 -415
c_menu.js:227 52 16 36 -414
c_menu.js:227 54 16 38 -412
c_menu.js:227 55 16 39 -411
c_menu.js:227 56 16 40 -410
c_menu.js:227 57 16 41 -409
c_menu.js:227 58 16 42 -408
c_menu.js:227 59 16 43 -407
c_menu.js:227 61 16 45 -405
c_menu.js:227 62 16 46 -404
c_menu.js:227 63 16 47 -403
c_menu.js:227 64 16 48 -402
c_menu.js:227 65 16 49 -401
c_menu.js:227 66 16 50 -400
c_menu.js:227 68 16 52 -398
d_menu.js:62 -398
c_menu.js:227 67 16 51 -399
c_menu.js:227 68 16 52 -398
c_menu.js:227 69 16 53 -397
c_menu.js:227 70 16 54 -396
c_menu.js:227 71 16 55 -395
c_menu.js:227 72 16 56 -394
d_menu.js:62 -394
c_menu.js:227 73 16 57 -393
c_menu.js:227 75 16 59 -391
c_menu.js:227 76 16 60 -390
c_menu.js:227 77 16 61 -389
c_menu.js:227 78 16 62 -388
c_menu.js:227 79 16 63 -387
c_menu.js:227 80 16 64 -386
d_menu.js:62 -386
c_menu.js:227 82 16 66 -384
c_menu.js:227 83 16 67 -383
c_menu.js:227 84 16 68 -382
c_menu.js:227 85 16 69 -381
c_menu.js:227 86 16 70 -380
c_menu.js:227 87 16 71 -379
d_menu.js:62 -379
c_menu.js:227 87 16 71 -379
c_menu.js:227 86 16 70 -380
c_menu.js:227 85 16 69 -381
c_menu.js:227 84 16 68 -382
c_menu.js:227 83 16 67 -383
c_menu.js:227 81 16 65 -385
c_menu.js:227 80 16 64 -386
c_menu.js:227 79 16 63 -387
c_menu.js:227 78 16 62 -388
c_menu.js:227 77 16 61 -389
d_menu.js:62 -389
c_menu.js:227 76 16 60 -390
c_menu.js:227 74 16 58 -392
c_menu.js:227 75 16 59 -391
c_menu.js:227 76 16 60 -390
c_menu.js:227 77 16 61 -389
c_menu.js:227 78 16 62 -388
c_menu.js:227 79 16 63 -387
c_menu.js:227 80 16 64 -386
d_menu.js:62 -386
c_menu.js:191 End drag
Run Code Online (Sandbox Code Playgroud)

我正在尝试做的一个小版本可以在这里找到:http : //codepen.io/taquionbcn/pen/yYZmVY?editors=101 HTML

        <link href="http://code.ionicframework.com/1.0.0/css/ionic.css" rel="stylesheet">
        <script src="http://code.ionicframework.com/1.0.0/js/ionic.bundle.js"></script>
    </head>

    <body ng-app="myapp" >
        <drawer side="left">
            <ion-content>
                <h2>Menu</h2>
                <button ng-click="closeDrawer()">Close</button>
                <ion-list>
                    <ion-item>Friends</ion-item>
                    <ion-item>Favorites</ion-item>
                    <ion-item>Search</ion-item>
                </ion-list>
            </ion-content>
        </drawer>
        <ion-pane>
            <content>
                <button ng-click="openDrawer()">Open</button>
            </content>
        </ion-pane>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

AngularJS

var app = angular.module('myapp', ['ionic'])

//'use strict';

/**
 * The ionic-contrib-frosted-glass is a fun frosted-glass effect
 * that can be used in iOS apps to give an iOS 7 frosted-glass effect
 * to any element.
 */

app.controller( 
    'drawerCtrl',
    ['$scope','$element', '$attrs', '$ionicGesture', '$document', 
     function($scope,$element, $attr, $ionicGesture, $document) {
         var el = $element[0];
         var dragging = false;
         var startX, lastX, offsetX,newX;
         $scope.outX = -1;
         var side;

         // How far to drag before triggering
         var thresholdX = 15;
         // How far from edge before triggering
         var edgeX = 40;

         var LEFT = 0;
         var RIGHT = 1;

         var isTargetDrag = false;

         var width = $element[0].clientWidth;

         var enableAnimation = function() {
             $element.addClass('animate');
         };
         var disableAnimation = function() {
             $element.removeClass('animate');
         };

         // Check if this is on target or not
         var isTarget = function(el) {
             while (el) {
                 if (el === $element[0]) {
                     return true;
                 }
                 el = el.parentNode;
             }
         };

         var startDrag = function(e) {
             disableAnimation();

             dragging = true;
             offsetX = lastX - startX;
             console.log('Starting drag');
             console.log('Offset:', offsetX);
         };

         var startTargetDrag = function(e) {
             disableAnimation();

             dragging = true;
             isTargetDrag = true;
             offsetX = lastX - startX;
             console.log('Starting target drag');
             console.log('Offset:', offsetX);
         };

         var doEndDrag = function(e) {
             startX = null;
             lastX = null;
             offsetX = null;
             isTargetDrag = false;

             if (!dragging) {
                 return;
             }

             dragging = false;

             console.log('End drag');
             enableAnimation();

             ionic.requestAnimationFrame(function() {
                 if ($scope.newX < (-width / 2)) {
                     el.style.transform = el.style.webkitTransform = 'translate3d(' + -width + 'px, 0, 0)';
                 } else {
                     el.style.transform = el.style.webkitTransform = 'translate3d(0px, 0, 0)';
                 }
             });
         };

         var doDrag = function(e) {
             if (e.defaultPrevented) {
                 return;
             }

             if (!lastX) {
                 startX = e.gesture.touches[0].pageX;
             }

             lastX = e.gesture.touches[0].pageX;

             if (!dragging) {

                 // Dragged 15 pixels and finger is by edge
                 if (Math.abs(lastX - startX) > thresholdX) {
                     if (isTarget(e.target)) {
                         startTargetDrag(e);
                     } else if (startX < edgeX) {
                         startDrag(e);
                     }
                 }
             } else {
                 //console.log(lastX, offsetX, lastX - offsetX);
                 newX = Math.min(0, (-width + (lastX - offsetX)));
                 $scope.outX =newX;
                // console.log(lastX, offsetX, lastX - offsetX,newX);
                 ionic.requestAnimationFrame(function() {
                     el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
                 });

             }

             if (dragging) {
                 e.gesture.srcEvent.preventDefault();
             }
         };

         side = $attr.side == 'left' ? LEFT : RIGHT;
         console.log(side);

         $ionicGesture.on('drag', function(e) {
             doDrag(e);
         }, $document);
         $ionicGesture.on('dragend', function(e) {
             doEndDrag(e);
         }, $document);

         this.close = function() {
             enableAnimation();
             ionic.requestAnimationFrame(function() {
                 if (side === LEFT) {
                     el.style.transform = el.style.webkitTransform = 'translate3d(-100%, 0, 0)';
                 } else {
                     el.style.transform = el.style.webkitTransform = 'translate3d(100%, 0, 0)';
                 }
             });
         };

         this.open = function() {
             enableAnimation();
             ionic.requestAnimationFrame(function() {
                 if (side === LEFT) {
                     el.style.transform = el.style.webkitTransform = 'translate3d(0%, 0, 0)';
                 } else {
                     el.style.transform = el.style.webkitTransform = 'translate3d(0%, 0, 0)';
                 }
             });
         };
     }])

app.directive('drawer', ['$rootScope', '$ionicGesture', function($rootScope, $ionicGesture) {
    return {
        restrict: 'E',
        controller: 'drawerCtrl',
        link: function($scope, $element, $attr, ctrl) {
            $element.addClass($attr.side);
            $scope.openDrawer = function() {
                console.log('open');
                ctrl.open();
            };
            $scope.closeDrawer = function() {
                console.log('close');
                ctrl.close();
            };
        }
    }
}]);

app.directive('drawerClose', ['$rootScope', function($rootScope) {
    return {
        restrict: 'A',
        link: function($scope, $element) {
            $element.bind('click', function() {
                var drawerCtrl = $element.inheritedData('$drawerController');
                drawerCtrl.close();
            });
        }
    }
}]);

app.directive('content',[ function() {
    return {
        restrict: 'E',
        //controller: 'contentCtrl',
        scope: {
            outX: '='
        },
        link: function ($scope, $element, $attr) {
            console.log($scope);
            console.log($element);
            $element[0].style.opacity = 0.5;
            $scope.$watch('outX',function(nv){
                console.log($scope.outX);
                //console.log($element);
                //console.log($scope);
            });
        }
    };
}]);
Run Code Online (Sandbox Code Playgroud)

的CSS

drawer {
  display: block;
  position: fixed;
  width: 270px;
  height: 100%;
  z-index: 100;
  background: #ffffff;
}

drawer.animate {
  -webkit-transition: 0.4s all ease-in-out;
  transition: 0.4s all ease-in-out;
}

drawer.left {
  -webkit-transform: translate3d(-100%, 0, 0);
  transform: translate3d(-100%, 0, 0);
  box-shadow: 1px 0px 10px rgba(0,0,0,0.3);
}
drawer.right {
  right: 0;
  top: 0;
  -webkit-transform: translate3d(100%, 0, 0);
  transform: translate3d(100%, 0, 0);
  box-shadow: -1px 0px 10px rgba(0,0,0,0.3);
}
Run Code Online (Sandbox Code Playgroud)

编辑:

一段时间后,我又回到了这个话题,并且对离子,角度和所有这些东西有了更多的了解,我已经采取了一些方法。

对于黑屏,因为我将有多个侧面菜单,并且我决定在车身上使用与侧面菜单和ion-nav-view平行的窗口:

<darkscreen class="darkscreen" id="iddarkscreen"></darkscreen>
Run Code Online (Sandbox Code Playgroud)

其指令:

menu.directive('darkscreen',function(){
    return{
        restrict: 'E',
        link : function($scope,$element,$attr){
            console.log(arguments)
        },
        controller: function($scope,$interval,operativeDB){
            console.log(arguments);
            var iddarkscreen = document.getElementById("iddarkscreen");

            $scope.getdarkvalue = function(){
                //console.log(JSON.stringify(operativeDB.getmov()));
                return operativeDB.getdark();
            };

            $scope.$watch($scope.getdarkvalue,function(newVal){
                if(newVal > 0) iddarkscreen.style.visibility = 'visible'; else iddarkscreen.style.visibility = 'hidden';
            },true);
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

和CSS:

.darkscreen {
    z-index: 50;
    background-color: black;
    position: absolute;
    height: 100%;
    width: 100%;
    opacity: .7;
    transition: opacity 300ms ease-in-out;
}
Run Code Online (Sandbox Code Playgroud)

下一步是将getdarkvalue函数的z-index参数修改为始终位于目标下方,并掩盖其余部分。最后一步是使不透明度渐进

tas*_*ATT 5

通过附加的侦听器功能$ionicGesture.on在Angular上下文之外执行,并且不会触发摘要循环,这意味着观察者将看不到任何更改。

如果$scope.$apply()doDrag函数内部添加,您将注意到观察者将开始看到更改。

我不会推荐这个。由于该doDrag函数执行了很多次,因此确实会使应用程序同样多次执行摘要循环,特别是在大型应用程序和移动设备上,这会给应用程序造成负担。

在这种情况下,我建议使用的指令是侦听拖动事件并直接修改元素的不透明度,而不是依赖于摘要循环和Angular的数据绑定。