顯示具有 javascript 標籤的文章。 顯示所有文章
顯示具有 javascript 標籤的文章。 顯示所有文章

2015年3月25日 星期三

React.js - a flux example with ES6 and Babel

這篇介紹一下用最新的 ECMAScript 6 的語法並搭配 Babel 來開發一個簡單的 react/flux 的程式

同樣這次的範例程式會放在 GitHub 上 >>在這裡<<

不知道 react/flux 的可以看我>>上一篇的教學<< 有寫一個簡單的 react/flux app

對 flux 有疑問或不清楚的可以 google 找一下資料,而我之前也有寫一篇對 flux 的>>心得分享<<

接下來回到主題,ECMAScript 6 以下都會簡稱 ES6,在2014確定了所有的新功能與語法

預定在今年 2015 6月左右會正式發佈,接下來瀏覽器會慢慢完全支援 ES6 的語法

所以這篇就用 ES6 來重寫一次 react/flux 的程式

雖然目前瀏覽器並沒有完全支援 ES6 的語法,不過我們可以透過 Babel 這個工具進行轉換

Babel 的原名叫做 6to5,也就是一個能夠將 ES6 轉換為 ES5 的工具,所以也不用擔心瀏覽器對 es6 的相容性問題了

至於為什麼要這麼快用 ES6 來開發程式?如果看過 ES6 的新功能之後,確實是蠻讓人期待的,之後有空再來介紹

另外也是因為有了 Babel 這類的工具,讓目前尚未完全支援 ES6 的情況下

可以開始專攻 ES6,等到之後 ES6 完全被瀏覽器支援後,你也不用考慮要重新寫程式了,因為你已經是在寫 ES6了

2014年10月23日 星期四

Grunt 教學 - 檔案管理(1)

本篇會介紹部分 Grunt 如何操作檔案,如果對 Grunt 不熟的可以先看 Grunt 教學 - Getting Started

在使用 Grunt 建構 JavaScript 專案時一定會常常接觸到檔案或是資料夾的整理

或是你想寫一些相關的 Grunt plug-in 時,也會遇到相同的情形

因為篇幅的關係,所已先簡單介紹一下如何建立與刪除資料夾

之後有空再補充其他關於檔案管理的技巧

以下是建立資料夾的 Grunt 程式

module.exports = function(grunt){
     grunt.initConfig({
         file: {
              params: {
                  sampleFolder: "sample"
              }
         }
     });
    grunt.registerTask("createFolder", function(){
         // grunt.config.requires() 會確保 config 有被設定
         // 如下就會確保 file.params.sampleFolder 是有先被設定過的
         // 假如沒有設定會拋出以下訊息
         //   Verifying property file.params.sampleFolder exists in config...ERROR
         //   >> Unable to process task.
         //   Warning: Required config property "file.params.sampleFolder" missing. Use --force to continue.
         grunt.config.requires("file.params.sampleFolder");

         // 利用 grunt.config.get() 來取得 config 的值
         grunt.file.mkdir(grunt.config.get("file.params.sampleFolder"));
    });

}

完成之後在你專案的 root 目錄下執行 Grunt 的指令 $grunt createFolder

結束之後,會在你的專案目錄下看到一個 sample 的資料夾

如果是刪除資料夾的話,就用 grunt.file.delete(),如下所示

grunt.registerTask("deleteFolder", function(){
         grunt.config.requires("file.params.sampleFolder");
         grunt.file.delete(grunt.config.get("file.params.sampleFolder"));

});

所以同樣在你專案的 root 目錄下執行 Grunt 的指令 $grunt deleteFolder

就會發現剛剛建立的 sample 資料夾被移除了

2014年10月6日 星期一

Grunt 教學 - Getting Started

Grunt 是一個 JavaScript Task Runner,這是 Grunt 的官方網站 GRUNT : The JavaScript Task Runner

它真正的目的是讓開發者可以更容易的建構(Build)他們的 JavaScript 專案

在一般的建構過程中,不外乎包含自動化測試、JS 與 CSS 的壓縮或合併、檔案操作等等

而且目前 JavaScript 專案或多或少都會包含很多第三方套件,會讓你的建構過程相當複雜

所以現在 Grunt 也有很多 Contributors 貢獻了很多的 Grunt plug-ins 來改善建構的過程

因此有了 Grunt 與這些 plug-ins 工具之後,勢必能夠改善你的工作效率

接下來就初步介紹一下 Grunt 的安裝與使用

2014年9月10日 星期三

AngularJS 教學 - Ajax(1)

上一篇 簡單介紹了 AngularJS 使用 Ajax 的方式 接下來繼續介紹一些 AngularJS 常用的 Ajax 設定

AngularJS 利用 $http 這個 Service 物件做為 Ajax 的一個管道

但是在多數複雜的應用中,我們的 Ajax 請求或回傳可能稍微複雜需要設定一些額外的參數

譬如說 HTTP 的請求表頭、HTTP 的 method(POST、PUT、DELET)之類的

所以以下列出幾個比較常用到的參數設定

首先在上一篇看過一個簡單的 Ajax 方式,如下:

$http.get("todos.json").success(function (data) {
    return data;
});

如果要加上額外的設定,可以類似這樣:

var config = {
    //你的設定參數在這
};
$http.post("/todos", config).success(function (data) {
    return data;
});

2014年8月16日 星期六

AngularJS 教學 - 模組化及開發模式

AngularJS 提供了一個 Javascript 的 MVC 框架讓開發者能夠輕易的在前端開發中實現 MVC 架構

但我認為 AngularJS 帶給前端開發者最重要的思維還是模組化以及開發模式

先從模組化談起

模組化(Modularity)已經是前端開發中一個很重要的準則了,就像大部分書籍說的

模組化能夠讓我們更能夠輕易重用(reuse)各個模組,另外能夠讓你容易地進行測試

也能夠幫助開發者快速並明確地釐清一個大型的前端應用的架構

但要組織一個大量模組間相互依賴的關係其實是一個蠻重要的課題

如果處理不當容易造成模組間的緊密耦合關係,並且降低重用性以及難於測試

要如何解耦?你可以透過 Mediator Pattern 或是 Observer Pattern 這類型的設計模式

這其實就有點像是 Event Driven Development

2014年8月3日 星期日

AngularJS 教學 - Ajax

AngularJS 教學 - MVC 介紹 中有特別提到 Model(模型) 的職責

其中一項就是用來跟後端作資料的操作 (CRUD)

而 AngularJS 提供了 REST 以及 Ajax 這兩種方式讓你能夠跟後端的應用程式作溝通

以下就介紹 AngularJS 的 Ajax 方法吧

首先 AngularJS 提供了 一個 Service 讓開發者能夠運用 Ajax,那個 Service 就叫做 $http

當你的模組需要用到 Ajax 的時候,可以將 $http 直接注入到你的模組中,就像 Controller 的 $scope 一樣

接著就看一下一個簡單的範例吧

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="demoApp">
     <head>
         <title>Examples</title>
         <script type="text/javascript" src="js/angular.min.js"></script>
         <script>
              var demoApp = angular.module("demoApp", []);
              demoApp.factory("Todo", function($http){
                  return {
                       list: function(){
                            $http.get("todos.json").success(function (data) {
                                return data;
                            });
                       }
                  };
              });
              demoApp.controller("demoCtrl", function($scope, Todo){
                  $scope.loadData = function(){
                       $scope.todos = Todo.list();
                  }
             });
         </script>
     </head> 
     <body>
         <div ng-controller="demoCtrl">
              <button ng-click="loadData()">Load Todos</button></br>
              <table>
                  <tr>
                       <td>NO.</td><td>Name</td><td>Priority</td>
                  </tr>
                  <tr ng-repeat="todo in todos">
                       <td>{{todo.id}}</td>
                       <td>{{todo.name}}</td>
                       <td>{{todo.priority}}</td>
                  </tr>
              </table>
         </div>
     </body>

</html>

2014年7月23日 星期三

AngularJS 教學 - provider method

在前兩篇
AngularJS 教學 - factory method
AngularJS 教學 - service method

介紹到了三種建立 service 的其中兩個方法,factory 與 service

最後就要來介紹第三種方法,provider

provider 方法是 AngularJS Module 所提供的一個建立 Service 的方法 (Module.provider)

provider 方法與其他兩個最大的不同在於它能夠對 Service Object 做額外的設定(Configured)

再談到如何做額外的設定之前,我們先來看一個基本的 provider 方法如何使用

var demoApp = angular.module("demoApp", []);
demoApp.provider("echoService", function(){
return {  //It's Provider Object
$get: function(){
            return {  //It's Service Object
               echoCount: 0,
               echo: function(name){
                   console.log((this.echoCount++) + ", Your name is " + name);
               }
            };
        }
}

});

2014年7月21日 星期一

AngularJS 教學 - service method

上一篇 AngularJS 教學 - factory method 講到了 AngularJS 建立 Service 的其中一個方法

如果不知道什麼是 Service 的,可以看 AngularJS 教學 - Service

接下來要介紹的是另外一種建立 Service 的方法,就是 service 了啦!

service方法是 AngularJS Module 所提供的一個建立 Service 的方法 (Module.service)

使用方式跟 factory 方法很像,同樣是傳入兩個參數

分別是 Service 的名稱以及一個建構子(Constructor)

這也是和 factory 方法的差別所在

factory 方法是要提供一個能夠回傳一個 Service Object 的工廠方法

而 service 方法則是要提供一個建構子函式,目的在於 AngularJS 底層會利用 new 這個關鍵子

來建立出你的 Service Object

簡單說就是

2014年7月17日 星期四

AngularJS 教學 - factory method

factory 方法是 AngularJS Module 所提供的一個建立 Service 的方法 (Module.factory)

如果不知道什麼是 Service 的,可以先看看 AngularJS 教學 - Service

使用方式就是利用 Module 的 factory 方法,並傳入兩個參數

分別是 Service 的名稱以及一個能夠回傳 Service Object 的工廠方法 (Factory Function)

以下我列舉了一個範例

var demoApp = angular.module("demoApp", []);
demoApp.factory("echoService", function(){
    var echoCount = 0;
    return {
        echo: function(name){
            return console.log((echoCount++) + ", Your name is " + name);
        }
    };

});

AngularJS 教學 - Service

在上一篇 AngularJS 教學 - Module 提到了 AngularJS 的 Module (模組),接下來要介紹的也跟 Module 有關係

那就是 Service 了,Service 可以把它想做是一個提供某一項服務的物件

至於在開發一個 AngularJS 的應用程式時,到底時麼時候該需要使用 Service 呢?

簡言之,Service 封裝了某一個定功能的實作邏輯,讓你能夠在不同模組之間重覆使用(reuse)

或是這樣的某一特定功能可能比較難融入到 MVC 的架構內

例如應用程式中的 logging 機制,就是一個很典型的 Service 例子

而 AngularJS 的 Module 提供了三個方法(method)來定義你的 Service

分別是 factory、service 以及 provider

這三個方法的結果完全是一樣的,就是一個 Service Object (注意:是一個物件)

而這三種方法的差別其實僅在於 Service Object 的建立與管理的過程

2014年7月13日 星期日

AngularJS 教學 - Module

這篇我介紹一下 Module 在 AngularJS 中扮演的角色,在正式介紹之前

其實在任何一個 AngularJS 的應用程式你都已經有使用到了

沒錯,就是 ng-app 這個 AngularJS 的 Directive,可以看 AngularJS 教學 - 第一個AngularJS App

所以這邊就不再多加解釋 ng-app 了

那我們就來詳細說一下 AngularJS 的 Module:

  • 什麼是 Module
          Module 就是模組的意思,它能夠幫助我們組織整個應用程式的元件(Controller、Model、Filters...)
          因此除了幫助我們更好理解整體架構外,也可以讓整個應用程式的各種元件可以分散在
          正確的 JS 檔案內,並透過 script 標籤載入這些元件,畢竟真實世界中的大型專案,並非
          像我們之前的範例這樣,將所有的 JS 程式寫在 HTML 內。

  • Module 的使用時機
          建議再做任何 AngularJS 的專案時,最好多多利用 Module 的概念去組織你的程式
          除了有上述的優點之外,也可以再多個 AngularJS 的應用中重覆使用(reuse)你的 Module

2014年7月10日 星期四

AngularJS 教學 - Attribute Directives

在  AngularJS 教學 - Element Directives 有提到幾個 AngularJS 中常用的 Element Directives

這些 Element Directive 都是能夠幫助開發者動態地新增或修改 HTML 元素或是 CSS

而接下來要介紹一些蠻常用到的 AngularJS Attribute Directive

Attribute 就是指 HTML 元素中的屬性,像是 disabled、checked

下表列出幾個常用的 Attribute Directive

2014年7月2日 星期三

AngularJS 教學 - 事件處理

本篇說明一下事件處理的方式以及種類,最後在說明 AngularJS 對於 Event 的定義

在 MVC 中的視圖(View),除了需要將資料做呈現之外,另外一個工作就是註冊事件了,

只要是寫過 Javascript 或是 jQuery 或是任何一種 Widget 的套件,都一定會處理這些事件的

例如 Javascript 的 onClick 事件,我們會將 onClick 屬性寫在 button 元素上,並指定一個

callback function 來執行按下按鈕時的處理邏輯,在AngularJS 教學 - Controller and View中有提到

AngularJS 在撰寫這一類的事件處理時,會由 View 負責註冊事件,由 Controller 負責處理

事件的後續邏輯。

以下是從官方網站節錄出來的事件列表,大致上看看就好了
ng-click ng-dblclick ng-change ng-blur ng-focus
ng-keydown ng-keypress ng-keyup ng-submit ng-mousedown
ng-mouseenter ng-mouseleave ng-mousemove ng-mouseover ng-mouseup
ng-copy ng-cut ng-paste

2014年6月30日 星期一

AngularJS 教學 - Element Directives

本篇介紹一下幾個常用的 AngularJS Directives,建議可以先看 AngularJS 教學 - Templates

AngularJS 教學 - Templates 提到了幾個好用的 Template Directives,

而接下來要介紹的 Directives 主要是用來對 HTML 元素做動態修改或是 CSS 調整

以下我依序分享這些好用的 Directives

  • ng-if
          從字面上就知道這是要用來做什麼啦,ng-if 屬性接受一個布林值,如果是 true 的話
          那 ng-if 的標籤內容就會顯示出來,範例如下:
          <span ng-if="flag">Flag is True</span>
      <span ng-if="!flag">Flag is False</span>
 
  • ng-show & ng-hide
          這也是一個蠻明顯易用的 Directive 拉,跟 ng-if 一樣是接受一個布林值,ng-show
          為 true 時會顯示反之則不顯示,至於 ng-if 同樣道理,範例如下:
      <span ng-hide="flag">Hide</span>
      <span ng-show="flag">Show</span>

2014年6月28日 星期六

AngularJS 教學 - Templates

Templates 在 AngularJS 中的視圖(View)是相當重要的一環,它跟多數套件的 Templates 有著相同的功能。

而 AngularJS 的 Templates 則是包括了 AngularJS 特殊的屬性(ex: ng-model)或元素(Directives)

所以 AngularJS 會融合 Templates 與 Model 和 Controller 的資訊來做到 View 的渲染以及 Two-Way Binding

本篇介紹一些常用或是好用的 AngularJS Templates:


  • ng-repeat
          ng-repeat 幾乎是一定會用到的一個 AngularJS 標籤屬性,他目的是用來在畫面上將
         多筆資料的 Model 用迴圈的方式一個一個的建立到視圖上,如下範例所示:
         
         <script>
              var demoApp = angular.module("demoApp", []);
              demoApp.controller("demoCtrl", function($scope){
                  $scope.users = [
                     {uid:'1', name: 'Allen', phone: '12493215'},
                     {uid:'2', name: 'Alex', phone: '70314568'},
                     {uid:'3', name: 'Alice', phone: '345106847'}
                  ];
             });
     </script>
     <div ng-controller="demoCtrl">
              <ul>
                  <li ng-repeat="user in users">
                       Name: {{user.name}} <br/>
                       Phone: {{user.phone}} <br/>
                  </li>
              </ul>
     </div>
        

2014年6月27日 星期五

AngularJS 教學 - Data Binding

在 AngularJS 教學 - Controller and View 文章中我們介紹了 Controller 和 View 之間的關係

其中一個在 AngularJS 內相當重要的觀念就是 Data Binding (資料繫結)

在 AngularJS 的官網也有特別說明到這一點,這也是 AngularJS 相當重要的特點之一

其中 Data Binding 可以分為 One-Way 以及 Two-Way,當然 AngularJS 是建議你使用 Two-Way

先從 Onw-Way Data Binding 開始說起吧

















One -Way Data Binding 的目的在於要產生 View 之前,會將定義好的樣版(Template)與

樣版內對應的模型(Model)做合併(merge)的動作,再呈現在 View 上面,但其缺點在於

2014年6月25日 星期三

AngularJS 教學 - Controller 進階(2)

上一篇我們延續了 AngularJS 的 MVC 教學,並更深入的解釋 Controller 的一些共通問題

可以看 AngularJS 教學 - Controller 進階(1) 來先對 Controller 有更進一步了解

接下來要說明一個 Controller 繼承的陷阱,還記得上一篇有講到巢狀的 Controller 嗎

其實就是 Scope Inheritance 的意思,以下先用一個範例說明這個陷阱

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="demoApp">
     <head>
         <title>Bootstrap Examples</title>
         <script type="text/javascript" src="js/angular.min.js"></script>
         <script>
              var demoApp = angular.module("demoApp", []);
              demoApp.controller("parentCtrl1", function($scope){
                  $scope.count = 1;
                  $scope.add = function(){
                     $scope.count++;
                  };
             }).controller("childCtrl1", function($scope){
                  $scope.minus = function(){
                     $scope.count--;
                  };
             })
         </script>
     </head>
     <body>
         <div ng-controller="parentCtrl1">
              <p>Parent count: {{count}}</p>
              <button ng-click="add()">+1</button>

              <div ng-controller="childCtrl1">
                  <p>Child count: {{count}}</p>
                  <button ng-click="add()">+1</button><button ng-click="minus()">-1</button>
              </div>

         </div>
     </body>

</html>

先簡單說明一下程式,可以看到我定義了兩個Controller,分別是 parentCtrl1 與 childCtrl1

其中 childCtrl1 繼承 parentCtrl1,而  parentCtrl1 定義一個 add function 會聆聽頁面上

兩個 "+1" 的按鈕事件,而 childCtrl1 則定義一個 minus function 會聆聽頁面上的 "-1" 按鈕事件

其中 add function 雖然 childCtrl1 沒有定義,但因為繼承關係

執行時會去乎叫父類別的 add function,所以也不會有任何問題

$scope.count 也是如此,雖然 childCtrl 內沒定義但是依照繼承關係,也是會找到父類別的

乍看之下沒什麼問題,但在畫面操作時你可能會發現一些 bug,入下圖所示

我先按下上面的 +1按鈕 ,你會發現兩個 Controller 的 count 都會變 2,這是正確的














再按下下面的+1按鈕,同樣兩個直都會變 3,這也沒什麼問題














之後按下下面的 -1 按鈕, Child count 的直就會變成 2,但是上面的 Parent count 並沒有變
2,這是有問題的,因為 childCtrl1 的 $scope.count 是繼承於 parentCtrl1 的 count ,他們應該是同一個 Reference 才對














這時候再按下 任何一個 +1 按鈕,你會發現下面的 Child count 永遠不會被加1了












一開始遇到還以為是程式寫錯或是 AngularJS 的臭蟲,但其實這是正確的,

先來探討這個問題如何產生的,我們知道所有問題都是再按下 -1 的按鈕之後所造成的

其實 childCtrl1 的 minus function 並沒有什麼問題,問題再於 $scope.count 之上

首先 childCtrl1 並沒有在他的 scope 內定義 count,他是使用(reuse) parentCtrl 的 scope count

這沒錯,畢竟我的目的就是要在這兩個不同的 view 上顯示同一個資料,沒必要分開定義

問題是在於 當我出發 mins function 的時候,因為 childCtrl1 的 scope 並沒有宣告 count

因此他在執行 $scope.count--; 的時候,會預設幫你在這個 childCtrl1 的 scope 定義一個 count

因此這時候兩個 Controller 的 count 就分別獨立了,因此不管你按了哪個 +1按鈕,child count 永遠都不會動了

該如何解決,你只要如下更改程式即可


<script>
      var demoApp = angular.module("demoApp", []);
      demoApp.controller("parentCtrl1", function($scope){
          $scope.data = {
           count: 1
        };
          $scope.add = function(){
              $scope.data.count++;
          };
      }).controller("childCtrl1", function($scope){
          $scope.minus = function(){
              $scope.data.count--;
          };
      });
</script>

<div ng-controller="parentCtrl1">
      <p>Parent count: {{data.count}}</p>
      <button ng-click="add()">+1</button>
      <div ng-controller="childCtrl1">
          <p>Child count: {{data.count}}</p>
          <button ng-click="add()">+1</button><button ng-click="minus()">-1</button>
      </div>
</div>

可以注意到粗體部分,我只將換了一個宣告方式,我不直接在 scope 內定義一個 count 屬性

而是在 scope 內定義一個物件,而物件內才有 count 屬性!!

這樣就解決所有問題了....QQ

為什麼會這樣,其實這是因為 Javascipt 的繼承機制造成的(prototype inheritance),

相信對 Javascript 有一定了解的都會聽過 ~

至於實際的原理就不多說了,因為那又是另一個很深度的話題了