zoukankan      html  css  js  c++  java
  • 另类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 equirejs)来实现,但是整合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个方法(getset),大致代码如下:

    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('
    '), '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来进行开发的,开发中遇到的问题和解决的方案整理了一下跟大家分享一下,希望对大家有所帮助。

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

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

  • 相关阅读:
    【DOM】如何给div的placeholder传参
    【nvm】使用nvm将node升级到指定版本
    【Worktile】升级业务组件库后,http的数据返回整个response而不是data问题及解决方案
    js获取上传文件内容
    【正则】正则表达式-零宽断言(?=,?<=,?!,?<!)及常见报错
    【Angular】动态组件
    【扩展】div获取焦点或可编辑
    【CSS】position新增属性sticky
    thinkphp写接口返回固定的形式方法
    thinkphp5计算文件大小
  • 原文地址:https://www.cnblogs.com/ahl5esoft/p/3911755.html
Copyright © 2011-2022 走看看