Show loading animation for slowscript using AngularJS?

前端 未结 8 542
野的像风
野的像风 2020-12-24 12:08

In angularjs 1.2 operations like filtering an ng-repeat with many rows (>2,000 rows) can become quite slow (>1 sec).
I know I can optimize execution times u

8条回答
  •  甜味超标
    2020-12-24 12:40

    Here are the steps:

    1. First, you should use CSS animations. No JS driven animations and GIFs should be used within heavy processes bec. of the single thread limit. The animation will freeze. CSS animations are separated from the UI thread and they are supported on IE 10+ and all major browsers.
    2. Write a directive and place it outside of your ng-view with fixed positioning.
    3. Bind it to your app controller with some special flag.
    4. Toggle this directive's visibility before and after long/heavy processes. (You can even bind a text message to the directive to display some useful info to the user). -- Interacting with this or anything else directly within a loop of heavy process will take way longer time to finish. That's bad for the user!

    Directive Template:

    {{ message }}

    activity Directive:

    A simple directive with a single attribute message. Note the ng-show directive in the template above. The message is used both to toggle the activity indicator and also to set the info text for the user.

    app.directive('activity', [
        function () {
            return {
                restrict: 'EA',
                templateUrl: '/templates/activity.html',
                replace: true,
                scope: {
                    message: '@'
                },
                link: function (scope, element, attrs) {}
            };
        }
    ]);
    

    SPA HTML:

    
        
    ...

    Note that the activity directive placed outside of ng-view. It will be available on each section of your single-page-app.

    APP Controller:

    app.controller('appController',
        function ($scope, $timeout) {
            // You would better place these two methods below, inside a 
            // service or factory; so you can inject that service anywhere
            // within the app and toggle the activity indicator on/off where needed
            $scope.showActivity = function (msg) {
                $timeout(function () {
                    $scope.activityMessage = msg;
                });
            };
            $scope.hideActivity = function () {
                $timeout(function () {
                    $scope.activityMessage = '';
                }, 1000); // message will be visible at least 1 sec
            };
            // So here is how we do it:
            // "Before" the process, we set the message and the activity indicator is shown
            $scope.showActivity('Loading items...');
            var i;
            for (i = 0; i < 10000; i += 1) {
                // here goes some heavy process
            }
            // "After" the process completes, we hide the activity indicator.
            $scope.hideActivity();
        });
    

    Of course, you can use this in other places too. e.g. you can call $scope.hideActivity(); when a promise resolves. Or toggling the activity on request and response of the httpInterceptor is a good idea too.

    Example CSS:

    .activity-box {
        display: block;
        position: fixed; /* fixed position so it doesn't scroll */
        z-index: 9999; /* on top of everything else */
        width: 250px;
        margin-left: -125px; /* horizontally centered */
        left: 50%;
        top: 10px; /* displayed on the top of the page, just like Gmail's yellow info-box */
        height: 40px;
        padding: 10px;
        background-color: #f3e9b5;
        border-radius: 4px;
    }
    
    /* styles for the activity text */
    .activity-box span {
        display: block;
        position: relative;
        margin-left: 60px;
        margin-top: 10px;
        font-family: arial;
        font-size: 15px;
    }
    
    /* animating a static image */
    .activity-box img {
        display: block;
        position: absolute;
        width: 40px;
        height: 40px;
        /* Below is the key for the rotating animation */
        -webkit-animation: spin 1s infinite linear;
        -moz-animation: spin 1s infinite linear;
        -o-animation: spin 1s infinite linear;
        animation: spin 1s infinite linear;
    }
    
    /* keyframe animation defined for various browsers */
    @-moz-keyframes spin {
        0% { -moz-transform: rotate(0deg); }
        100% { -moz-transform: rotate(359deg); }
    }
    @-webkit-keyframes spin {
        0% { -webkit-transform: rotate(0deg); }
        100% { -webkit-transform: rotate(359deg); }
    }
    @-o-keyframes spin {
        0% { -o-transform: rotate(0deg); }
        100% { -o-transform: rotate(359deg); }
    }
    @-ms-keyframes spin {
        0% { -ms-transform: rotate(0deg); }
        100% { -ms-transform: rotate(359deg); }
    }
    @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(359deg); }
    }
    

    Hope this helps.

提交回复
热议问题