3

我正在使用一个名为 Gentelella 的模板,我正在尝试在其中实现 AngularJS。但是,我遇到了某个 Javascript 文件的问题。在这个文件的末尾,$(document).ready调用了一个函数来初始化 Javascript 代码,从而对 HTML 代码进行一些更改。问题是$(document).ready函数在 HTML 完全加载之前被调用得太早。

出现此问题可能是因为我正在使用 ngRoute,这会将模板 html 文件注入到 index.html 的 ng-view 中。当这种情况发生时,DOM 可能在 AngularJS 注入模板(=HTML)之前就已经宣布了一个文档准备就绪。

所以基本上,一旦 AngularJS 注入了模板,我只需要找到一种方法来调用 Javascript 文件中的一些代码。

我附上了一些代码来深入了解这个问题:

custom.min.js 的片段

$(document).ready(function () {
  init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
});

main.js 的片段:

.config(function($routeProvider, $httpProvider) {

  $routeProvider.when('/', {
    templateUrl : 'dash.html',
    controller : 'dash',
    controllerAs: 'controller'
  }).when('/login', {
    templateUrl : 'login.html',
    controller : 'navigation',
    controllerAs: 'controller'
  }).when('/plain_page', {
    templateUrl : 'plain_page.html',
    controller : 'dash',
    controllerAs: 'controller'
  }).otherwise('/');

  $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';

})

提前致谢!

4

5 回答 5

5

许多 jQuery 插件依赖于 1. 绘制 DOM 的工作流程。2. 运行一个init()函数来针对这些 DOM 元素设置代码。

该工作流程在 Angular 中表现不佳,因为 DOM 不是静态的:Angular 在其自己的生命周期中设置和销毁 DOM 节点,这可能会覆盖事件绑定或在 Angular 之外进行的 DOM 更改。当您使用 Angular 时,文档就绪并不是特别有用,因为它只表明 Angular 本身已准备好开始运行。

要有效地使用 Angular,您必须养成仅在实际需要时才启动代码的习惯。init_foo(); init_bar();因此,您应该有一个带有自己的初始化代码的 Foo 指令和一个带有自己特定的初始化代码的 Bar 指令,等等,而不是一大桶on document.ready。这些指令中的每一个都应该只修改由该特定指令创建的 DOM。这是确保需要修改的 DOM 元素确实存在并且不会在指令之间产生冲突或意外相互依赖的唯一安全方法。

举个例子:我猜你init_flot_chart()在 DOM 中爬行,寻找一个特定的元素,它会在其中绘制一个浮动图表。而不是那种自上而下的方法,而是创建一个指令:

angular.module('yourApp')
  .directive('flotWrapper', function () {
    return {
      template: "<div></div>",
      scope: {
        data: '@'
      },
      link: function(scope, elem, attrs) {
        var options = {}; // or could pass this in as an attribute if desired
        $.plot(elem, scope.data, options); // <-- this calls flot on the directive's element; no DOM crawling necessary
      }
    };
});

你像这样使用它:

<flot-wrapper data="{{theChartData}}"></flot-wrapper>

... wheretheChartData是一个包含要在图表中绘制的任何数据的对象。(您可以添加其他属性来传递您喜欢的任何其他参数,例如浮动选项、标题等)

当 Angular 绘制 flotWrapper 指令时,它首先在指令模板中创建 DOM 元素,然后link针对模板的根元素运行其函数中的任何内容。(flot 库本身可以通过一个普通的旧<script>标签包含,因此它的plot功能在指令需要时可用。)

(请注意,如果内容发生更改,这不会自动更新theChartData;可以在此处看到一个更详细的示例,它也监视更改并适当地响应。)

于 2017-05-04T14:48:34.960 回答
1

当您使用ngRoute时,您的控制器将在页面加载时运行。init()当控制器开始做任何你想做的事情时,你可以调用一个方法。

function MyCtrl($scope) {
    function init() {
        console.log('controller started!');
    }
    init();
}

作为旁注,这是John Papa Angular 指南中推荐的最佳实践。


另一种可能是使用ng-init指令,例如:

<div ng-controller="MyCtrl" ng-init="myFunction()">...</div>
于 2017-05-04T12:18:30.433 回答
0

$postLink()在最近版本的 angular.js 中有一个生命周期钩子,在这个控制器的元素和它的子元素被链接之后调用。与 post-link 函数类似,此钩子可用于设置 DOM 事件处理程序并进行直接 DOM 操作。查看指南

于 2017-07-14T09:41:16.693 回答
-1
$document.ready(function() {
  $scope.$on('$viewContentLoaded', function() {
    $timeout(function() {
      init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
    })
  })
})

更新通知:sry 伙计们,这不是一个严格的解决方案,请看我写的另一个答案

于 2017-05-04T12:26:30.523 回答
-1

这与角度摘要循环有关,它是关于角度如何在引擎盖下工作,数据绑定等。有很好的教程解释了这一点。

要解决您的问题,请使用$timeout,它将使代码在下一个周期执行:

app.controller('Controller', function ($scope, $timeout) {
    $scope.$on('$viewContentLoaded', function(event) {
      $timeout(function() {
        init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
      },0);
    });
});
于 2017-05-04T12:31:47.210 回答