本文将分享angularJS+requireJS实现controller及directive的按需加载的详细内容,此外,我们还将为大家带来关于AngularDirective:linkvscompil
本文将分享angularJS+requireJS实现controller及directive的按需加载的详细内容,此外,我们还将为大家带来关于Angular Directive: link vs compile vs controller、Angular JS + Require JS 实现按需加载、Angular 学习心得之 directive——require 选项的细节、angular.js指令(directive)中的controller,compile,link函数有什么不同?的相关知识,希望对你有所帮助。
本文目录一览:- angularJS+requireJS实现controller及directive的按需加载
- Angular Directive: link vs compile vs controller
- Angular JS + Require JS 实现按需加载
- Angular 学习心得之 directive——require 选项的细节
- angular.js指令(directive)中的controller,compile,link函数有什么不同?
angularJS+requireJS实现controller及directive的按需加载
最近因为项目的比较大,需要加载的js文件较多,为了提高首屏页面的加载速度,需要对js文件进行按需加载,然后网上参考了一些资料,自己也深入研究一番之后,实现了按需加载控制器js文件及指令js文件的效果;思路如下,1、借助ui-router里面的resolve属性来实现预加载,2、需要借助$controllerProvider动态去注册控制器,$compileProvider动态去注册指令,3、需要借助$q来帮助我们实现异步加载,具体步骤如下所示;
1、在我们定义的app(在定义app.config()的js文件内)模块上挂载注册控制器和指令的属性,如下所示
app.register = {
//注意这里的$controllerProvider是内置注册控制器的属性,$compileProvider是内置的注册指令的属性 controller: $controllerProvider.register,directive: $compileProvider.directive }
2、借助$q定义一个异步加载js文件的方法(在定义路由的js文件内)
app.loadMyJs = function(js){ return function($rootScope,$q){ var deffer = $q.defer(),deps=[]; angular.isArray(js) ? (deps = js) : deps.push(js); require(deps,function(){ $rootScope.$apply(function(){ deffer.resolve(); }); }); return deffer.promise; }; }
3、借助路由里面的resolve属性,进行配置需要加载的控制器文件及指令文件(在定义路由的js文件内)
.state('view1',{ url: '/view1',templateUrl: 'temp/partial1.html',controller: 'MyCtrl1',resolve:{
//需要动态加载的控制器及指令js文件,其它js文件以此类推 deps:app.loadMyJs(['./controllers/my-ctrl-1','./directives/loading']) } })
4、通过第一步先挂载在app上的属性来进行动态注册控制器or指令
//注册控制器(对应的控制器js文件内)
app.register.controller('MyCtrl1',function ($scope,$css,$rootScope) { //控制器里面的内容 });
//注册指令(对应的指令js文件内)
app.register.directive("loading",function (){
return {
restrict: "AE",
replace: true,
template: "<divng-show='isLoading'><span>loading</span></div>"
}
});
如果有服务or过滤器需要按需加载也是类似的方法,另外如果是公共的服务,指令or过滤器等不需要进行按需加载的文件就可以使用普通的angular.module()的方式来定义即可;
最后这只是实现按需加载js文件中的一种思路,希望对您有所帮助。
Angular Directive: link vs compile vs controller
Compile :
This is the phase where Angular actually compiles your directive. This compile function is called just once for each references to the given directive. For example, say you are using the ng-repeat directive. ng-repeat will have to look up the element it is attached to, extract the html fragment that it is attached to and create a template function.
If you have used HandleBars, underscore templates or equivalent, its like compiling their templates to extract out a template function. To this template function you pass data and the return value of that function is the html with the data in the right places.
The compilation phase is that step in Angular which returns the template function. This template function in angular is called the linking function.
Linking phase :
The linking phase is where you attach the data ( $scope ) to the linking function and it should return you the linked html. Since the directive also specifies where this html goes or what it changes, it is already good to go. This is the function where you want to make changes to the linked html, i.e the html that already has the data attached to it. In angular if you write code in the linking function its generally the post-link function (by default). It is kind of a callback that gets called after the linking function has linked the data with the template.
Controller :
The controller is a place where you put in some directive specific logic. This logic can go into the linking function as well, but then you would have to put that logic on the scope to make it "shareable". The problem with that is that you would then be corrupting the scope with your directives stuff which is not really something that is expected. So what is the alternative if two Directives want to talk to each other / co-operate with each other? Ofcourse you could put all that logic into a service and then make both these directives depend on that service but that just brings in one more dependency. The alternative is to provide a Controller for this scope ( usually isolate scope ? ) and then this controller is injected into another directive when that directive "requires" the other one. See tabs and panes on the first page of angularjs.org for an example.
Angular JS + Require JS 实现按需加载
先看下目录结构,为了方便配置将所有文件放在同一文件夹下,实际使用过程中建议归类文件:
1.index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>require angularjs</title>
</head>
<body>
<a href="#module1" rel="external nofollow" >module1</a><br/>
<a href="#module2" rel="external nofollow" >module2</a>
<div style="height: 30px;width: 100px">{{str}}</div>
<div id="container" ui-view></div>
<script data-main="main.js" src="require.js" id="main"></script>
</body>
</html>
2.main.js
var config = {
baseUrl: ''./'', //依赖相对路径
paths: { //如果某个前缀的依赖不是按照baseUrl拼接这么简单,就需要在这里指出
angular: ''angular'',
app:''app'',
router:''angular-ui-router''
},
shim: { //引入没有使用requirejs模块写法的类库。例如underscore这个类库,本来会有一个全局变量''_''。这里shim等于快速定义一个模块,把原来的全局变量''_''封装在局部,并导出为一个exports,变成跟普通requirejs模块一样
''router'': {
deps: [''angular''], //依赖什么模块
},
''angular'': {
exports: ''angular''
}
}
};
require.config(config);
// deps:[''webapp'']
require([''app'',''angular''],function(){
angular.bootstrap(document, [''webapp''])//这里会去执行app.js这个文件
})
3.app.js
define([''router''], function () {
var app = angular.module(''webapp'', [''ui.router'']);
app.config(
function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise(''module1'');
$stateProvider.
state(''module1'', {
url:"/module1",
// controller: ''ctr1'',
templateUrl: ''./module1.html'',
resolve: {
loadCtrl: ["$q", function($q) {
var deferred = $q.defer();
require([
''./module1''
], function() { deferred.resolve(); });
return deferred.promise;
}]
}
})
.state("module2",{
url:"/module2",
// controller: ''ctr2'',
templateUrl: ''./module2.html'',
resolve: {
loadCtrl: ["$q", function($q) {
var deferred = $q.defer();
require([
''./module2''
], function() { deferred.resolve(); });
return deferred.promise;
}]
}
})
});
app.config(function($controllerProvider,$compileProvider,$filterProvider,$provide){
app.register = {
controller : $controllerProvider.register,
directive: $compileProvider.directive,
filter: $compileProvider.register,
service: $provide.service
};
})
return app;
});
4.module1.html
<div ng-controller="ctr1">
5.module2.html
<div ng-controller="ctr2">
{{str}}
</div>
6.module1.js
define([''app''],function(app){
app.register
.controller(''ctr1'', function($scope){
$scope.str = ''home page'';
console.log(''page1'')
})
})
7.module2.js
define([''app''],function(app){
app.register
.controller(''ctr2'',function($scope){
$scope.str = ''local page'';
console.log(''page2'')
})
})
8.server.js (node 服务)
var url = require("url"),
fs=require("fs"),
http=require("http"),
path = require("path");
http.createServer(function (req, res) {
var pathname=__dirname+url.parse(req.url).pathname;
if (path.extname(pathname)=="") {
pathname+="/";
}
if (pathname.charAt(pathname.length-1)=="/"){
pathname+="index.html";
}
fs.exists(pathname,function(exists){
if(exists){
switch(path.extname(pathname)){
case ".html":
res.writeHead(200, {"Content-Type": "text/html"});
break;
case ".js":
res.writeHead(200, {"Content-Type": "text/javascript"});
break;
case ".css":
res.writeHead(200, {"Content-Type": "text/css"});
break;
case ".gif":
res.writeHead(200, {"Content-Type": "image/gif"});
break;
case ".jpg":
res.writeHead(200, {"Content-Type": "image/jpeg"});
break;
case ".png":
res.writeHead(200, {"Content-Type": "image/png"});
break;
default:
res.writeHead(200, {"Content-Type": "application/octet-stream"});
}
fs.readFile(pathname,function (err,data){
res.end(data);
});
} else {
res.writeHead(404, {"Content-Type": "text/html"});
res.end("<h1>404 Not Found</h1>");
}
});
}).listen(5000);
console.log("Server running at localhost");
参考地址:https://www.jb51.net/article/115695.htm
Angular 学习心得之 directive——require 选项的细节
谈 require 选项之前,应该先说说 controller 选项,controller 选项允许指令对其他指令提供一个类似接口的功能,只要别的指令(甚至是自己)有需要,就可以获取该 controller,将其作为一个对象,并取得其中的所有内容。而 require 就是连接两个指令的锁链,它可以选择性地获取指令中已经定义好的 controller,并作为 link 函数的第四个参数传递进去,link 函数的四个参数分别为 scope,element,attr 和 someCtrl,最后一个就是通过 require 获取的 controller 的名字,对于 controller 的名字,可以在指令中用 controllerAs 选项进行定义,这是发布控制器的关键.
具体如何获取 controller 呢?require 选项的值可以分别用前缀?、^ 和?^ 进行修饰,也可以不修饰。
如果不进行修饰,比如 require:''thisDirective'',那么 require 只会在当前指令中查找控制器
如果想要指向上游的指令,那么就是用 ^ 进行修饰,比如 require:''^parentDirective'',如果没有找到,那就会抛出一个错误。
如果使用?前缀,就意味着如果在当前指令没有找到控制器,就将 null 作为 link 的第四个参数;
那么,如果将?和 ^ 结合起来,我们就可以既指定上游指令,又可以在找不到时,不抛出严重的错误。
现在问题来了,如果我想指定多于一个指令,那怎么办呢?这时,我们可以将需要的指令放进一个数组中,例如:require:[''^?firstDirective'',''^?secondDirective'',''thisDirective''],这不正是依赖注入的形式吗?但要注意一点,如果使用这种写法的话,原先指令中发布的控制器的名字,即 controllerAs 选项,就失去意义了。此时,我们在 link 中调用这些指令的 controller 的方法变为:先为上边的数组定义一个名字,接着根据其下标号来指定具体的某个指令。类似于:ctrlList [0]。
好,准备工作完毕,接下来通过一个大杂烩的实例来实践 require 选项。我想实现的效果是,在主指令中,分别指定父级指令中的增加与减少的操作。
JS 代码:
增加操作的指令:
.directive("add",function(){
return{
restrict:''ECMA'',
controller:function($scope){
$scope.count=0;
this.addCount=function(){
$scope.$apply(function(){
$scope.count++;
})
}
}
}
})
减少操作的指令:
.directive("minor",function(){
return{
restrict:''ECAM'',
controller:function($scope){
this.reduceCount=function(){
$scope.$apply(function(){
$scope.count--;
})
}
}
}
})
主指令:
.directive("figure",function(){
return{
restrict:''ECMA'',
template:''<button id="add" >增加</button>''+
''<button id="minor" >减少</button>''+
''<div>{{ figureCtrl.temp }}</div>'',
require:[''?^add'',''?^minor''],
controller:function(){
this.temp="这个属性被隔离开,可通过controllerAs创建的动态对象调用";
},
controllerAs:''figureCtrl'',
link:function(scope,element,attrs,resultCtrl){
angular.element(document.querySelector(''#minor'')).on(''click'',resultCtrl[1].reduceCount);
angular.element(document.querySelector(''#add'')).on(''click'',resultCtrl[0].addCount);
}
}
})
HTML 代码:
<add minor class="col-md-2 col-md-offset-3">
<div >次数: {{ count }}</div>
<figure></figure>
</add>
运行结果如下图:
注意点:
1. 由于 add 和 minor 指令都已被注入 resultCtrl 数组中,所以想调用它们的控制器中的方法,就可以使用 resultCtrl [i].fun () 的方式;
2. 更新 count 的值,但视图是不会改变的,所以需要通过手动 $apply () 的方式来更新;
3.controllerAs 实际上是把 controller 创建为一个对象,并且是隔离的。
大功告成!但还是希望大神们能毫不吝啬地对我的文章进行指点和纠正,谢谢!
angular.js指令(directive)中的controller,compile,link函数有什么不同?
今天我们来一起了解一下它们有什么不同的地方:
var ag = angular.module("myApp",[]);
ag.controller("myCtrl",["$rootScope",function($rootScope){
}]);
ag.directive("order",function(){
return{
restrict:"AE",
controller:function($scope, $element, $attrs, $transclude) {
console.log("controller");
},
compile:function(tElement, tAttrs, transclude){
console.log("compile");
return{
pre:function(scope, iElement, iAttrs, controller){
console.log("pre")
},
post:function(scope, iElement, iAttrs, controller){
console.log("post")
}
}
},
link:function(scope, iElement, iAttrs, controller){
console.log("link")
}
}
});
我们可以看到什么order指令中写了controller, complie, link函数;我们可以思考一下上面会输出一下什么来.
从上面的输出结果我们可以得出两个结论: 他们的执行顺序不同,最先执行的是complie函数 ; 然后是controller函数,然后是pre函数,最后是post函数. link函数没有执行. 首先我们来解释第一个问题;看下图(摘自stackoverflow.com)
从图中我们可以看到整个 AngularJs 的生命周期;分为两个阶段: 第一个阶段是编译阶段:
在编译阶段,AngularJS会遍历整个HTML文档并根据JavaScript中的指令定义来处理页面上声明的指令。每一个指令的模板中都可能含有另外一个指令,另外一个指令也可能会有自己的模板。当AngularJS调用HTML文档根部的指令时,会遍历其中所有的模板,模板中也可能包含带有模板的指令.一旦对指令和其中的子模板进行遍历或编译,编译后的模板会返回一个叫做模板函数的函数。我们有机会在指令的模板函数被返回前,对编译后的DOM树进行修改。
ag.directive("order",function(){
return{
restrict:"AE",
compile:function(tELe ,tAttrs,transcludeFn){
//进行编译后的dom操作
return{
pre:function(scope, iElement, iAttrs, controller){
// 在子元素被链接之前执行
// 在这里进行Dom转换不安全
},
post:function(scope, iElement, iAttrs, controller){
// 在子元素被链接之后执行
}
}
}
}
})
第二个阶段是链接阶段:链接函数来将模板与作用域链接起来;负责设置事件监听器,监视数据变化和实时的操作DOM.链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义了时,编译函数会重载链接函数.(解释上面的结论2)
var ag = angular.module("myApp",[]);
ag.controller("myCtrl",["$rootScope",function($rootScope){
}]);
ag.directive("order",function(){
return{
restrict:"AE",
controller:function($scope, $element, $attrs, $transclude) {
console.log("controller");
},
link:function(scope, iElement, iAttrs, controller){
console.log("link")
}
}
});
上面指令执行时;会输出:
我们可以看到controller函数先执行,然后是link函数.但是链接阶段会执行controller,link函数;那么他们有什么不同;我们在什么情况该用哪个? 答案是: 指令的控制器和link函数可以进行互换。控制器主要是用来提供可在指令间复用的行为,但链接函数只能在当前内部指令中定义行为,且无法在指令间复用.link函数可以将指令互相隔离开来,而controller则定义可复用的行为。 实际使用的一些建议: 如果我们希望将当前指令的API暴露给其他指令使用,可以使用controller参数,否则可以使用link来构造当前指令元素的功能性。如果我们使用了scope.$watch()或者想要与DOM元素做实时的交互,使用链接会是更好的选择。 到这里:我们应该有一点了解这三者有什么差异了吧?其实这个问题考的就是我们对AngularJs生命周期的了解. 最后我们用一个实际例子来看一下AngularJs的生命周期:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<div parent>
<div child></div>
</div>
<script src="../plugins/angularjs/angular.src.js"></script>
<script>
var ag = angular.module("myApp",[]);
ag.controller("myCtrl",["$rootScope",function($rootScope){
}]);
ag.directive("parent",function(){
return{
restrict:"AE",
controller:function($scope, $element, $attrs, $transclude) {
console.log("parent controller");
},
compile:function(tElement, tAttrs, transclude){
console.log("parent compile");
return{
pre:function(scope, iElement, iAttrs, controller){
console.log("parent pre")
},
post:function(scope, iElement, iAttrs, controller){
console.log("parent post")
}
}
}
}
});
ag.directive("child",function(){
return{
restrict:"AE",
controller:function($scope, $element, $attrs, $transclude) {
console.log("child controller");
},
compile:function(tElement, tAttrs, transclude){
console.log("child compile");
return{
pre:function(scope, iElement, iAttrs, controller){
console.log("child pre")
},
post:function(scope, iElement, iAttrs, controller){
console.log("child post")
}
}
}
}
});
</script>
</body>
</html>
结果如图:
可以参照上面的angularjs生命周期图来理解.
今天关于angularJS+requireJS实现controller及directive的按需加载的讲解已经结束,谢谢您的阅读,如果想了解更多关于Angular Directive: link vs compile vs controller、Angular JS + Require JS 实现按需加载、Angular 学习心得之 directive——require 选项的细节、angular.js指令(directive)中的controller,compile,link函数有什么不同?的相关知识,请在本站搜索。
本文标签: