另类angularjs应用

回顾

  上一篇文章主要讲解了创建兼容任意浏览器(主要是ie的一些奇葩问题)的angularjs web应用,但是项目开发中其实更重要的还是在功能的模块化、代码自动压缩上面,这样项目在后期维护或者功能的重复利用上才会更方便,那么今天主要围绕以下几个主题来讲讲如何在不是用其他js模块化库的情况下,开发便于管理的angualrjs模块化代码:

  • 使用service来创建模块
  • 模块间引用
  • 代码合并及压缩

  本文中的代码均已nodejs来实现。

  nodejs中,使用UglifyJS2来实现代码压缩

使用service来创建模块

  以前创建angualrjs应用都是直接基于对scope的直接绑定来完成的,例如:登录功能,代码如下:

//html
<div ng-controller="loginController">
    <div>
        用户名:
        <input type="text" ng-model="name" />
    </div>
    <div>
        密 码:
        <input type="password" ng-model="pwd" />
    </div>
    <a href="javascript:void(0)" ng-click="login()">
        登录
    </a>
</div>

//js
var myApp = angular.module(‘myApp‘, []);
myApp.controller(‘loginController‘, function ($scope) {
    $scope.name = ‘‘;
    $scope.pwd = ‘‘;

    $scope.login = function () {
        //代码略
    };
});

  当有很多的功能的时候,有些人可能会创建很多的controller来完成,也有些人会像我一样,使用一些js模块化库(seajs\requirejs)来实现,但是整合js模块化库会带来一些问题,而且效果也不尽人意,代码也会变得很复杂。

  鉴于以上的一些问题,我不得不寻找一些其他的方案来替代,于是后来就想到了使用service来替代模块化(可能是资质比较差的原因吧),这样便可以充分利用angularjs的特性来完成,首先创建一个user的service,其实就是将当前scope内的代码迁移到user.js内,代码如下:

myApp.service(‘user‘, function () {
    function User() {
        this.name = ‘‘;
        this.pwd = ‘‘;
    }

    User.prototype.login = function () {
        //代码略
    };

    return new User();
});

  然后只要稍微修改一下上面的代码便可以实现这个功能了,改完代码如下:

//html
<div ng-controller="loginController">
    <div>
        用户名:
        <input type="text" ng-model="user.name" />
    </div>
    <div>
        密 码:
        <input type="password" ng-model="user.pwd" />
    </div>
    <a href="javascript:void(0)" ng-click="user.login()">
        登录
    </a>
</div>

//js
myApp.controller(‘loginController‘, function ($scope, user) {
    $scope.user = user;
});

  使用这种方法,功能开发就简单多了,只要将功能的代码变成一个个的js,然后页面上引用后在controller初始化的时候,一个个绑定到scope上就可以了。

模块间引用

  项目开发当中,免不了模块之间的交互,由于以上我们只用了service来创建模块,而angularjs的service跟许多js模块化库是一样的,不允许模块之间的循环引用,这样如果我们有一个user和userAddress,当user需要引用userAddress的时候就会遇到一些问题。

  遇到此类问题的时候,其实可以引入一个类似缓存的模块来解决,首先将所有的功能模块都加入到缓存模块中(controller内),然后当user模块需要引用到userAddress模块的时候,只要引用缓存模块并从其开放的接口中获取userAddress模块即可。

  其实缓存模块就只要有2个方法(get\set),大致代码如下:

myApp.controller(‘loginController‘, function ($scope, cache, user, userAddress) {
    $scope.user = user;
    $scope.userAddress = userAddress;

    caceh.set(‘user‘, user);
    caceh.set(‘userAddress‘, userAddress);
});

//user
myApp.service(‘user‘, function(cache) {
    //需要引用的时候
    var userAddress = cache.get(‘userAddress‘);
    //其他代码省略
});

代码合并及压缩

  当功能模块越来越多的时候,controller内就会有很多类似的代码了,而且每增加一个js模块,都需要在controller内注册并添加到cache中去,实在是很麻烦。

  其实大家应该已经发现了,只要我们将模块放在同一的文件夹内,然后通过扫描这个文件夹,并使用模板来进行代码生成就可以免去这些麻烦的注册代码了,代码如下:

//模板
window.myApp= angular.module(‘myApp‘, []);

myApp.controller(‘mainController‘, function ($scope, cache, <%= modules.join(‘, ‘) %>){
    <% modules.forEach(function (m){ %>
    $scope.<%= m %> = <%= m %>;
    cache.set(‘<%= m %>‘, <%= m %>);
    <% }) %>
});
<% codes.forEach(function (c){ %>
<%- code %>
<% }) %>

//合并
var ejs = require(‘ejs‘);
var fs = require(‘fs‘);
var path = require(‘path‘);
var jsDir = ‘js文件夹路径‘;
var codes = [];
var modules = [];
fs.readdirSync(jsDir).forEach(function (filename) {
    if (filename.indexOf(‘.js‘) == -1)
        return;

    codes.push(fs.readFileSync(path.join(jsDir, filename), ‘utf8‘));
    modules.push(filename.replace(‘.js‘, ‘‘));
});

var tplCode = fs.readFileSync(‘模板路径‘, ‘utf8‘);
codes.unshift(ejs.render(tplCode, {
    modules: modules,
    codes: codes
}));

fs.writeFileSync(‘整合后的js文件路径‘, codes.join(‘\r\n‘), ‘utf8‘);

  这样我们便可以在js文件变化的时候,通过合并所有的js,但是这里要注意将功能模块的js和公用库的js放在不同的文件夹下,引用公用代码并不会去引用功能模块,因此不需要加入到cache中去,并在合并的时候通过额外的代码去拼接公用js。

  通过以上的操作,我们只需要在页面上只引入一个js,这样开发起来也会比较方便,但是测试的时候,就略微麻烦。

  在这里我建议将angularjs创建module和controller的生成代码独立放在一个生成模块中,并生成一个js(如:config);将合并公用js和模块js放在另一个生成模块中;并在项目中添加一个诸如development的变量来标识是否为开发模式。

  开发模式的时候,页面上引用生成的config及其他公用js和功能js;非开发者模式下,则引用合并且压缩后的js,示例代码如下:

<%
	var app = process.app;
	if (app.get(‘development‘)) {
%>
<script type="text/javascript" src="/js/config.js"></script>
<script type="text/javascript" src="/js/lib/cache.js"></script>
<script type="text/javascript" src="/js/main/user.js"></script>
<script type="text/javascript" src="/js/main/userAddress.js"></script>
<%	}
	else { %>
<script type="text/javascript" src="/js/myApp.min.js"></script>
<%	} %>

  2个代码生成的模块代码这里就不再写出来了,因此大致的代码上面都已经给出来了,其他的就靠大家自己根据实际情况去重构了,^_^。

  压缩js脚本的代码也不写了,具体的可以查看文章开头的UglifyJS2的示例代码,需要注意的是except参数是不能少的,不然会将合并脚本内的angularjs的模块名和功能模块名替换成其他的简单变量,项目运行起来会出现错误。

结尾

  由于近段时间都是使用angualrjs配合nodejs来进行开发的,开发中遇到的问题和解决的方案整理了一下跟大家分享一下,希望对大家有所帮助。

  大致的代码基本上都有提供,其他的就要靠大家自己去编码了,这样才能将分享的东西转化成自己的。

  今天的文章就到这里了,如果有什么错误、问题请留言给我,谢谢大家!

另类angularjs应用

时间: 2024-10-06 08:44:13

另类angularjs应用的相关文章

AngularJS - 服务简介

服务是AngularJS中非常重要的一个概念,虽然我们有了控制器,但考虑到其生命实在脆弱,我们需要用到服务. 起初用service时,我便把service和factory()理所当然地关联起来了. 确实,factory()是创建一个服务的最简单的方式,但服务并非仅此而已. 这里记录一下我对服务的一些简单认识. Service 非常重要的一点 —— 服务是单例. 一个服务在一个AngularJS应用中只会被$injector实例化一次,并贯穿应用的整个生命周期,与脆弱的控制器们进行通信. 先从注册

angularJs中关于ng-class的三种使用方式说明

在开发中我们通常会遇到一种需求:一个元素在不同的状态需要展现不同的样子. 而在这所谓的样子当然就是改变其css的属性,而实现能动态的改变其属性值,必然只能是更换其class属性 这里有三种方法: 第一种:通过数据的双向绑定(不推荐) 第二种:通过对象数组 第三种:通过key/value 下面简单说下这三种: 第一种:通过数据的双向绑定 实现方式: function changeClass(){   $scope.className = "change2"; } <div clas

Node.js 使用angularjs取得Nodejs http服务端返回的JSON数组示例

server.js代码: // 内置http模块,提供了http服务器和客户端功能(path模块也是内置模块,而mime是附加模块) var http=require("http"); // 创建服务器,创建HTTP服务器要调用http.createServer()函数,它只有一个参数,是个回调函数,服务器每次收到http请求后都会调用这个回调函数.服务器每收到一条http请求,都会用新的request和response对象触发请求函数. var server=http.createS

Bootstrap + AngularJS+ Ashx + SQL Server/MySQL

去年年底12月,为适应移动端浏览需求,花了1个月时间学习Bootstrap,并将公司ASP网站重构成ASP.NET. 当时采取的网站架构: Bootstrap + jQuery + Ashx + SQL Server 时间紧,没人带,只能硬着头皮,最后如期完成,但是也遗留了几个问题. 问题: 1.页面查询条件太复杂,太多的checkbox,jQuery操作DOM虽然方便,但是组合成json提交给后端还是比较麻烦,有没有天然支持json的前端框架或者脚本语言? html控件做的任何修改,都自动保存

一招制敌 - 玩转 AngularJS 指令的 Scope (作用域),讲得特别好

学习了AngularJS挺长时间,最近再次回首看看指令这部分的时候,觉得比自己刚开始学习的时候理解的更加深入了,尤其是指令的作用域这部分. 步入正题: 每当一个指令被创建的时候,都会有这样一个选择,是继承自己的父作用域(一般是外部的Controller提供的作用域或者根作用域($rootScope)),还是创建一个新的自己的作用域,当然AngularJS为我们指令的scope参数提供了三种选择,分别是:false,true,{}:默认情况下是false. scope = false 首先我们来看

前端angularJS利用directive实现移动端自定义软键盘的方法

最近公司项目的需求上要求我们iPad项目上一些需要输入数字的地方用我们自定义的软键盘而不是移动端设备自带的键盘,刚接到需求有点懵,因为之前没有做过,后来理了一下思路发现这东西也就那样.先看一下实现之后的效果: 实现的效果就是当点击页面中需要弹出软键盘的时候软键盘弹出,浮在页面的中间,和模态框一样的效果,可以在软键盘中输入任何数字,附带的功能有小数点.退格.清空.确定等功能.当在键盘上点击数字的时候页面中的表单中实时的添加对应的数字,上图中可以看到. 产品经理那边给的原因是iPad屏幕本来就小,如

AngularJs自定义过滤器filter

AngularJs自带有很多过滤器,现在Insus.NET演示一个自定义的过滤器,如实现一个数据的平方. 本演示是在ASP.NET MVC环境中进行. 创建一个app: 创建一个控制器: 接下来是重点,创建一个过滤器,例子中的过滤器是实现一个数值的平方. 以上的所指的App,控制器和过滤器均是依Angularjs而言. 下面是ASP.NET MVC的视图,实现数据过滤: 程序运行结果:

AngularJS:directive自定义的指令

除了 AngularJS 内置的指令外,我们还可以创建自定义指令. 你可以使用 .directive 函数来添加自定义的指令. 要调用自定义指令,HTML 元素上需要添加自定义指令名. 使用驼峰法来命名一个指令, runoobDirective, 但在使用它时需要以 - 分割, runoob-directive: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script

Angularjs[补21] - 显示注入,隐示注入

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div ng-app="myApp"> <div ng-controller="secondController"> &