用ES6编写AngularJS顺序是如何一种体验

AngularJS不必我赘述,前端开辟人员肯定耳熟能详。有人称之为MVWhatever框架,意义是运用AngularJS,你能够参考恣意范式举行运用开辟,无论是MVC、照样MVVVM都信手拈来,只需你懂,范式在AngularJS部下,都能够轻松适配。

跟着种种当代浏览器、以及nodeES6的支撑,已经有越来越多的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); //相符前提的新数组

假如改用数组的高阶函数,再合营ES6arrow function,代码能够简约云云:

const list = originalList.filter(item => item.gender === 'male');

console.log(list); //相符前提的新数组

既然有云云文雅的语法糖能让我们的开辟变得high到爆,那过去我们以为屌炸天的AngularJS(如今也屌炸天,只不过另有Angular2, React, vue横空出世)是不是是能够用ES6来写?少年不要疑心,真的能够哦!
《用ES6编写AngularJS顺序是如何一种体验》

一个优越、疾速、简约的starter东西有利于我们对ES6编写AngularJS的深切认知,所以我要用一个骨架天生器generator-es6-angular来建立新项目,该generator是依托于yeoman的脚手架。

装置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?时,国内用户挑选第一个淘宝镜像装置速率会快许多)

《用ES6编写AngularJS顺序是如何一种体验》

当敕令实行终了后,你就可以在当前目次下看到适才建立的项目了,本例中我运用的project namees6-demo

开启调试之旅

#进入刚建立的项目目次
cd es6-demo
#启动调试效劳
npm start

然后你就可以够在http://localhost:8080下,看到刚建立的项目的运转效果了:

《用ES6编写AngularJS顺序是如何一种体验》

项目简介

骨架组织

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();
            }
        };
    }
};

同时固然也能够声明诸如:组件、过滤器之类的大众东西,详见:common

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';
//引入features
import 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中要用到的service
import 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: '<home></home>'//路由对应组件
    }
];

用ES6写<home>组件

//引入该组件对应的css,注重这里不会有像vue那样的作用域,
//不过能协助你星散css内容,也不错的
import './home.css';

//导出组件声明对象
export default {
    template: `
        <logo></logo>
        <description></description>
        <github></github>
        <todo-app list="$ctrl.todos" loading="$ctrl.loading" on-toggle="$ctrl.toggleTodo(todo)" on-add="$ctrl.addTodo(todo)" on-archive="$ctrl.archive()"></todo-app>
        <footer></footer>
    `,
    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上给我提issue也未尝不可呢

    原文作者:leftstick
    原文地址: https://segmentfault.com/a/1190000005103425
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞