Jame's Blog

前端開發心得 front-end Develop

超好用的 Postman 自動化測試

| Comments

如何使透過Postman進行大量測試

環境設定

  1. 讓 Postman 顯示 console.log
  2. 讓Postman啟用開發者工具原文
    1. 在chrome瀏覽器上輸入chrome://flags
    2. 尋找debug-packed-apps字串
    3. 啟動選項
    4. 重開chrome
    5. 輸入chrome://inspect/#apps
    6. 點開Pstman下方的inspect

透過CSV或JSON檔進行測試 原文

  1. 點開 Runner
  2. 選擇要測試的collection
  3. 選擇iteration數量,可以控制測試的數量

如何使用CSV中的變數?

在request 中是用雙括號{{varname}}
在tests 或prescript 是用data.varname 或data['username']

fancybox 的 ios bug

| Comments

今天在練習做 lightbox 裡面放 image carousel 的功能
好不容易做完後,
在ios 中測試竟然 Scrolling 的時候整個lightbox 變空白

網路上某個範例:
http://jsfiddle.net/STgGM/1329/
在iOS上Scrolling 然後就變白色..
然後我的臉也變慘白.....
應該是iOS的Bug吧?XD

解決方法其實蠻簡單的,江湖一點訣說破不值錢
當時我想說晃一下iOS裝置,旋轉看看~
沒想到畫面就正常了。
因此可以推論~
就是在載入iframe的內容後
強迫瀏覽器重新繪製畫面
這個問題就解決了

docker 相關參考文件

| Comments

關於 docker-compose 的設定

docker compose 範例

docker-compose.yml

report-dev-server:

  build: . #執行位置

  dockerfile: reportServer/Dockerfile  #相對執行位置

  container_name: report-dev-server  #容器名稱

  volumes:

    - ./reportServer/www:/www

  ports:

    - "3000:3000"

    - "3001:3001"

    - "3002:3002"

  stdin_open: true #開啟標準輸入(stdin)

  # tty: true #終端機



# 必須先在 report-dev-server 中執行 yarn run build

# 有了 build 資料夾之後才能使 report-server 正常運作

蛋頭教室 如何使用 npm script 變成你的建立工具 重點筆記

| Comments

egghead

How to Use npm Scripts as Your Build Tool

https://egghead.io/lessons/tools-use-a-shorthand-syntax-for-running-multiple-npm-scripts-with-npm-run-all

1. 建立基本的 package.json 檔案

  1. 輸入 npm init
  2. 接著輸入基本資料
  3. 若你不想要輸入資料可以透過下列的參數
npm init --yes
npm init --force
npm init -y
npm init -f

以上方式都是同等效用

2. 執行基本的指令 / test 與 start

{
  "name": "practice",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "James Yang",
  "license": "MIT"
}
  1. 修改 scripts 的部份加入測試項目
    1. 例如:"test" : "mocha spec/ —require babel-register"
    2. 執行測試 npm testnpm t
  2. 修改 scripts 添加 start
    1. 例如:"start":"node index.js"
    2. 啟動項目 npm start

3. 建立自訂的指令

除了基本的 start 與 test 你也可以撰寫自訂的指令
但此之前,如何透過環境變數,讓 npm 知道你的檔案位置在哪,然後透過指令的方式執行它
可以使用 npm bin 找出本地端的 node_module 執行檔的資料夾,然後用在 sciprt 指令中

例如:

"eslint" : "$(npm bin)/eslint --cache --fix ./"

若要啟動,執行 npm run eslintnpm run-script eslint 即可啟動

你可以透過 npm run env,列出相關的環境設定
透過 npm run env | grep "^PATH" 找出 PATH 的設定
列出來之後會發現 /Users/james/Projects/James/practice/node_modules/.bin 有列在 PATH 中
所以不需要再 script 上面加 $(npm bin) ,直接執行 eslint 即可

4. 執行串連指令

如果你想要透過一個指令,執行數個指令的話可透過 && 將指令串接在一起
例如:

{
  "scripts": {
    "test": "mocha tests/node-test.js",
    "start": "node index.js",
    "eslint": "$(npm bin)/eslint --cache --fix ./",
    "serial": "npm test && npm start && npm run eslint"
  }
}

執行:npm run serail

5. 執行並連指令

直接把 && 改成 & 即可

{
    "scripts": {
    "test": "mocha tests/node-test.js --watch & wait",
    "start": "node index.js",
    "eslint": "$(npm bin)/eslint --cache --fix ./",
    "serial": "npm test && npm start && npm run eslint",
    "parallel" : "npm test & npm start & npm run eslint"
  }
}

執行 : npm parallel
test 的部分,加上了 --watch 指令,此時 mocha 會監聽 tests/node-test.js 檔案,若有異動就會重新執行。
如果這時候你用 ^C (control+C)將程序關閉的時候, --watch 並不會停止, 可以使用 ps -xa | grep mocha 找出正在監聽的程序 然後用 kill -9 id 將正在監聽的程序終止。為了避免這個狀況發生,就必須在後面加上 wait 指令。確保在中斷的時候停止監聽。

6. 透過 npm-run-all 取代原本的指令

先安裝 npm-run-all

npm i npm-run-all -D

-D 同等於 --save-dev
i 同等於 install

接下來可以把 script 中 npm 與 && 的部分取代掉,直接用 npm-run-all 執行並聯程序。
若要併發的話可以加上 --parallel 參數取代

取代並聯方式

修改前

{
  "scripts": {
      "test": "mocha tests/node-test.js --watch & wait",
      "start": "node index.js",
      "eslint": "$(npm bin)/eslint --cache --fix ./",
      "serial": "npm test && npm start && npm run eslint",
      "parallel" : "npm test & npm start & npm run eslint"
    }
}

使用 npm-run-all 套件不需要使用 wait 指令
修改後

{
  "scripts": {
      "test": "mocha tests/node-test.js --watch",
      "start": "node index.js",
      "eslint": "$(npm bin)/eslint --cache --fix ./",
      "serial": "npm-run-all test start eslint",
      "parallel" : "npm-run-all test start eslint"
    }
}

7. 透過配通符號(wildcard) 執行相似的指令碼

當我們有好幾個 script 名稱格式相似,可以透過配通符號執行
例如:

  • lint:js
  • lint:css
  • lint:css:fix

可以使用 lint:* 或 lint:** 執行所有相似的 script
具體的作法如下:

{
  "scripts": {
      "test": "mocha tests/node-test.js --watch",
      "start": "node index.js",
      "eslint": "$(npm bin)/eslint --cache --fix ./",
      "serial": "npm-run-all test start eslint",
      "parallel" : "npm-run-all test start eslint",
    }
}

8. 使用事前執行與事後執行的觸發事件

當執行 script 的時候,可以透過命名的規則,在執行前或執行後添加執行的 script

  • pre 事前
  • post 事後

只要根據執行指令的名稱加上 pre 或 post 即可
例如: customScript
事前執行的 script 取名為 precustomScript
事後執行的 script 取名為 pastcustomScript
即可

然後調用 npm run customScript
就會依序執行

處理 stylefmt 的問題
執行 lint:css:fix 時發現問題
原來是因為 stylefmt 第五版之後就把參數 -R 改為 -r 了
另外延伸的問題是 怎麼指定多個目錄
方法如下

stylefmt -r src/*.css scss/*.scss
stylefmt -r {src/*.css,scss/*.scss}

上面兩個方式等效
此語法稱之為 glob patten

完成的範例:

{
  "name": "practice",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "precustomScript": "echo 'precustomScript running'",
    "postcustomScript": "echo 'postcustomScript running'",
    "mocha": "mocha tests/node-test.js --watch",
    "customScript":  "echo 'npm run customScript'",
    "test": "npm-run-all lint mocha",
    "start": "node index.js",
    "eslint": "$(npm bin)/eslint --cache --fix ./",
    "serial": "npm-run-all test start eslint",
    "parallel": "npm-run-all --parallel test start eslint",
    "lint":"npm-run-all lint:**",
    "lint:js": "eslint --cache --fix ./",
    "lint:css": "stylelint '**/*.scss' --syntax scss",
    "lint:css:fix": "stylefmt -r 'src/*.css, scss/*.scss'"
  },
  "keywords": [
    "npm",
    "script",
    "practice"
  ],
  "author": "James Yang",
  "license": "MIT",
  "devDependencies": {
    "eslint": "^3.14.1",
    "npm-run-all": "^4.0.1",
    "stylefmt": "^5.1.1",
    "stylelint": "^7.8.0"
  }
}

9. 丟參數給 npm scripts

透過兩個 -- 放在 npm 的指令與參數中間
例如:

{
    "watch:test" : "npm test -- --watch"
}

10. 透過指令將不同的 script 串連起來

綜合先前的教學,將不同程序的 script 串聯在一起
範例:

{
  "build" : "npm-run-all build:*",
  "prebuild": "rm -rf public/",
  "build:html" : "pug --obj data.json src/index.pug --out public/",
  "build:css" : "node-sass src/index.scss | postcss -c .postcssrc.json | cssmin > public/index.min.css",
  "build:js" : "mustache data.json src/index.mustache.js | uglifyjs > public/index.min.js"
}

11. 透過 onchange 當程式改變時執行 npm script 指令

範例:當執行 npm run watch 時會同時執行 watch:test 與 watch:lint
需安裝 https://www.npmjs.com/package/onchange 執行 npm i onchange -D
即可透過 script 指令 onchange 監聽檔案改變事件,觸發執行

{ 
  "watch":"npm-run-all --parallel watch:*",
  "watch:test" : "npm t -- --watch",
  "watch:lint" : "onchange '**/*.js' '**/*.scss' -- npm run lint"
}

12. 在 npm script 中使用 package.json 變數

透過 npm run env 指令,可以列出所有 package.json 中可以參考的變數
再透過 grep 取出需要項目

npm run env | grep "npm_package" | less 

然後可以看到有個變數稱為 npm_package_version
可以直接套用在 package.json 中 前面加上 字符號
像這樣:

{
  "precustomScript":"echo 'precustomScript running' $npm_package_version"
}

要注意要放在雙引號裡頭,單引號外面才會是變數值,不然會被當成字串使用。

13. 在 package.json 中添加 config 作為參考

例如:

"config" : {
  "port" : "1337"
}

如何取得這個值呢? 就像取得變數方式相同 $npm_package_config_port
同理,用任何的字串當key都可以行得通,
可以先透過 npm run env | grep "npm_package_config"  的方式先行驗證

14. 透過 git hook 執行 npm script

使用 hasky 外掛,可以協助我們在執行 git 指令的時候,觸發 npm 的 script 內容

npm i husky -D
{
  "scripts": {
    "precommit": "npm test",
    "prepush": "npm test",
    "...": "..."
  }
}

當你做 git 指令操作的時候 git commit -m "Keep calm and commit"
就會觸發 npm test
所有的事件清單

Git hook npm script
applypatch-msg applypatchmsg
commit-msg commitmsg
post-applypatch postapplypatch
post-checkout postcheckout
post-commit postcommit
post-merge postmerge
post-receive postreceive
post-rewrite postrewrite
post-update postupdate
pre-applypatch preapplypatch
pre-auto-gc preautogc
pre-commit precommit
pre-push prepush
pre-rebase prerebase
pre-receive prereceive
prepare-commit-msg preparecommitmsg
push-to-checkout pushtocheckout
update update

15. 修改 console 輸出的程度

npm start 指令後面,可以加上不同的旗標 (flags)。
可以適當的調整 npm script 輸出的訊息內容

-s, --silent: --loglevel silent
-q, --quiet: --loglevel warn
-d: --loglevel info
-dd, --verbose: --loglevel verbose
-ddd: --loglevel silly

更多參數說明

16. 讓 npm script 跨平台更友善

建立一個 window 系統或 linux 或 macos 系統可兼容的 npm script
需要注意到很多細節,並透過相關的套件處理

  1. 在 windows 中 NODE_ENV 不是內部或外部命令,也不是可運行的程序,必續透過 npm 套件 cross-env 處理。 安裝完後,直接在 NODE_ENV 前面添加 cross-env 範例:


"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"

  1. 在 window 無法混用單引號跟雙引號,必須要用脫逸字元把單引號 ' 改為 \"

例如:


"watch:lint" : "onchange '**/*.js' '**/*.scss' -- npm run lint"
改為
"watch:lint" : "onchange \"**/*.js\" \"**/*.scss\" -- npm run lint"

  1. npm 的環境變數,在windows 也無法直接使用 字號,必須安裝 cross-var ,使用方式與 cross-env 相同


windows 的寫法為
"server:launch": "opn http://localhost:%npm_package_config_port%"
使用 cross-env 之後
"server:launch": "cross-var opn http://localhost:$npm_package_config_port"

  1. rm -rf 改為 rimraf

17. 列出 npm script 可用項目與支援 tab 提示功能

透過指令 npm run | less   可以將 專案中的 package.json 裏頭能夠執行 script 列出,另外可以透過安裝 completionntl 套件 透過 tab 鍵自動提示

  1. 設定 bash 支援提示功能

    1. 透過 completion 設定 bash
    2. 若使用 fishshell 得改用 npm.fishlink 放到 ~/.config/fish/completions/npm.fish
  2. 安裝 ntl 套件,透過 ntl 採用詢問的方式執行 script

shell
$ npm install -g ntl

直接在專案資料夾輸入 ntl 即可

18. 添加註解

如果你需要再 package.json 中添加註解,雖然 json 是不能寫註解,但是可以透過一些做法,添加額外的辨識。
例如:

"scripts": {
    "//" : "Run, build, and serve"
    "start": "#🚀 Run, build, and serve \n\t node index.js",
   }

19. 透過 p-s 讓 npm script 寫在 package-scripts.js

原生的 package.json 天生有一些限制,我們可透過 p-s 改用 package-scripts.js 格式載入設定。
如此一來就可以在裡頭寫註解或撰寫邏輯程式

$ npm install --global p-s

初始化 package-scripts.js

$ nps init     

但裡頭的程式碼就要把 npm 改為 nps ,且 npm-run-all 就不能使用了,也不能使用配通符號,需要改成用逗點的方式串接。例如 "lint":"npm-run-all lint:**", 就要改成 nps lint:test,lint:css,lint:css:fix

20 .透過 bash script 替換複雜的 npm script

可以透過 npm 執行 bash 指令

{ "test" : "./scripts/test.sh" }

記得 test.sh 的檔案標題要設定 bash

#!/usr/bin/env bash
echo "Building..."
rm -rf public/$npm_package_version
echo "Finished"

21.也可以透過 node script 取代 npm script

mkdir scripts
touch scripts/{test,build,server}.js
import { exec } from "shelljs";
const isWindows = process.platform;
exec(`BABEL_ENV=test mocha spec/ --require babel-register`);

Hummus 學習筆記

| Comments

使用範例:

var express = require('express');
var app = express();

var hummus = require('hummus');

app.get('/', function(req, res) {
    res.writeHead(200, {'Content-Type': 'application/pdf'});
    // 輸出成檔案

    // var pdfWriter = hummus.createWriter(__dirname + '/output/TestOnlyMerge.pdf');

    // 輸出成網頁

    var pdfWriter = hummus.createWriter(new hummus.PDFStreamForResponse(res));

    // var pdfWriter = hummus.createWriter(new hummus.PDFRStreamForFile('./pdf/pdf-sample.pdf'));

    var page = pdfWriter.createPage(0, 0, 595, 842);

    pdfWriter.startPageContentContext(page).writeText(`雲端互動`, 0, 842 - 12, {
        font: pdfWriter.getFontForFile('./fonts/microsoft-jhenghei.ttf'),
        size: 12,
        colorspace: 'gray',
        color: 0x00
    });
    pdfWriter.writePage(page); //新增頁面


    //添加

    pdfWriter.appendPDFPagesFromPDF(__dirname + '/pdf/Qu_Mod3.PDF', {
        type: hummus.eRangeTypeSpecific,
        specificRanges: [
            [0, 2]
        ]
    });

    //合併

    pdfWriter.mergePDFPagesToPage(page, __dirname + '/pdf/Qu_Mod3.PDF', {
        type: hummus.eRangeTypeSpecific,
        specificRanges: [
            [2, 2]
        ]
    });

    pdfWriter.writePage(page); //新增頁面


    // 添加共用元素

    // var xobjectForm = pdfWriter.createFormXObject(0,0,200,100);

    // xobjectForm.getContentContext().q().k(0,100,100,0).re(0,0,200,100).f().Q();

    // pdfWriter.endFormXObject(xobjectForm);

    //

    // var pageContent = pdfWriter.startPageContentContext(page);

    // pageContent.q()

    //         .cm(1,0,0,1,200,600)

    //         .doXObject(xobjectForm)

    //         .Q();


    //結束

    pdfWriter.end();
    res.end();
});
app.listen(3000);

Redux 學習筆記

| Comments

Redux 學習筆記

使用 create-react-app 建立開發環境

本篇內容參考來源 Create React Apps

  1. 安裝react開發環境產生器

    npm install -g create-react-app

因為自己設定太累了,直接用生成器產生專案環境,會比較方便。

安裝完成之後,
就可以使用 create-react-app [資料夾名稱] 的指令建立專案資料夾

  1. 然後我們輸入 create-react-app todos

  2. 接著就會建立完成

  3. 然後輸入 cd todos

  4. 啟動開發環境 npm start

  5. 然後輸入 http://locahost:3000/

ESlint 設定

package.json 添加 eslintConfig 屬性,或是使用 eslint --init 建立規則。

下方為 eslint --init 產生的 .eslintrc.js

module.exports = {
    "env": {
        "browser": true,
        "es6": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "installedESLint": true,
    "parserOptions": {
        "ecmaFeatures": {
            "experimentalObjectRestSpread": true,
            "jsx": true
        },
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "no-console": "off",
        "react/jsx-uses-react": "error",
        "react/jsx-uses-vars": "error",
        "indent": [
            "error",
            4
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ]
    }
};

才不會一直看到 no-user-varable 的提示,超煩的。

以上內容是設定 reactjs 的開發環境,接下來繼續做其他項目。

安裝redux

npm install --save redux

補充性套件

npm安裝

npm install --save react-redux
npm install --save-dev redux-devtools

yarn 安裝

yarn add react-redux -S
yarn add redux-devtools -D  

綁定工具與開發者工具

Atom 的 auto-beautify 設定

目前在 官網上可以找到一些支援 jsx 的語法格式,auto-beautify 提供對 JSX 的格式化功能。

  1. language-babel 文件格式 Babel ES6 JavaScript ,**** 推薦,Atom 可以自動偵測,不需要手動切換。
  2. language-javascript-jsx 文件格式 JavaScript with JSX
  3. react 文件格式 JavaScript (JSX)

開發工具備齊了~

npm start   

啟動環境 http://localhost:3000/

~~等等,還沒辦法馬上寫 Code

先認識一下 redux 所需要的三大元素

  1. action
  2. reducer
  3. Store

認識 Actions

https://chentsulin.github.io/redux/docs/basics/Actions.html

說明 Actions , Actions 的工作就是把資料傳遞到 store,是 store 的唯一資料來源。
透過 store.dispatch() 傳遞至store

範例:

const ADD_TODO = 'ADD_TOTO'
{
  type:ADD_TODO,
  text:'Build my First Redux app'
}

Action 如同一般的 Object , 需要有 type 屬性,表示 action 的類型,通常會是字串,且不能重複。

如果你的程式架構很大,可以把 type 拉出來變成一個單獨的 module

import {ADD_TODO,REMOVE_TODO} from '../actionTypes'

盡量讓每個 action 中傳遞的資料越少越好,避免傳遞整個物件

Action Creator

action creator 指的是產生 action 的 方法。action 與 action creator 是兩個不同的名詞。

在 Redux 中 action creator 會回傳一個 action :

function addTodo(text){
  return {
    type: ADD_TODO,
    text
  }
}

在 redux 中,直接使用 dispatch ,透過 action creator 把 action 回傳,然後傳遞出去。

dispatch(addTodo(text));

… 後面的先不贅述

Reducer

Action 是用來描述行為與資料內容,不過他並沒有說明應用程式的 state 如何去應對這些資料。
而這是 Reducer 的工作。

設計 State 的樣貌

在 Redux 中,所有的應用程式的 state 被儲存為一個單一的物件。所以在寫程式之前,可以先構思一下他的結構。
如何用 state 描述成一個物件。

在 todo 的應用程式來說,有兩個重要的內容:

  1. 目前顯示項目的條件
  2. 所有 todos 的內容

盡量讓資料與UI的狀態分離。

{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}
  1. 我們建議你盡量保持 state 正規化,不要有任何的巢狀。
  2. 讓儲存在物件的每個實體都用一個 ID 作為 key,並且使用 IDs 來從其他實體或清單參考它。
  3. 把應用程式的 state 想成是一個資料庫,做法可以參考 normalizr

現在我們已經有了 state 樣貌
接下來我們需要建立一個 reducer, reducer 是一個純函式,用來接收 state 與 action 然後回傳新的 state
之所以稱為 reducer 是因為他是 Array.prototype.reduce 的原型 。 讓 reducer 保持乾淨非常重要。
不要在裡頭做這些事

  1. 改變參數
  2. 執行有 side effect 的動作,像是呼叫 API 或 Routing 的轉換
  3. 呼叫不是 pure 的 function,像是 Date.now() 或是 Math.random()

以後會學到 side effects 的使用方式。給定一個 state 與 action 然後計算下一個 state 然後回傳。

讓 reducer 認識我們之前所定義的 actions

import { VisibilityFilters } from './actions'

const initialState = {
  visibilityFilter: VisibilityFilters.SHOW_ALL,
  todos: []
}

function todoApp(state, action) {
  if (typeof state === 'undefined') {
    return initialState
  }
  // 在現在,不要處理任何 action

  // 而只是回傳給我們的 state。

  return state
}

上面的可以簡寫成

function todoApp(state = initialState, action){
  return state
}

然後根據 action 的內容進行 state 的計算

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
}

注意這幾點:

  1. 我們不改變 state。 我們用 Object.assign() 複製一份。Object.assign(state, { visibilityFilter: action.filter }) 也是錯的:它會改變第一個參數。你必須提供一個空物件作為第一個參數。你也可以啟用 object spread 運算子提案,就可以寫 { ...state, ...newState } 作為取代。
  2. 我們在 default case 回傳先前的 state。針對任何未知的 action 回傳先前的 state 非常重要。

createStore 是從 redux 提供的,每個 App 只會有一個 Store 用來記錄 State 。
所以 Store 提供下列功能

  • getState() 回傳 state
  • dispatch(action) 執行動作,而更新 state
  • subscribe(listener) 註冊 listener
  • 用 subscribe(listener) 所回傳 function 用來撤銷 listener

結構

import { createStore } from 'redux'
import todoApp from './reducers' // 用 combineReducers 把 reducer 合併在一起

let store = createStore(todoApp)

在 server 加 authorized_keys 檔

| Comments

add authorized_keys

$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ touch authorized_keys
$ chmod 600 authorized_keys

add local user public key to remote authorized file

ssh-copy-id -i ~/.ssh/id_rsa.pub username@remote-host-name     

Backbone 的 五個技巧

| Comments

backbone 小技巧

1. 使用正確的類別方法宣告

錯誤的宣告方式
// anti-pattern

var Car = Backbone.Model.extend({});
Car.manufacturersByCountry = function(country) {
    // custom logic to query manufacturers

}
正確的宣告方式
var Car = Backbone.Model.extend({
  // instance methods


}, {
  // class methods


  manufacturersByCountry: function(country) {
    // custom logic to query manufacturers

  }
});

2. 保護Backbone的生命週期函式,避免被覆蓋

var Car = Backbone.Model.extend({
    initialize: function() {
        // my custom stuff

        // ..

        // ..


        Backbone.View.prototype.initialize.call(this);
    }
});

3. 建立私有方法,放在區域範圍中

公開方法宣告方式
var Session = Backbone.Model.extend({
    _persistAuth: function() {
        // sensitive auth code

    }
});

module.exports = Session;
私有的方法宣告方式
var persistAuth = function() {
    // sensitive auth code

};

var Session = Backbone.Model.extend({
    initialize: function() {
        // setup code

        // …

        if (this.isValid()) {
            persistAuth.call(this)
        }

    }
});

module.exports = Session;

4. 善用Backbone的長處

Backbone 管理 model 與 RESTful 十分的強大,但是對於rendering 的部分,略遜 React
可以結合兩者一起使用像是這樣

backbone+react
var UserView = Backbone.View.extend({
  render: function() {
    React.renderComponent(new UserComponent(), this.el);
    return this;
  }
});

5. 保持 Router 的簡潔

建立屬於自己的controller

var Router = BackboneRouteControl.extend({
  routes: {
    "users":        "users#index",
    "users/:id":        "users#show",
    "users/:id/edit":   "users#edit"
  }  
});

var myRouter = new Router({
  controllers: {
    users: new UsersController()
  }
});
Controller.js
var UsersController = function() {
  return {
    index: function() {
    ...
    },
    show: function(id) {
    ...
    },
    edit: function(id) {
    ...
    }    
  };
};

資料來源:https://blog.engineyard.com/2015/5-ways-to-level-up-your-backbone-code

近日工作心得筆記 2016/10/03

| Comments

最近很久沒有深入 backbonejs
很多技巧已經忘光光了
剛好這次可以複習一下

簡單的測試環境:

main.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
  <title>JS Bin</title>
</head>
<body>

</body>
</html>
main.js
var MyView = Backbone.View.extend({
  
    el : 'body',
  
    collection : new Backbone.Collection(),
    
    // 測試 collection 的綁定事件

    initialize: function(){
      this.listenTo(this.collection,"change",this.change),
      this.listenTo(this.collection,"add",this.add),
      this.listenTo(this.collection,"remove",this.remove)
    },
    
    change: function(e){
      console.log("change",e);
    },
  
    add: function(e){
      console.log("add",e);
    },
  
    remove:function(e){
      console.log("remove",e);
    }
  
});


var myView = new MyView();

// 開始測試

console.log(myView);

myView.collection.add(new Backbone.Model({"name":"001"}));
myView.collection.add(new Backbone.Model({"name":"002"}));
myView.collection.at(0).set("name","James");

console.log("collection",myView.collection); //此時有兩個 model


var first = myView.collection.at(0);
var secend = myView.collection.at(1);

myView.collection.remove(first); // 移除第一個


console.log("a",myView.collection,first);

secend.destroy({success: function(model, response) {
  console.log(model,response);
}}); 
// destory 時,會自動從 collection 移除

// 可以傳入一組 success callback  


console.log("b",myView.collection,secend);
// secend 還在 記憶體中,但是已經自動從 collection 移出


測試網址:http://jsbin.com/secorat/1/edit?html,js