HTML5工程

本工程包括工程化管理模块、框架管理、业务实现,涉及到技术主要就是javascript、html、css,工程化主要依赖于:Nodejs、Grunt、Bower等。

前端工程化

我们一般的概念里面,只有Java代码需要进行编译、打包、发布,其实更加需要这些自动化的开发步骤;这里所谓工程化,就是通过现有前端技术对我们的前端代码,实现编译、打包、发布、框架和组件的版本维护,实现自动化、获得多端开发能力。

工程化主要是基于NodeJS,主要的依赖的框架结构如下:

工程环境:NodeJS

项目管理:NPM 项目js版本包的管理,GRUNT 项目构建。

前端框架:Angularjs

框架管理:Bower

构建工具:GRUNT("grunt": "^0.4.5")

页面刷新:connect-livereload、grunt-contrib-watch

版本控制:Git 、grunt-bump、grunt-changelog

插件集合:grunt-contrib-clean 、grunt-contrib-concat、grunt-contrib-copy、grunt-recess、grunt-contrib-uglify,这里包含js、css文件的整理、压缩、打包。

语法检测:grunt-contrib-jshint

本地服务器:http-server

测试框架:Karma + Jasmine

项目创建,建立基本目录结构

gtx.alias("jshint",['jshint:srcjs']);

gtx.alias('servers', ['connect:server','watch']);

gtx.alias('server', ['connect:server']);

gtx.alias('build:apps',[
        'clean:apps',
        'copy:libs',
        'copy:apps',
        'useminPrepare',
        'htmlmin',
        'recess:apps',
        'concat:apps',
        'uglify:apps',
        'usemin',
        'clean:tmp'
]);

gtx.alias('release', ['bower-install-simple', 'bump-commit']);
gtx.alias('release-patch', ['bump-only:patch', 'release']);
gtx.alias('release-minor', ['bump-only:minor', 'release']);
gtx.alias('release-major', ['bump-only:major', 'release']);
gtx.alias('prerelease', ['bump-only:prerelease', 'release']);
gtx.alias('deploy-staging', ['ssh_deploy:staging']);


// 本地启动服务和动态刷新(修改密码后不用刷新页面)
> grunt servers

// 本地启动服务
> grunt connect:server  

// 检查JavaScript的语法检查
> grunt jshint

// 组件版本控制打包需要使用的组件。
> grunt copy:libs

// 复制应用到指定目录
> grunt copy:apps

// 压缩html代码和替换index.html代码块。
> grunt useminPrepare
> grunt htmlmin
> grunt usemin

// 整合css文件到app.min.css
> grunt recess:apps

// 合并index.html的js到app.src.js
> grunt concat:apps

// 压缩app.src.js到app.min.js
> grunt uglify:apps

// 打包整个应用
> grunt build:apps

// 提交并进行版本号控制

// 补丁提交 0.0.1
> grunt release-patch

// 中端提交 0.1.0
> grunt release-minor

// 版本提交 1.0.0
> grunt relasse-major

目录或文件 解释说明
libs 组件目录(从bower_components目录同步。)
src 源码目录
apps 整合部署目录
grunt 构建脚本目录
GruntFile.js 构建工程组件
package.json 构建工程组件
bower.json 组件版本控制
bower_components 版本控制自动生成,组件集合
node_components 构建自动生成,构建框架
readme.txt 初始化等说明
update.txt 发布版本说明
1.整理第三方框架,并整合到bower.js ,实现版本控制。
2.构建脚本:GruntFile.js package.json。
3.构建Grunt插件,工程化打包流程。
4.整理构建流程。
5.设计src的文件目录。
6.设计基本AngularJs结构。

安装 node.js

brew install node

打开根目录执行一下命令

npm install -g grunt-cli

npm install

npm install -g bower

bower install

grunt build:apps

grunt servers

前端结构约定

SRC目录约定

目录或文件 约定说明
css 自主设计的样式表单。
I10n 国际化目录。
images 系统中使用的图片。
js 业务代码。
tpl 模版代码。
index.html 项目总的入口。
JS目录约定

目录或文件 约定说明
app 目录:项目公共模块。
banniu 目录:班牛业务代码
common 目录:公共控制器。
directives 目录:指令。
filters 目录:筛选器。
salecrm 目录:销售CRM业务代码
services 目录:资源配置目录。
app.js 应用启动加载模块。
config.js 应用基础配置和静态常量。
config.lazyload.js 准备延时加载的组件。
config.router.js 路由配置。
config.session.js 拦截器。
main.js 应用初始化配置。

在业务目录中添加相应的模块代码。每一个模块对应一个目录。

前端编码约定

命名和注释约定

(https://shimo.im/doc/bKCrIoqmEWw1CV7L)

延时加载
延时加载组件,就是在使用时加载组件。在config.lazyload.js中引入所有需要使用的组件。
有两种使用方式:
1.在路由中加载
resolve: load(['atwho','simditor','js/salecrm/tag/tag.js','ui.select'])
2.指令加载
ui-jq="atwho"
路由配置
这里路由是两级,根据情况,我们可以分成三级。通过路由来分解代码的耦合和重复。
.state('salecrm', {
        abstract: true,
        url: '/salecrm',
        templateUrl: layout_salecrm
})
.state('salecrm.customer_my', {
        url: '/my/customer/:customerId',
        views: {
                "header@salecrm" : {
                        templateUrl: "tpl/salecrm/customer/customer_my_header.html"
                },
                "container@salecrm" : {
                        templateUrl: 'tpl/salecrm/customer/customer.html',
                        resolve: load(['atwho','simditor','js/salecrm/customer/customer_my.js', 'js/salecrm/customer/customer_show.js', 'ui.select']),
                        controller: 'CustomerMyCtrl'
                }
        }
})
资源配置
一个对象或RESTFul资源配置一个资源对象。

app.factory('Linkmans', ['$resource','rserv',
    function($resource,rserv){
        var opts = rserv.operates(false);
        opts.checkMobile = {
          method: 'POST',
          isArray: false,
          url: rserv.baseUrl + '/customerLinkman/:mobile/check'
        };
        opts.doubleCall = {
            method: 'POST',
            isArray: false,
            url: rserv.baseUrl + '/customerLinkman/doubleCall'
        };
        return $resource(rserv.url('customerLinkman'), {id: '@id', mobile:'@mobile'}, opts);
    }]
);

app.factory('Visits', ['$resource','rserv',
    function($resource,rserv){
        return $resource(rserv.url('customerVisit'), {id: '@id'}, rserv.operates(false));
    }]
);
前端控制器
注意事项
* 调用资源的方式统一。
* 命名规范。
  * 控制器命名:      模块名+Ctrl
    * 初始化列表命名:  set+模型名
    *    查询:                     search+模型名
    * 新建:                     new+模块名
    * 编辑:                     edit+模块名
    * 查看:                     show+模块名
    * 保存/修改:         save+模块名
* 代码注释
    * 控制器说明
    * 复杂的算法和方法说明(包括方法、指令、服务、筛选器)

模版说明如下:


/**
 * 系统标签(包含子标签),比如:客户成熟度、客户类型。
 * Created by mifeng on 2017/3/9.
 */
app.controller('TagCtrl', ['$scope','$modal','$log','$aside','$stateParams','$http','toaster','Tags','svThrow','Linkmans', function($scope,$modal,$log,$aside,$stateParams,$http,toaster,Tags,svThrow,Linkmans) {

    // 标签ID(必传字段)
    $scope.tagId = $stateParams.tagId;

    // 搜索条件
    $scope.conditions = {
        pageNum: 1,
        pageSize: 10,
        tagId: $scope.tagId,
        tagType: null,
        tagName: null
    };

    // 加载分页信息和数据
    $scope.setTags = function() {
      // 由ui-paginate调用改变pageNum。
      if($scope.result) {
        $scope.conditions.pageNum = $scope.result.pageNum;
      }
            // 资源查询列表
      Tags.query($scope.conditions, function(result){
        $scope.result = result;
      });
    }

    // 搜索查询
    $scope.searchTags = function(tagType){

        if($scope.conditions.tagName == "") {
          $scope.conditions.tagName = null;
        }

        if (tagType) {
          $scope.conditions.tagType = tagType;
          $scope.setTags();
        }

        $scope.setTags();
    }

    // 初次加载
    $scope.setTags();

    // 新建标签
    $scope.newTag = function() {
      $scope.tag = new Tags({tagType: 1,status: 0, tagId: $scope.tagId });
      angular.element("#tag_modal").click();
    }

    // 新建子标签
    $scope.newSubTag = function(tag) {
      $scope.tag = new Tags({tagType: 1,status: 0,tagId: tag ? tag.id : 0 });
      angular.element("#tag_modal").click();
    }

    // 编辑标签(包括子标签)
    $scope.editTag = function(tag) {
      $scope.tag = tag;
      angular.element("#tag_modal").click();
    }

    // 新增或修改标签
    $scope.saveTag = function() {

      if($scope.tag.id) {
        $scope.uTag = new Tags($scope.tag);
        $scope.uTag.$update(
          function(result) {
            $scope.tag = $scope.uTag;
            angular.element("#tag_modal").click();
            toaster.pop('success','修改成功。');
          }
        );
      }else {
        $scope.tag.$save(
          function(result) {
            angular.element("#tag_modal").click();
            $scope.setTags();
            toaster.pop('success','添加成功。');
          },svThrow.throwError
        );
      }
    }

    // 查看标签
    var tagAside = $aside({    //侧栏——详情
        templateUrl: 'tpl/salecrm/tag/tag_show.html',
        controller: 'TagShowCtrl',
        show: false
    });

    $scope.showTag = function(tag) {
        console.log("显示详情");

        Tags.show({id: tag.id},function(result) {
          console.log(result);
        });

        tagAside.$scope.tag = tag;
        tagAside.show();
        tagAside.$promise.then(function () {

        });
    }

}]);

前端发布方案

1)通过Nginx的反向代理。
2)WEB工程发布后,HTML工程代码整合到WEB工程中。