基于ES6的模塊化開發(fā)(附件:基于Angular-cli的WorkTile效果)


在沒有框架的約束下,我們開發(fā)項目可能都是基于過程的,想到哪里就添加一個函數(shù)窥岩。這在項目開發(fā)的初期可能是很快的,特別是對于前端項目宰缤。但在后期修改需求的時候就發(fā)現(xiàn) 項目文件存在 功能不明確颂翼,職責混亂的情況,假如有Vue.js 或者Angular.js 等框架約束慨灭,這種情況會相對好些朦乏。本文記錄下基于ES6 實踐模塊化開發(fā)的過程,本文所用到的代碼在github項目上氧骤,歡迎各位大神指點呻疹。

Angular.js 架構圖

這些MVC框架基本都著眼于以數(shù)據(jù)模型為中心,打造數(shù)據(jù)驅(qū)動的模塊化前端應用筹陵」舸福框架可能層出不窮,學也學不完朦佩,但基本的思想是不變的并思。以 Angular.js 的架構 為例,Component(組件) 和 Template(HTML模板) 分別代表了Web App的數(shù)據(jù) 和 視圖兩大部分语稠,數(shù)據(jù)的存儲宋彼、更新過程都是在我們定義的組件中弄砍,組件中包含的數(shù)據(jù)模型更新都會通過數(shù)據(jù)綁定引起視圖的更新。

而用戶對用戶界面的操作输涕,可以通過事先定義的各種Directive(指令)音婶,反饋到數(shù)據(jù)模型中。比如 ngModel 這樣的指令就可用于綁定視圖對數(shù)據(jù)模型的更新莱坎∫率剑基于Angular這樣的框架開發(fā)過程中,基本就是不斷寫組件檐什,寫模板瞳收,寫指令的過程。那么扯遠了厢汹,Angular 的模塊化系統(tǒng)和ES6 的還是有很大差異的。說了半天谐宙,框架畢竟是別人團隊開發(fā)的烫葬,你大可去用,從ES6 這樣的本源出發(fā)去學習實踐更加以不變應萬變凡蜻。

ES6 簡單入門

簡單地說搭综,ES6 新的特性可分為以下幾點:

  • Classes and Modules (這回主要談一談模塊)
  • New methods for strings and Arrays, Promises, Maps, Sets
  • Completely new features: Generators, Proxies

定義Class

定義一個類
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ',' + this.y + ')';
  }
}

// es6 的class 等同于 function,就是構造函數(shù)
Point.prototype.constructor === Point // true

var point = new Point(2, 3);
point.toString()

point.hasOwnProperty('x') //true
point.hasOwnProperty('toString') // false
// toString 方法是原型對象Point 的屬性, 而不是屬于point 實例的屬性划栓,是通過查找原型鏈得來的兑巾。

es6 私有屬性和方法定義

私有方法可以通過將 function 定義在class 作用域之外

// 例如 想要給Point 類一個私有方法
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.type = type;
  }
  
  print () {
     toString.call(this);
  }
}

function toString( point ) {
   return point.x + "," + point.y;
}
var type = 'Point';

class 靜態(tài)方法

上面提及的類 都需要實例化后才能使用,那靜態(tài)方法可以使我們無需實例化就 通過類直接調(diào)用

 class Format {
    static transform(jsonStr) {
      return JSON.parse(jsonStr);
    }
 }

  // 靜態(tài)屬性 extension
 Format.extension = {
   geojson: ".json"
 }

 class GeoJSON extends Format {
 }

 GeoJSON.transform("{'name': 'hello'}"   // 直接調(diào)用 靜態(tài)方法

ES6轉碼打包


由于大部分瀏覽器還沒有支持ES6 模塊忠荞,所以可采用Babel 轉
來把我們的代碼轉化為es5.

然后用 Webpack 打包所有js文件 為一個bundle 蒋歌,也可以采用SystemJS的依賴管理方案,實現(xiàn)瀏覽器端的模塊加載委煤。

由于之前在Angular的 實踐過程中采用的是 SystemJS堂油,所以這次把兩種方法都討論演示下。需要說明的是碧绞,這兩種瀏覽器端加載es6模塊的方法都需要Babel的支持府框,根據(jù)具體情況可選用 Webpack 或SystemJS。

模塊編寫過程

比如我們現(xiàn)在有 drone 和 bullet 兩個類讥邻,drone 可以通過fire() 方法創(chuàng)建bullet 實例迫靖,并且通過一個全局的 RenderBullet 方法計算bullet 軌跡。

就這么簡單的需求兴使,因為drone 和bullet 在我們的游戲應用中是 基礎類系宜,所以單獨寫成模塊。常數(shù)變量至于const.js 中发魄。

// drone.js
import Const from './const';
import Bullet from './bullet';

/**
 * Drone class with control method.
 */
export default class Drone {
    constructor(opts) {
        this.id;
        this.speed = opts.speed ? opts.speed: 0.01;
        this.direction = opts.direction ? opts.direction: 0;
        this.name = opts.name ? opts.name: this.randomName();
        this.life = Const.DroneParam.LIFE;
        this.bullets = [];
        this.firing = false;
        this.point = {
            type: 'Point',
            coordinates: [121, 31]
        }
        this.bulletNum = 2;
    }
    // .... 省略飛控代碼蜈首。。  
  
    fire () {
        // if not firing, start firing for specific duration.
        if (!this.firing) {
            for (let i = 0; i < this.bulletNum; i ++) {
                this.bullets.push(new Bullet(this));
            }
            this.firing = true;
            setTimeout(() => this.firing = false, Cost.DroneParam.FIRINGTIME);
        }
    }
}

下面簡單看下**bullet.js **的結構:

/**
 * Bullet based on Drone instance
 */
export default class Bullet {
    // opts should contain the Drone's direction and geometry
    constructor(opts) {
        this.id;
        this.direciton = opts.direction ? opts.direction: 0;
        this.spoint = {
            type: 'Point',
            coordinates: [0, 0]
        };
        // DeepCopy the drone coords to bullet.
        this.spoint.coordinates[0] = opts.point.coordinates[0];
        this.spoint.coordinates[1] = opts.point.coordinates[1];
    }
}

常量模塊,包含靜態(tài)屬性欢策,無需實例化直接調(diào)用:

export default class Const {
}

// Static Props outside of class definition
Const.DroneParam = {
    MAXSPEED: 3.999,
    FIRINGTIME: 800,
    LIFE: 10,
    // Firing range.. 0.2 rad in LngLat
    RANGE: 0.2 
};

至此吆寨,這就完成了幾個基礎模塊的編寫,注意: 現(xiàn)在drone.js, bullet.js const.js 這幾個模塊都在項目的src文件夾下踩寇,基于Babel 和 Webpack 轉碼打包需要如下過程:

Babel 和Webpack 安裝配置

  • 首先npm 安裝Babel 和 Webpack 庫:

npm install babel-cli babel-core babel-loader webpack babel-preset-latest --save-dev

  • 第二啄清,配置 .babelrc 。在項目根目錄下創(chuàng)建 .babelrc俺孙,前面有一個點啊辣卒,別說沒玩過linux。睛榄。配置文件都這熊樣荣茫,內(nèi)容跟官網(wǎng)一樣。
{ "presets": ["latest"] }
  • 第三场靴,配置 webpack.config.js如下.
module.exports = {
    entry: {
        index: [
            "./src/app.js"
            ]
    },
    output: {
        path: "./dist/",
        filename: "bundle.js",
        // app.js 中導出的模塊都在Alex 這個Root 命名空間下
        library: 'Alex',
        libraryTarget: 'umd',
    },
    module: {
        loaders: [
        {
            // 用babel 作為 js loader啡莉,打包前轉碼為es5,沒有中間文件
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel'
        }]
    }
};

說明一下旨剥,entry.index 指向的 ./src/app.js 是應用的入口文件咧欣,也就是說,drone轨帜, bullet 等等模塊是寫好了魄咕,但是還需要一個Root 模塊來導出所有模塊(API模式)或者啟動應用(APP模式)。 當然上述兩個模式是我胡謅的蚌父,但是經(jīng)過實踐確實證明這兩種模式對應模塊化的不同需求哮兰。

  • 假如你的 業(yè)務邏輯代碼 都需要 采用es6 來模塊化編寫(往往是大型應用),那么你的app.js 應該包含業(yè)務代碼(APP模式)
  • 假如你的 模塊只是作為 API 供外部代碼調(diào)用苟弛,比如 f3earth 這樣的采用es6 編寫的 API,那么你的app.js 應該只包含模塊導出的過程(API模式)

比如我的app.js 長這樣:

import Drone from './drone';
// 引入自行封裝的Canvas奠蹬,渲染游戲場景
import Canvas from './chart/canvas';

export {
        Drone,
        Canvas
} 

這里將所有子模塊再次導出為一個根模塊,對應webpack.config.js 中配置的名為 Alex 的根模塊嗡午。在業(yè)務代碼中通過 Alex.Drone, Alex.Canvas 來調(diào)用不同的類囤躁。
至此,就完成了打包前的工作荔睹,在根目錄下 cmd中 通過webpack命令開始打包狸演。完成之后,在 dist 目錄下產(chǎn)生 bundle.js僻他,那么這個文件包含了我們剛才所編寫的所有模塊宵距,可供業(yè)務代碼調(diào)用。

如果想詳細了解 Babel吨拗,可以直接參考其官網(wǎng)栗子满哪,各種babel 的用法(npm script婿斥,或者在webpack中作為loader)
如果想了解更多關于webpack,可以參考我看過比較簡明易懂的 webpack 入門 這篇文章

寫在最后

根據(jù)上面的過程哨鸭,我基本編寫了一個架子民宿,有了幾個基礎類,但是功能還很弱像鸡,而且基于Canvas 的渲染類還在開發(fā)活鹰。你看看,這都是些造輪子的工作只估,但是難免有些人揍喜歡造輪子志群。。蘇美爾人造出輪子后還是有人在不斷通過造輪子學習蛔钙。

最后我把項目代碼放到了github上锌云,歡迎想了解 ES6 模塊化以及 Webpack 打包以及SystemJS 的同學去圍觀,clone 下來改裝下可以打造自己的飛機大戰(zhàn)啊哈哈吁脱! 另外也掛出我放在云服務器上的基于Angular-cli的WorkTile Demo桑涎,比較簡陋,歡迎圍觀豫喧。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市幢泼,隨后出現(xiàn)的幾起案子紧显,更是在濱河造成了極大的恐慌,老刑警劉巖缕棵,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孵班,死亡現(xiàn)場離奇詭異,居然都是意外死亡招驴,警方通過查閱死者的電腦和手機篙程,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來别厘,“玉大人虱饿,你說我怎么就攤上這事〈ヅ浚” “怎么了氮发?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長冗懦。 經(jīng)常有香客問我爽冕,道長,這世上最難降的妖魔是什么披蕉? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任颈畸,我火速辦了婚禮乌奇,結果婚禮上,老公的妹妹穿的比我還像新娘眯娱。我一直安慰自己礁苗,他們只是感情好,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布困乒。 她就那樣靜靜地躺著寂屏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪娜搂。 梳的紋絲不亂的頭發(fā)上迁霎,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音百宇,去河邊找鬼考廉。 笑死,一個胖子當著我的面吹牛携御,可吹牛的內(nèi)容都是我干的昌粤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼啄刹,長吁一口氣:“原來是場噩夢啊……” “哼涮坐!你這毒婦竟也來了?” 一聲冷哼從身側響起誓军,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤袱讹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后昵时,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捷雕,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年壹甥,在試婚紗的時候發(fā)現(xiàn)自己被綠了救巷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡句柠,死狀恐怖浦译,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情溯职,我是刑警寧澤管怠,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站缸榄,受9級特大地震影響渤弛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜甚带,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一她肯、第九天 我趴在偏房一處隱蔽的房頂上張望佳头。 院中可真熱鬧,春花似錦晴氨、人聲如沸康嘉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亭珍。三九已至,卻和暖如春枝哄,著一層夾襖步出監(jiān)牢的瞬間肄梨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工挠锥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留众羡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓蓖租,卻偏偏與公主長得像粱侣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蓖宦,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容