繁体   English   中英

在不带范围的情况下更新变量.AngularJS中的$ apply()

[英]Update variable without scope.$apply() in AngularJS

在我的项目中,画布元素显示操纵杆。 通过鼠标/触摸事件,画布将更新为看起来像用户在移动操纵杆。 这很好。 坐标保存在这样的对象中:

scope.point = {
        x: 0,
        y: 0,
    };

并且我添加了此HTML以向用户显示:

<span>X:{{point.x.toFixed(2)}} Y:{{point.y.toFixed(2)}}</span>

问题是,当scope.point.x和scope.point.y的值更改(在鼠标/触摸事件处理程序中)时,它们不会在HTML中更新。 唯一的解决方案似乎是添加:

scope.$apply()
//or
scope.$digest()

到渲染循环。 这确实有效,但看起来不佳(imho),并且使性能明显下降,正如预期的那样。

还有其他解决方案吗?

提前致谢。

PS:尽管我认为这无关紧要,但作为参考,这是事件处理程序代码和render循环:

    //handles mouse or touch movement on joystick
    scope.mouseMove = function(evt) {
        if (leftClick == 1) { //check if left mouse button down or touch
            // get cursor or touch coordinates, saved in point object.
            if (evt.type == 'touchstart' || evt.type == 'touchmove') {
                scope.point.x = evt.targetTouches[0].pageX - joystick.offsetLeft;
                scope.point.y = evt.targetTouches[0].pageY - joystick.offsetTop;
            } else {
                scope.point.x = evt.pageX - joystick.offsetLeft - 3;
                scope.point.y = evt.pageY - joystick.offsetTop - 3;
            };
            //make coordinates relative to canvas center
            scope.point = GeometrySrv.centerCoord(scope.point, joystick);
            //if Directional Lock is ON, enforce
            if (scope.lockMode != "fullAnalog") {
                scope.point = GeometrySrv.forceDirectionLock(scope.point.x, scope.point.y, scope.lockMode);
            };
            // force coordinates into maxRadius
            if (!GeometrySrv.isInsideCircle(scope.point.x, scope.point.y, maxRadius)) {
                scope.point = GeometrySrv.forceIntoCircle(scope.point.x, scope.point.y, maxRadius);
            };
            //send coordinates back to server (websocket)
            updateJoystick(scope.point, scope.lockMode);
        };
    };

    function renderLoop() {
        //erases previous joystick position
        resetJoystick();
        // erases previous vector
        resetVector();
        //change coordinates to canvas reference
        scope.point = GeometrySrv.canvasCoord(scope.point, joystick);
        DrawSrv.drawLineFromCenter(joystickctx, scope.point.x, scope.point.y);
        if (scope.showVector) {
            DrawSrv.drawLineFromCenter(vectorctx, scope.point.x * vector.width / joystick.width, scope.point.y * vector.width / joystick.width);
        };
        //redraw joystick position
        DrawSrv.drawCircle(joystickctx, scope.point.x, scope.point.y, radius, maxRadiusBGColor);
        //change back to relative coordinates
        scope.point = GeometrySrv.centerCoord(scope.point, joystick);
        //scope.$digest();
        //call renderLoop every 15ms (60fps)
        renderReq = requestAnimationFrame(renderLoop);
    };

我只是做一个过滤器,那样您仍然绑定到对象,但是您的过滤器以特定的方式显示对象。

[your angular module].filter('toFixed', [function () {
    return function (input) {
        if (typeof input.toFixed == 'function')
            return input.toFixed(2);
        return input;
    };
}]);

然后将其绑定为HTML:

<span>X:{{point.x | toFixed}} Y:{{point.y | toFixed}}</span>    

$apply内部调用$rootScope.$digest ,因此在本地范围内使用$diggest可获得更好的性能。 为了获得最佳性能,请放弃数据绑定并直接操作DOM。 您可以通过自己的angular 指令执行此操作。

了解有关$ applyAsync()的信息 -它使您可以将$ digest()循环排入队列,并每10ms进行一次节流。

知道Angular是否已经在$ digest()循环中也很聪明,这样可以避免在$ digest()完成之前调用两次$ apply()的烦人的错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM