繁体   English   中英

$(document).ready AngularJS的替代品

[英]$(document).ready alternative for AngularJS

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

出现此问题可能是因为我正在使用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';

})

提前致谢!

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

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

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

举一个例子:我猜你的init_flot_chart()通过DOM向下搜索,寻找一个特定元素,在其中绘制一个flot图表。 而不是那种自上而下的方法,创建一个指令:

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>

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

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

(注意,如果theChartData的内容theChartData变化,这不会自动更新; 这里可以看到一个更精细的例子,它也会观察变化并做出适当的响应。)

在使用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>

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

$document.ready(function() {
  $scope.$on('$viewContentLoaded', function() {
    $timeout(function() {
      init_sparklines(), init_flot_chart(), init_sidebar(), init_wysiwyg(), init_InputMask(), ...
    })
  })
})

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

这与角度消化周期有关,它是关于角度如何在引擎盖下工作,数据绑定等。有很好的教程解释这一点。

要解决您的问题,请使用$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);
    });
});

暂无
暂无

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

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