基于angularjs与materialDesign的管理后台

最近换了个公司,乱七八糟的事儿比较多,更新耽误了些…
之前还看过一段时间的Vuejs,想着新公司如果做项目的话,用Vuejs去做。然而新公司的技术架构pc端更倾向于Angularjs,而且有专门的前端架构,架子什么的都搭的差不多了,所以来到新公司的第一个项目就用Angularjs做的。

通过这个项目,我对eslint、gitignore、proxy也算有了接触。毕竟以前做项目的时候也没关注过这些。这个项目是用gulp跟webpack配合使用的。也是直接用的旧有的架子,没做什么改动。
现在就说一下用Angularjs做的这个项目吧。

目录结构

  • app: 源代码
    • views: 一个页面一个文件夹
    • *.ctrl Controller
    • *.html Controller对应的页面
    • *.scss Controller对应页面的样式表
    • services: 服务,一个页面可能有多个服务,与页面一一对应
    • filters: 过滤器
    • app.js: 项目入口文件
    • index.html: index
  • dest: 编译后代码存放的位置,源码中不存在
  • .eslintrc.json: 语法检查
  • .gitignore: git忽略目录
  • .babelrc: babel编译配置
  • … 其他配置

入口文件 app.js

这个项目使用了angular-resource、angular-material等框架,因为Angularjs是依赖注入的,所以所有依赖的框架、插件甚至服务过滤器等等都需要import进来,并且注入到angular程序中。

Dependencies 项目依赖

import angular from 'angular';
import 'angular-material';
import 'angular-resource';
...

View 项目页面,包括其中的Controller及template等

import { Template, Controller } from './views/page1/page1.ctrl';
...

Service 服务

import IndexMenuResource from './services/index-menu.resource'

主程序,所有注入的内容都会在这里体现。

angular.module('app', [
    'ngResource', 'ngRoute', 'ngMaterial' ...
])
.controller('controller', Controller)
.service('IndexMenuResource', IndexMenuResource)
.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/', {
        template: Template,
        controller: Controller,
        controllerAs: 'ctrl'
        }) ...
    }]);

在这里,我每一个只写了一个,需要说明一点,使用controllerAs,在其他页面的对应的controller中,就可以不用$scope,转而使用this就可以了。然后需要在controller对应的template中,每一个变量前面都加上controllerAs的内容,也就是上文中的ctrl
这个地方也可以将路由模块抽离出来,但是,看着这个文件也不大,就放在这里吧,维护起来也还算好维护。

登录模块

登录模块是最后加的,原型图中也没有这个,但是感觉作为一个后台管理系统,如果没有这个模块,岂不是所有人知道网址就能随意修改内容了么…于是跟后端同事商量了一下,就把这个做上了。因为时间比较紧,项目经理就直接说,暂不需要权限管理,注册之类的,直接把这个东西在后台写死就好。但是后端同学还是为user单独建了张表,把权限也留出口来,以后如果有需要直接加上就好了。

在这里我就说一下前台是如何实现的:
在index.html中,写了一个跟页面平级的div,用于放置登录模块。这里用到了ng-if这个来控制是否显示登录模块。在登录成功后,我会将用户信息用session存到浏览器缓存中,然后将控制登录模块是否显示的字段置为false,然后,在跟controller加载的时候就去session中检查用户信息。这样就可以实现登录成功后,无论怎样刷新,都不会再显示这个页面。

我是用的es6语法写的这个项目,所以在这里也放一下es6写的controller:

export class RootController {
    constructor(IndexMenuResource, User, $mdDialog) {
        this.menuRes = IndexMenuResource;
        this.user = User;
        this.$mdDialog = $mdDialog;

        this.isUserLogin = false;
    }
}

在constructor构造函数中,将这个controller需要的资源注入进来。这个isUserLogin如果按照之前的写法,需要注入$scope,并将this替换为$scope。但是之前在配置路由的时候提到过,使用了controllerAs这个配置,所以这里就不需要使用$scope。再说一下template中是如何配合使用的:

<div ng-if="root.isUserLogin">

</div>

这个root就是之前配置的controllerAs,其他页面以此类推。

导航模块

回想刚开始做前端的时候,恨不得所有的东西都在html中写死,还美其名曰加快加载进度。但是现在看来,像导航这种东西,还是配置成数据,然后通过各个框架的循环ng-repeat或v-for等这种东西使用起来,才算是优雅(我认为的…)。这样看起来页面不会有那么多重复的东西,显得也比较简洁。

<ul>
    <li ng-repeat="item in root.menus" ng-click="root.activeMenu($index)" ng-class="item.active? 'zs-toolbar-active' : ''">
        <md-button href={{item.url}} class="md-icon-button">
            <md-icon class="fl">{{item.icon}}</md-icon>
            <span class="fl">{{item.cnt}}</span>
        </md-button>
    </li>
</ul>

Angularjs的服务具体是什么我就不说了,这里我只是说一下es6是怎么写的。像这个导航模块的服务就相对简单:

export default function IndexMenuResource() {
    return [
        {cnt: '管理1', icon: '', url: '#/manager1', active: false},
        ...
    ]
}

服务、请求

上面的导航模块,服务只有这一个功能,所以只是用了一个function,然后export出去就可以了。如果服务功能多一点的话,就需要使用es6的class,同样,需要在constructor中引入依赖。

/**
 * 单条活动资源。
 */
export default class ActivityItemResourceService{

  /**
   * 引入$resource模块
   * @param $resource
   */
  constructor($resource) {
    this.$resource = $resource;
  }


  /**
   * 编辑/新建活动
   * @return { 单条活动资源 }
   */
  resActivityItem() {
    return this.$resource('cardactivity/activitydetail');
  }

  /**
   * 保存活动
   * @returns { 更新服务器中的活动资源 }
   */
  saveActivityItem() {
    return this.$resource('cardactivity/savecardactivity', {});
  }
}

从上面的代码中可以看出,项目的前后端交互部分是用的$resource,接口是用的restful风格的。
最开始我一直想在服务中返回的就是请求回来的资源,但是通过几次尝试,发现非常的不好用。无论是使用$q还是在服务中本地维护一个对象,将请求回来的数据放进去,发现都不好用。最终,在服务中体现的就是上面的样子:实际上是每个资源的地址。在controller中调用时,写上调用这个资源需要的方法。然后在callback中赋值给本地维护的对象。

material design

最初要求项目开发周期较短,并且这个项目只有非常简陋的原型图,所以前端老大说使用angular-material-design来作为UI框架。之前也没接触过,然后就上官网去看demo,需要什么样的样式,就去官网上找对应的demo,然后就大体知道了些。

布局

这个UI框架跟bootstrap还是有相似之处的,比如说那个布局,确实非常好用。如果想让内容上下分布的话,就用layout="column";如果想让内容左右分布的话,就用layout="row"。内容的大小就可以用flex属性来设置。
flex属性的最大值为100,设置的最小步长为5,也就是可以设置为10、设置为15可以,但是设置为13就不行。

<div layout="row">
    <div flex="10"></div>
    <div flex="90"></div>
</div>

Form表单

materialDesign中的input都是没有边框的,并且它的input的label是位于input输入框内的,不是左右或上下分离的,这在有很多input的form表单中就显得略微有些怪异。这个就算是加上边框,看起来也略微有点别扭,不过也没办法…既然当初是为了节省时间成本选用的这个框架,如果还是要自定义那么多样式的话,也没必要用UI框架了。
如果使用validate功能的话,需要引入angular-messages,但是在引入这个插件的时候,发现报错了,进入源码把带有angularVersion的那一行删掉就好了。这个地方我也不知道是怎么回事,尝试换过angularjs的版本及angular-messages的版本,但是都没有解决,只能删掉这行了。

card

虽然看官网的demo,card基本是作为类似于微信分享那样,带有图片之类的。但是因为样式设计原因,我更喜欢把他作为一个个区块去使用,带有box-shadow的样式看起来也不错。

富文本

这个富文本模块最初的需求中有这个,但是除了管理后台以外,对应的用户界面也是由我开发,找了半天也没找到富文本到底是在哪里使用。后来跟产品沟通了一下,用多行文本textarea就满足需求了。
但是自己也尝试了一下,从网上找了个CKEditor的插件,自己写了个demo可以使用。但是用到我的这个项目中就出现问题,写了指令之后也一直报错,找了半天原因也没找到,就暂时放弃了,等再有这个需求的时候再研究吧。

总结

这个项目还是让我有很大收获的,除了eslint这种东西,本地开发需要的跨域问题也通过proxy得以解决。也对Angularjs以及angular-material-design有了一定的了解。当然还有开动脑筋把简陋的原型图变成web网站的间接的审美锻炼……

发表评论

邮箱地址不会被公开。 必填项已用*标注