博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用ES6编写AngularJS程序是怎样一种体验
阅读量:5861 次
发布时间:2019-06-19

本文共 9768 字,大约阅读时间需要 32 分钟。

不用我赘述,前端开发人员一定耳熟能详。有人称之为MVWhatever框架,意思是使用AngularJS,你可以参考任意范式进行应用开发,无论是MVC、还是MVVVM都信手拈来,只要你懂,范式在AngularJS手下,都可以轻松适配。

随着各种现代浏览器、以及对的支持,已经有越来越多的ES6特性可以在程序中使用,她们给开发过程带来的便利不言而喻,举个小例子,我想从一个数组里找一些符合条件的数据,放入另一个数组内,过去我们这么写:

var list = [],    i;for (i = 0; i < originalList.length; i++) {    var item = originalList[i];    if (item.gender === 'male') {        list.push(item);    }}console.log(list); //符合条件的新数组

如果改用数组的高阶函数,再配合ES6的,代码可以简洁如斯:

const list = originalList.filter(item => item.gender === 'male');console.log(list); //符合条件的新数组

既然有如此优雅的语法糖能让我们的开发变得high到爆,那过去我们认为屌炸天的AngularJS(现在也屌炸天,只不过还有Angular2, React, vue横空出世)是不是可以用ES6来写?少年不要怀疑,真的可以哦!

图片描述

一个良好、快速、简洁的starter工具有利于我们对ES6编写AngularJS的深入认知,所以我要用一个骨架生成器来创建新项目,该generator是依托于的脚手架。

安装yo

npm install -g yo

请注意前缀sudo,如果你使用的是unix like操作系统的话

安装generator-es6-angular

npm install -g generator-es6-angular

请注意前缀sudo,如果你使用的是unix like操作系统的话

使用generator-es6-angular创建项目

先找个你喜欢的目录,然后运行下面的命令,因为一会新项目会直接创建在该目录下。

yo es6-angular

上面命令回车后,生成器会问你如下问题,老实作答即可(注意: 对单页应用没经验的孩纸,在Use html5 model这个问题上,请选择No; 当问你Which registry would you use?时,国内用户选择第一个淘宝镜像安装速度会快很多)

图片描述

当命令执行完毕后,你就能在当前目录下看到刚才创建的项目了,本例中我使用的project namees6-demo

开启调试之旅

#进入刚创建的项目目录cd es6-demo#启动调试服务npm start

然后你就可以在下,看到刚创建的项目的运行效果了:

图片描述

项目简介

骨架结构

es6-demo├── etc│   └── config.js├── img│   └── ...├── js│   ├── features│   │   ├── about│   │   │   ├── components│   │   │   │   ├── about.co│   │   │   │   ├── about.css│   │   │   │   └── subs│   │   │   │       ├── more│   │   │   │       │   ├── index.co│   │   │   │       │   └── more.css│   │   │   │       └── why│   │   │   │           ├── index.co│   │   │   │           └── why.css│   │   │   ├── main.js│   │   │   └── routes.js│   │   ├── common│   │   │   ├── components│   │   │   │   ├── main.js│   │   │   │   ├── menu.co│   │   │   │   └── menu.css│   │   │   ├── directives│   │   │   │   ├── autofocus.js│   │   │   │   └── main.js│   │   │   ├── main.js│   │   │   └── runners│   │   │       ├── main.js│   │   │       └── routeIndicator.js│   │   ├── home│   │   │   ├── components│   │   │   │   ├── home.co│   │   │   │   └── home.css│   │   │   ││   │   │   ├── main.js│   │   │   ├── routes.js│   │   │   └── service│   │   │       └── HomeService.js│   │   └── main.js│   ├── fw│   │   ├── config│   │   │   ├── SSOConfig.js│   │   │   ├── main.js│   │   │   └── routerConfig.js│   │   ├── ext│   │   │   └── main.js│   │   ├── helper│   │   │   ├── event.js│   │   │   ├── ngDeclare.js│   │   │   └── object.js│   │   └── value│   │       ├── main.js│   │       └── routesValue.js│   ├── application.co│   ├── application.css│   ├── index.js│   └── main.js├── index.html_vm├── package.json├── postcss.config.js├── webpack.config.js└── webpack.config.prod.js
  • etc, 一些公共配置性内容,可以放在这里,方便查找、通用

  • img, 用我多说么?放图片的啦

  • js, 分为featuresfw两大部分。这个内容略多,我后面详述吧。

  • index.html_vm, 单页应用html模版,最终的html会由webpack根据这个模版生成

  • package.json, 项目的npm描述文件,那些具体的工具命令(譬如刚才用过的npm start,都在这里面定义好了)

  • postcss.config.js, postcss的配置文件

  • webpack.config.js, 开发、调试环境使用的webpack配置

  • webpack.config.prod.js, 正式运行环境使用的webpack配置。npm run release命令会用这个配置,生成的结果都会给文件名加hashjavascript文件也会压缩。

可用工具介绍

  • npm start, 启动调试服务器,使用webpack.config.dev.js作为webpack配置,不直接生成物理文件,直接内存级别响应调试服务器资源请求。而且内置hot reload,不用重启服务,修改源码,浏览器即可刷新看到新效果

  • npm run release, 使用webpack.config.prod.js作为webpack配置,生成压缩、去缓存化的bundle文件到es6-demo/build目录下。也就是说,如果你要发布到生产环境或者其它什么测试环境,你应该提供的是es6-demo/build目录下生成的那堆东西,而不是源码。

js目录介绍

features

common

那些通用的组件、指令、过滤器、服务。。。通通应该放在这里,譬如为了演示方便,我已经在features/common/directives里写了一个autofocus.js的指令,拿去用,不要客气。代码如下:

export default {    type: 'directive',//声明这是一个指令    name: 'autofocus',//声明指令名    //声明指令构造函数,详见:https://docs.angularjs.org/api/ng/type/angular.Module#directive    directiveFactory: function() {        'ngInject';        return {            restrict: 'A',            link($scope, element) {                element[0].focus();            }        };    }};

同时当然也可以声明诸如:组件、过滤器之类的公共工具,详见:

about

home

这两个就是纯粹为了演示“功能 <对应> 路由”这个小原则而做的,你可以分别在这两个feature下找到一个routes.js,里面的内容就描述了该功能对应一个(或多个)路由,是何等的easy。至于最后这个路由会怎样被这个骨架使用,小伙伴们,好好研究哦!

fw

这里面都是些所谓"框架"级别的设置,有兴趣的话挨个儿打开瞧瞧嘛,没什么大不了的。

特别注意,大部分时候,你的开发都应该围绕features目录展开,之所以叫fw,就是和具体业务无关,除非你需要修改框架启动逻辑,路由控制系统。。。,否则不需要动这里的内容

源码介绍

js/index.js

入口文件

/** *  * 这里连用两个ensure,是webpack的特性,可以强制在bundle时将内容拆成两个部分 * 然后两个部分还并行加载 * *///第一个部分是一个很小的spinner,在并行加载两个chunk时,这个非常小的部分90%会竞速成功//于是你就看到了传说中的loading动画require.ensure(['splash-screen/dist/splash.min.css', 'splash-screen'], function(require) {    require('splash-screen/dist/splash.min.css').use();    require('splash-screen').Splash.enable('circular');});//由于这里是真正的业务,代码多了太多,所以体积也更大,加载也更慢,于是在这个chunk加载完成前//有个美好的loading动画,要比生硬的白屏更优雅。//放心,这个chunk加载完后,loading动画也会被销毁require.ensure(['css/main.css', 'splash-screen', './main'], function(require) {    require('css/main.css').use();    //这里启动了真正的“框架”    var App = require('./main').default;    (new App()).run();});

js/main.js

“框架”启动器

//引入依赖部分import angular from 'angular';//引入Object帮助库import {pluck} from './fw/helper/object';//引入feature注册工具import {declareFeatures, declareValues, declareDirectives, declareComponents, declareRunners, declareFilters} from './fw/helper/ngDeclare';//引入三方依赖import Extensions from './fw/ext/main';//引入项目配置import Configurators from './fw/config/main';//引入项目常量设置import Values from './fw/value/main';//引入featuresimport Things from './features/main';//引入根组件import Application from './application';//引入启动spinner控制器import {Splash} from 'splash-screen';class App {    constructor() {        //这里相当于ng-app的名字        this.appName = 'es6-demo';        //找到所有的features        this.features = Things.filter(t => t.type === 'feature' && t.name);    }        //检查项目基本设置    validate() {        if (!this.features || this.features.length === 0) {            return console.warn('No features loaded');        }        const modNames = pluck(this.features, 'name').sort();        for (let i = 0; i < modNames.length - 1; i++) {            if (modNames[i] === modNames[i + 1]) {                throw new Error('Duplicated Module: [ ' + modNames[i] + ' ], you have to specify another name');            }        }    }    //从features实例中提取AngularJS module name    //并将这些name作为es6-demo的依赖    //会在下面createApp时用到    findDependencies() {        this.depends = [...Extensions, ...this.features.map(f => f.name)];    }    //创建angular应用    createApp() {        declareFeatures(this.features);        this.app = angular.module(this.appName, this.depends);        this.app.component('application', Application);    }    //配置es6-demo    configApp() {        Configurators.forEach(Configurator => {            this.app.config(Configurator.config);        });    }        //注册fw下的“框架”级service    registerServices() {        declareValues(this.app, Values);        declareDirectives(this.app, Things.filter(t => t.type === 'directive'));        declareComponents(this.app, Things.filter(t => t.type === 'component'));        declareRunners(this.app, Things.filter(t => t.type === 'runner'));        declareFilters(this.app, Things.filter(t => t.type === 'filter'));    }    //看到了么,这里我会销毁loading动画,并做了容错    //也就是说,即便你遇到了那微乎其微的状况,loading动画比业务的chunk加载还慢    //我也会默默的把它收拾掉的    destroySplash() {        Splash.destroy();        require('splash-screen/dist/splash.min.css').unuse();        setTimeout(() => {            if (Splash.isRunning()) {                this.destroySplash();            }        }, 100);    }        //启动AngularJS app    launch() {        angular.bootstrap(document, [this.appName]);    }    //顺序激活所有模块    run() {        this.validate();        this.findDependencies();        this.createApp();        this.configApp();        this.registerServices();        this.destroySplash();        this.launch();    }}export default App;

用ES6写Feature

features/home/main.js

//引入路由import routes from './routes';//引入所有本feature中要用到的组件import home from './components/home';import logo from './components/subs/logo';import description from './components/subs/description';import github from './components/subs/github';import todoApp from './components/subs/todo';import footer from './components/subs/footer';//引入本feature中要用到的serviceimport HomeService from './service/HomeService';export default {    type: 'feature',//声明该模块是一个feature    name: 'home',//声明feature的名字,必须的    routes,//倒入路由    component: {//注册所有用到的组件        home,        logo,        description,        github,        todoApp,        footer    },    service: {//注册所有用到的service        HomeService    }};

用ES6写路由

简单到没朋友

export default [    {        id: 'home',//为该路由起一个唯一标识符        isDefault: true,//声明是否为默认路由        when: '/home',//路由路径        template: '
'//路由对应组件 }];

用ES6写<home>组件

//引入该组件对应的css,注意这里不会有像vue那样的作用域,//不过能帮助你分离css内容,也不错的import './home.css';//导出组件声明对象export default {    template: `        
`, controller: class { //下面是依赖注入的关键,通过https://github.com/schmod/babel-plugin-angularjs-annotate实现 /*@ngInject*/ constructor(HomeService) { this.HomeService = HomeService; this.todos = []; this.loading = true; } $onInit() { this.HomeService .getInitTodos() .then(todos => { this.todos = todos; this.loading = false; }); } addTodo(todo) { this.todos = [todo, ...this.todos]; } toggleTodo(todo) { this.todos = this.todos.map(t => { if (t.txt !== todo.txt) { return t; } return { finished: !todo.finished, txt: t.txt }; }); } archive() { this.todos = this.todos.filter(todo => !todo.finished); } $onDestroy() {} }};

最后,你可能还有其它问题,直接来,或者Github上给我提也未尝不可呢

转载地址:http://cfgjx.baihongyu.com/

你可能感兴趣的文章
Spring Security笔记:自定义登录页
查看>>
中间件的理解
查看>>
用于主题检测的临时日志(452a49c2-4455-430f-a1cc-bbcd2d1944dd - 3bfe001a-32de-4114-a6b4-4005b770f6d7)...
查看>>
Convert Sorted Array to Binary Search Tree leetcode java
查看>>
【BZOJ】1041: [HAOI2008]圆上的整点(几何)
查看>>
Biorhythms(中国剩余定理)
查看>>
PL/SQL连接oracle数据库
查看>>
项目管理心得:一个项目经理的个人体会、经验总结
查看>>
android 检测网络是否可用
查看>>
XSS测试语句大全
查看>>
C#异步调用
查看>>
阿里2015校招面试回忆录(成功拿到offer)
查看>>
Android Activity的生命周期
查看>>
linux find
查看>>
Android4.2以及最新SDK的尝鲜使用
查看>>
[大家谈谈] 13个在线接收短信的国外网站
查看>>
Atitit. Dwr 抛出异常error解决方案
查看>>
10分钟掌握XML、JSON及其解析
查看>>
FarBox的建站过程
查看>>
雷人的一幕:国外的codeproject论坛竟有人发“中文贴”.....
查看>>