hjzheng / CUF_meeting_knowledge_share

Record CUF team meeting knowledge share
121 stars 49 forks source link

2014-12-8 AngularJS 执行流程 | 如何使用RequireJS管理AngularJS和Dojo #20

Open hjzheng opened 9 years ago

hjzheng commented 9 years ago

AngularJS 执行流程

首先感谢慕课网提供的阿里懒懒交流会的视频,本人是受益匪浅的,这次主要是想分享由城池同学分享的AngularJS执行流程的视频

通过对AngularJS源码(基于AngularJS v1.3.3源码)的分析,将AngularJS执行流程分为三大块:

  //AngularJS源码25741 - 25747行
  bindJQuery();

  publishExternalAPI(angular);

  jqLite(document).ready(function() {
    angularInit(document, bootstrap);

bindJQuery

判断是否引入JQuery,如果没有就内置JQlite(对JQuery的轻量级实现)

publishExternalAPI

//源码1952 return moduleInstance
 var moduleInstance = {
     // Private state
     _invokeQueue: invokeQueue,
     _configBlocks: configBlocks,
     _runBlocks: runBlocks,
     requires: requires,
     name: name,
     provider: invokeLater('$provide', 'provider'),
     factory: invokeLater('$provide', 'factory'),
     service: invokeLater('$provide', 'service'),
     value: invokeLater('$provide', 'value'),
     constant: invokeLater('$provide', 'constant', 'unshift'),
     animation: invokeLater('$animateProvider', 'register'),
     filter: invokeLater('$filterProvider', 'register'),
     controller: invokeLater('$controllerProvider', 'register'),
     directive: invokeLater('$compileProvider', 'directive'),
     config: config,
 ... ...

angularInit

createInjector(modules)
//经所有provider存放在这里
provideCache: {$provider, $injector}
//如果调用过,存在这里
instanceCache: {$injector}

042315138498282

hjzheng commented 9 years ago

如何使用RequireJS管理AngularJS和Dojo

前端代码规模越来越大,为了更好的组织和管理前端代码,需要进行模块化和解耦合,提高代码的可扩展性和可维护性,AngularJS充分满足我们的需求,Angular具有模块化,MVC,双向数据绑定和指令系统四大特性,但是它的UI相对较弱,所以当项目使用AngularJS作为核心时,需要引入其他库对其UI进行增强(将dojo UI组件封装成AngularJS的指令),在这里我们选用dojo,选用dojo原因是dojo本身就是AMD模块化库,可以与RequireJS无缝集成,另外它的组件丰富且功能强大。

基于以上观点,决定选用RequireJS来管理AngularJS和Dojo,首先先明确一点,AngularJS虽然是模块化库,但是它不是AMD模块化,所以需要在RequireJS中进行特殊配置。

/**
 * Created by hjzheng on 2014/12/4.
 * This is a require config file
 */
require.config({
    baseUrl: "./",
    //dojo and dijit are AMD module, so you can easy to use require to load them
    paths: {
        'dojo': 'bower_components/dojo',
        'dijit': 'bower_components/dijit',
        'angular': 'bower_components/angular/angular',
        'angular-route': 'bower_components/angular-route/angular-route',
        'domReady': 'bower_components/domReady/domReady'
    },

    //angular does not support AMD out of the box, put it in a shim
    shim: {
        'angular': {
            exports: 'angular'
        },
        'angular-route': {
            deps: ['angular'],
            exports: 'angular-route'
        }
    },

    // kick start application
    deps: ['./js/bootstrap']
});

对AngularJS进行特殊配置后,需要手动启动AngularJS

/**
 * Created by hjzheng on 2014/12/4.
 * The whole project bootstrap by Angularjs
 */

define([
    'require',
    'angular',
    './route',
    './app'
], function (require, ng) {
    require(['domReady!'], function (document) {
        ng.bootstrap(document, ['app']);
    });
});

其它更多细节,大家自己参考我的项目 https://github.com/hjzheng/RequireJS-Dojo-AngularJS

在这里举一个简单的封装dijit/form/Button的简单例子

/**
 * Created by hjzheng on 2014/12/4.
 * This file define directive my-button
 * use dijit/form/Button
 */
define(['./module', 'dijit/form/Button'], function (directives, Button) {
    directives.directive('myButton', function () {
        return {
            restrict: 'EA',
            template: '<div></div>',
            replace: true,
            scope: {
                label: "@"
            },
            link: function ($scope, iElm, iAttrs, controller) {
                new Button({
                    label: $scope.label,
                    onClick: function () {
                        console.log("click dojo button");
                    }
                }, iElm[0]).startup();
            }
        };
    });
});
hjzheng commented 9 years ago

封装dojo组件为angular指令,需要注意两点