step-by-step-frontend, 一步一步地学习

分享于 

35分钟阅读

GitHub

  繁體 雙語
step by step learning about frontend
  • 源代码名称:step-by-step-frontend
  • 源代码网址:http://www.github.com/ironhee/step-by-step-frontend
  • step-by-step-frontend源代码文档
  • step-by-step-frontend源代码下载
  • Git URL:
    git://www.github.com/ironhee/step-by-step-frontend.git
    Git Clone代码到本地:
    git clone http://www.github.com/ironhee/step-by-step-frontend
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/ironhee/step-by-step-frontend
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    介绍

    本教程是为了介绍一些前端库&框架而创建的。

    为了避免混淆,本教程编写简单且排除优化。

    如果需要更多信息,请查看每个教程底部的'相关链接'。

    table-内容

    1: 初始化 node-软件包

    • Initailize node 软件包。
    npm init # This command make package.json

    package.json

    {
     "name": "step-by-step-frontend",
     "version": "0.0.0",
     "description": "step by step learning about frontend",
     "main": "index.js",
     "author": "ironhee <leechulhee95@gmail.com>",
     "license": "MIT"}
    • 编写 node 模块。

    index.js

    'use strict'; module.exports=functionhelloWorld() {
     console.log('hello world!');
    };
    • 加载&运行你的模块。

    test.js

    'use strict';var helloWorld =require('./');helloWorld();
    node test.js # hello world!

    相关链接

    : 使用另一个 node-软件包

    • 安装另一个 node 软件包。
    npm install --save underscore

    package.json

    {
     "name": "step-by-step-frontend",
     "version": "0.0.0",
     "description": "step by step learning about frontend",
     "main": "index.js",
     "author": "ironhee <leechulhee95@gmail.com>",
     "license": "MIT",
     "dependencies": {
     "underscore": "^1.8.3" }
    }
    • 更新 node 模块。

    index.js

    'use strict';var _ =require('underscore');module.exports=functionhelloWorld() {
     _.times(10, function (index) {
     console.log('['+ index +'] hello world!');
     });
    };
    • 加载&运行你的模块。

    test.js

    'use strict';var helloWorld =require('./');helloWorld();
    node test.js # [0] hello world!.. .
    • 创建. gitignore

    gitignore

     
    node_modules
    
    
    
     

    相关链接

    : 让我的软件包浏览器通过 web pack执行

    • 安装 & Initailize Bower 软件包。
    npm install -g bower
    bower init # This command make bower.json

    bower.json

    {
     "name": "step-by-step-frontend",
     "version": "0.0.0",
     "description": "step by step learning about frontend",
     "main": "dist/index.js",
     "authors": [
     "ironhee <iron@ediket.com>" ],
     "license": "MIT"}
    • 安装 web pack
    npm install -g webpack
    • 创建 web pack配置

    webpack.config.js

    'use strict';var _ =require('underscore');var pkg =require('./package.json');module.exports= {
     entry: {
     'index':'./index.js' },
     output: {
     path:'dist/',
     filename:'[name].js',
     library:'MyLib',
     libraryTarget:'umd' }
    };
    • 通过 web pack生成源代码
    webpack # use webpack.config.js by default

    如果要在文件更改时重新生成,请使用--watch选项

    webpack --watch # ctrl-c to exit
    • 加载&运行你的模块。

    test.html

    <html>
     <body>
     <scriptsrc='./dist/index.js'></script>
     <script>MyLib(); </script>
     </body>
    </html>
    • 更改 package.json'主要'属性

    package.json

    {
     "name": "step-by-step-frontend",
     "version": "0.0.0",
     "description": "step by step learning about frontend",
     "main": "dist/index.js",
     "author": "ironhee <leechulhee95@gmail.com>",
     "license": "MIT",
     "dependencies": {
     "underscore": "^1.8.3" }
    }
    • 加载&运行 node 模块。

    test.js

    'use strict';var helloWorld =require('./');helloWorld();
    node test.js # [0] hello world!.. .

    相关链接

    Step4: 通过Babel使用ES6语法

    • 通过npm安装babel加载程序
    npm install --save-dev babel-loader
    • 重命名 index.js 并更改内容
    mv index.js index.es6

    index.es6

    import_from'underscore';exportdefaultfunctionhelloWorld() {
     _.times(10, (index) => {
     console.log(`[${index}] hello world!`);
     });
    }
    • 更改 web pack配置

    webpack.config.js

    'use strict';var _ =require('underscore');var pkg =require('./package.json');module.exports= {
     entry: {
     'index':'./index.es6' },
     output: {
     path:'dist/',
     filename:'[name].js',
     library:'MyLib',
     libraryTarget:'umd' },
     module: {
     loaders: [
     { test:/.es6$/, loader:'babel-loader' }
     ]
     }
    };
    • 通过 web pack生成源代码
    webpack
    • 测试浏览器侧面和节点侧面

    test.html

    <html>
     <body>
     <scriptsrc='./dist/index.js'></script>
     <script>MyLib(); </script>
     </body>
    </html>
    node test.js # [0] hello world!.. .

    相关链接

    Step5: 使用响应

    • 安装npmReact
    npm install --save react
    • 创建目录
    mkdir -p src/js/components
    • 创建模块和渲染脚本

    src/js/components/MyComponent.es6

    importReactfrom'react';exportdefaultReact.createClass({
     render() {
     return (
     <div><h1>Hello world!</h1></div> );
     }
    });

    src/js/app.es6

    importMyComponentfrom'./components/MyComponent';exportdefault {
     MyComponent
    };

    src/js/main.es6

    importReactfrom'react';import { MyComponent } from'./app';React.render(<MyComponent/>, document.body);
    • 删除旧文件并更改 web pack配置
    rm -rf test.js test.html index.es6 dist/index.js
    • 单独的web pack配置

    webpack.base.config.js

    'use strict';module.exports= {
     resolve: {
     extensions: ['', '.js', '.es6']
     },
     module: {
     loaders: [
     { test:/.es6$/, loader:'babel-loader' }
     ]
     }
    };

    webpack.config.js

    'use strict';var _ =require('underscore');var baseConfig =require('./webpack.base.config');module.exports=_.extend({}, baseConfig, {
     entry: {
     'app':'./src/js/app.es6' },
     output: {
     path:'dist/',
     filename:'index.js',
     library:'MyLib',
     libraryTarget:'umd' }
    });

    webpack.main.config.js

    'use strict';var _ =require('underscore');var baseConfig =require('./webpack.base.config');module.exports=_.extend({}, baseConfig, {
     entry: {
     'main':'./src/js/main.es6' },
     output: {
     path:'dist/',
     filename:'main.js',
     libraryTarget:'umd' }
    });
    • web service生成
    webpack # build library codewebpack --config webpack.main.config # build rendering code
    • 检查 node 和浏览器
    node -e 'console.log(require("./"))'# { MyComponent: { [Function] displayName: 'MyComponent' } }

    演示/index.html

    <html>
     <body>
     <scriptsrc='../dist/index.js'></script>
     <script>console.log(MyLib) </script>
     </body>
    </html>
    • 在浏览器中使用 main.js ( 渲染逻辑)

    演示/index.html

    <html>
     <body>
     <scriptsrc='../dist/index.js'></script>
     <script>console.log(MyLib) </script>
     <scriptsrc='../dist/main.js'></script>
     </body>
    </html>

    相关链接

    Step6: 通过ESLint使用样式指南

    • 通过npm安装eslint和插件
    npm install --save-dev eslint babel-eslint eslint-plugin-react
    • eslint配置

    eslintrc

    {
     "env": {
     "browser": true,
     "node": true },
     "rules": {
     "strict": [2, "global"],
     "no-shadow": 2,
     "no-shadow-restricted-names": 2,
     "no-unused-vars": [2, {
     "vars": "local",
     "args": "after-used" }],
     "no-use-before-define": 2,
     "comma-dangle": [2, "never"],
     "no-cond-assign": [2, "always"],
     "no-console": 1,
     "no-debugger": 1,
     "no-alert": 1,
     "no-constant-condition": 1,
     "no-dupe-keys": 2,
     "no-duplicate-case": 2,
     "no-empty": 2,
     "no-ex-assign": 2,
     "no-extra-boolean-cast": 0,
     "no-extra-semi": 2,
     "no-func-assign": 2,
     "no-inner-declarations": 2,
     "no-invalid-regexp": 2,
     "no-irregular-whitespace": 2,
     "no-obj-calls": 2,
     "no-reserved-keys": 2,
     "no-sparse-arrays": 2,
     "no-unreachable": 2,
     "use-isnan": 2,
     "block-scoped-var": 2,
     "consistent-return": 2,
     "curly": [2, "multi-line"],
     "default-case": 2,
     "dot-notation": [2, {
     "allowKeywords": true }],
     "eqeqeq": 2,
     "guard-for-in": 2,
     "no-caller": 2,
     "no-else-return": 2,
     "no-eq-null": 2,
     "no-eval": 2,
     "no-extend-native": 2,
     "no-extra-bind": 2,
     "no-fallthrough": 2,
     "no-floating-decimal": 2,
     "no-implied-eval": 2,
     "no-lone-blocks": 2,
     "no-loop-func": 2,
     "no-multi-str": 2,
     "no-native-reassign": 2,
     "no-new": 2,
     "no-new-func": 2,
     "no-new-wrappers": 2,
     "no-octal": 2,
     "no-octal-escape": 2,
     "no-param-reassign": 2,
     "no-proto": 2,
     "no-redeclare": 2,
     "no-return-assign": 2,
     "no-script-url": 2,
     "no-self-compare": 2,
     "no-sequences": 2,
     "no-throw-literal": 2,
     "no-with": 2,
     "radix": 2,
     "vars-on-top": 2,
     "wrap-iife": [2, "any"],
     "yoda": 2,
     "indent": [2, 2],
     "brace-style": [2,
     "1tbs", {
     "allowSingleLine": true }],
     "quotes": [
     2, "single", "avoid-escape" ],
     "camelcase": [2, {
     "properties": "never" }],
     "comma-spacing": [2, {
     "before": false,
     "after": true }],
     "comma-style": [2, "last"],
     "eol-last": 2,
     "func-names": 1,
     "key-spacing": [2, {
     "beforeColon": false,
     "afterColon": true }],
     "new-cap": [2, {
     "newIsCap": true }],
     "no-multiple-empty-lines": [2, {
     "max": 2 }],
     "no-nested-ternary": 2,
     "no-new-object": 2,
     "no-spaced-func": 2,
     "no-trailing-spaces": 2,
     "no-wrap-func": 2,
     "no-underscore-dangle": 0,
     "one-var": [2, "never"],
     "padded-blocks": [2, "never"],
     "semi": [2, "always"],
     "semi-spacing": [2, {
     "before": false,
     "after": true }],
     "space-after-keywords": 2,
     "space-before-blocks": 2,
     "space-before-function-paren": [2, "never"],
     "space-infix-ops": 2,
     "space-return-throw-case": 2,
     "spaced-line-comment": 2,
     }
    }

    src/js/.estlinrc

    {
     "parser": "babel-eslint",
     "plugins": [
     "react" ],
     "ecmaFeatures": {
     "arrowFunctions": true,
     "blockBindings": true,
     "classes": true,
     "defaultParams": true,
     "destructuring": true,
     "forOf": true,
     "generators": false,
     "modules": true,
     "objectLiteralComputedProperties": true,
     "objectLiteralDuplicateProperties": false,
     "objectLiteralShorthandMethods": true,
     "objectLiteralShorthandProperties": true,
     "spread": true,
     "superInFunctions": true,
     "templateStrings": true,
     "jsx": true },
     "rules": {
     "strict": [2, "never"],
     "no-var": 2,
     "react/display-name": 0,
     "react/jsx-boolean-value": 2,
     "react/jsx-quotes": [2, "double"],
     "react/jsx-no-undef": 2,
     "react/jsx-sort-props": 0,
     "react/jsx-sort-prop-types": 0,
     "react/jsx-uses-react": 2,
     "react/jsx-uses-vars": 2,
     "react/no-did-mount-set-state": [2, "allow-in-func"],
     "react/no-did-update-set-state": 2,
     "react/no-multi-comp": 2,
     "react/no-unknown-property": 2,
     "react/prop-types": 2,
     "react/react-in-jsx-scope": 2,
     "react/self-closing-comp": 2,
     "react/wrap-multilines": 2,
     "react/sort-comp": [2, {
     "order": [
     "displayName",
     "mixins",
     "statics",
     "propTypes",
     "getDefaultProps",
     "getInitialState",
     "componentWillMount",
     "componentDidMount",
     "componentWillReceiveProps",
     "shouldComponentUpdate",
     "componentWillUpdate",
     "componentWillUnmount",
     "/^on.+$/",
     "/^get.+$/",
     "/^render.+$/",
     "render" ]
     }]
     }
    }
    • 安装编辑器插件
    • sublime text: 安装 SublimeLinter & SublimeLinter-eslint
    • Atom: 安装 linter & linter-eslint

    相关链接

    Step7: 通过吞咽管理任务

    • 安装 gulp
    npm install -g gulp
    npm install --save-dev gulp
    • 通过npm安装 web pack和插件
    npm install --save-dev webpack
    npm install --save-dev webpack-gulp-logger
    • 创建吞咽配置文件( gulpfile。js )

    gulpfile.js

    'use strict';var gulp =require('gulp');var webpack =require('webpack');var webpackLogger =require('webpack-gulp-logger');var libWebpackConfig =require('./webpack.config');var mainWebpackConfig =require('./webpack.main.config');gulp.task('default', [
     'watch']);gulp.task('watch', [
     'watch-lib',
     'watch-main']);gulp.task('build', [
     'build-lib',
     'build-main']);gulp.task('watch-lib', function() {
     webpack(libWebpackConfig).watch({}, webpackLogger());
    });gulp.task('watch-main', function() {
     webpack(mainWebpackConfig).watch({}, webpackLogger());
    });gulp.task('build-lib', function(callback) {
     webpack(libWebpackConfig).run(webpackLogger(callback));
    });gulp.task('build-main', function(callback) {
     webpack(mainWebpackConfig).run(webpackLogger(callback));
    });
    • 运行gulp任务

    用于生成

    gulp build

    for

    gulp watch

    相关链接

    Step8: 通过 web pack添加 Sourcemaps

    • 在 web pack配置中设置devtool属性

    webpack.base.config.js

    'use strict';module.exports= {
     devtool:'eval-source-map',
     resolve: {
     extensions: ['', '.js', '.es6']
     },
     module: {
     loaders: [
     { test:/.es6$/, loader:'babel-loader' }
     ]
     }
    };
    • 通过gulp构建
    gulp build

    现在你可以区分源代码。

    相关链接

    Step9: 创建带有回流&React的简单应用

    • 将 resolve.modulesDirectories 选项添加到 web pack配置中以便方便

    webpack.base.config

    'use strict';module.exports= {
     devtool:'eval-source-map',
     resolve: {
     modulesDirectories: ['src/js/', 'node_modules'],
     extensions: ['', '.js', '.es6']
     },
     module: {
     loaders: [
     { test:/.es6$/, loader:'babel-loader' }
     ]
     }
    };
    • 创建 Commment.es6 和 CommentSite.es6

    src/js/components/Comment.es6

    importReactfrom'react';exportdefaultReact.createClass({
     propTypes: {
     comment:React.PropTypes.shape({
     content:React.PropTypes.string.isRequired,
     updatedAt:React.PropTypes.object.isRequired }).isRequired },
     render() {
     return (
     <div> { this.props.comment.content } - { this.props.comment.updatedAt.toDateString() }
     <a href="#">remove</a></div> );
     }
    });

    src/js/components/CommentSite.es6

    importReactfrom'react';import_from'underscore';importCommentfrom'components/Comment';exportdefaultReact.createClass({
     getInitialState() {
     return {
     comments: [{
     id:1,
     content:'this is comment1!',
     updatedAt:newDate(Date.now())
     }, {
     id:2,
     content:'this is comment2!',
     updatedAt:newDate(Date.now())
     }]
     };
     },
     render() {
     return (
     <div><h3>Comments</h3> { _.map(this.state.comments, comment=> (
     <Comment comment={ comment } key={ comment.id } /> )) }
     <form><textarea ref="newComment"></textarea><button>Comment!</button></form></div> );
     }
    });
    • 将CommentSite添加到 app.es6

    src/js/app.es6

    importMyComponentfrom'components/MyComponent';importCommentSitefrom'components/CommentSite';exportdefault {
     MyComponent,
     CommentSite
    };
    • 更改 main.es6

    main.es6

    importReactfrom'react';import { CommentSite } from'app';React.render(<CommentSite/>, document.body);

    在浏览器中打开 demo.index.html 并检查组件是否正确呈现

    安装回流器,q,下划线 db

    npm install --save reflux q@~1.0 underscore-db
    • 将 node.fs 选项添加到 web pack配置中

    webpack.base.config

    'use strict';module.exports= {
     devtool:'eval-source-map',
     node: {
     fs:'empty' },
     resolve: {
     modulesDirectories: ['src/js/', 'node_modules'],
     extensions: ['', '.js', '.es6']
     },
     module: {
     loaders: [
     { test:/.es6$/, loader:'babel-loader' }
     ]
     }
    };
    • 定义注释操作

    src/js/actions/CommentActions.es6

    importRefluxfrom'reflux';exportdefaultReflux.createActions({
     createComment: {
     asyncResult:true },
     removeComment: {
     asyncResult:true }
    });
    • 将回流承诺工厂设置为 Q.Promise

    src/js/app.es6

    importRefluxfrom'reflux';importQfrom'q';Reflux.setPromiseFactory(Q.Promise);importMyComponentfrom'components/MyComponent';importCommentSitefrom'components/CommentSite';exportdefault {
     MyComponent,
     CommentSite
    };
    • 创建评论存储

    src/js/mixins/DBMixin.es6

    importunderscoreDBfrom'underscore-db';import_from'underscore';_.mixin(underscoreDB);exportdefaultfunctionDBMixin() {
     let result = {
     db: []
     };
     _.extend(result, _(result.db));
     return result;
    }

    src/js/stores/CommentStore.es6

    importRefluxfrom'reflux';importCommentActionsfrom'actions/CommentActions';importDBMixinfrom'mixins/DBMixin';import { Promise } from'q';exportdefaultReflux.createStore({
     mixins: [newDBMixin()],
     listenables: [CommentActions],
     onCreateComment(content) {
     CommentActions.createComment.promise(
     newPromise((resolve) => {
     let comment =this.insert({
     content,
     updatedAt:newDate(Date.now())
     });
     resolve(comment);
     this.trigger();
     })
     );
     },
     onRemoveComment(commentID) {
     CommentActions.removeComment.promise(
     newPromise((resolve) => {
     let comment =this.removeById(commentID);
     resolve(comment);
     this.trigger();
     })
     );
     }
    });
    • 使 Commment.es6 和 CommentSite.es6 用户存储&操作

    src/js/components/Comment.es6

    importReactfrom'react';importCommentActionsfrom'actions/CommentActions';exportdefaultReact.createClass({
     propTypes: {
     comment:React.PropTypes.shape({
     content:React.PropTypes.string.isRequired,
     updatedAt:React.PropTypes.object.isRequired }).isRequired },
     onRemove() {
     CommentActions.removeComment(this.props.comment.id)
    . then(() => {
     alert('removed!');
     });
     returnfalse;
     },
     render() {
     return (
     <div> { this.props.comment.content } - { this.props.comment.updatedAt.toDateString() }
     <a href="#" onClick={ this.onRemove }>remove</a></div> );
     }
    });

    src/js/components/CommentSite.es6

    importReactfrom'react';importRefluxfrom'reflux';import_from'underscore';importCommentfrom'components/Comment';importCommentStorefrom'stores/CommentStore';importCommentActionsfrom'actions/CommentActions';functiongetStoreState() {
     return {
     comments:CommentStore.value()
     };
    }exportdefaultReact.createClass({
     mixins: [
     Reflux.listenTo(CommentStore, 'onStoreChange')
     ],
     getInitialState() {
     returngetStoreState();
     },
     onStoreChange() {
     this.setState(getStoreState());
     },
     onCreateComment() {
     let content =React.findDOMNode(this.refs.newComment).value;
     CommentActions.createComment(content)
    . then(() => {
     alert('created!');
     });
     returnfalse;
     },
     render() {
     return (
     <div><h3>Comments</h3> { _.map(this.state.comments, comment=> (
     <Comment comment={ comment } key={ comment.id } /> )) }
     <form onSubmit={ this.onCreateComment }><textarea ref="newComment"></textarea><button>Comment!</button></form></div> );
     }
    });
    • 在浏览器中打开 demo.index.html 并检查组件是否正确操作

    相关链接

    :使你的应用程序与 REST API 服务器同步,使用json服务器 & jquery

    • 通过npm全球安装json服务器
    npm install -g json-server
    • 为json服务器创建目录
    mkdir public
    • 将演示/index.html 移动到 public/index.html
    mv demo/index.html public
    rm -rf demo
    • 更改 public/index.html的内容

    public/index.html

    <html>
     <body>
     <scriptsrc='/static/main.js'></script>
     </body>
    </html>
    • 创建 static 文件的符号链接。
    
    ln -s.. /dist/public/static
    
    
    
    
    • 创建 db.json

    db.json

    {}
    • 运行json服务器
    json-server db.json# {^_^} Hi!## Loading database from db.json### You can now go to http://localhost:3000## Enter s at any time to create a snapshot # of the db

    在浏览器中打开 http://localhost:3000 插件。 检查你的应用是否正确运作。

    安装 jquery,通过npm连接 url

    npm install -S jquery url-join
    • 使CommentStore使用Ajax请求。

    src/js/mixins/DBMixin.es6

    importunderscoreDBfrom'underscore-db';import_from'underscore';import $ from'jquery';importurlJoinfrom'url-join';import { Promise } from'q';_.mixin(underscoreDB);functionajaxRequest(options) {
     returnnewPromise((resolve, reject) => {
     $.ajax(options)
    . then(resolve)
    . fail(reject);
     });
    }exportdefaultfunctionDBMixin(type) {
     let result = {
     db: []
     };
     let methods =_(result.db);
     _.extend(result, methods);
     _.extend(result, {
     insert(attributes) {
     returnajaxRequest({
     type:'POST',
     url:urlJoin(type),
     data: attributes
     })
    . then(response=> {
     return response;
     })
    . then(response=>methods.insert(response));
     },
     removeById(id) {
     returnajaxRequest({
     type:'DELETE',
     url:urlJoin(type, id)
     })
    . then(() =>methods.removeById(id));
     }
     });
     return result;
    }

    src/js/stores/CommentStore.es6

    importRefluxfrom'reflux';importCommentActionsfrom'actions/CommentActions';importDBMixinfrom'mixins/DBMixin';import { Promise } from'q';exportdefaultReflux.createStore({
     mixins: [newDBMixin('comments')],
     listenables: [CommentActions],
     onCreateComment(content) {
     CommentActions.createComment.promise(
     newPromise((resolve, reject) => {
     this.insert({
     content,
     updatedAt:newDate().getTime()
     })
    . then(comment=>resolve(comment))
    . then(() =>this.trigger())
    . catch(reject);
     })
     );
     },
     onRemoveComment(commentID) {
     CommentActions.removeComment.promise(
     newPromise((resolve, reject) => {
     this.removeById(commentID)
    . then(comment=>resolve(comment))
    . then(() =>this.trigger())
    . catch(reject);
     })
     );
     }
    });

    警告:comment.updatedAt 类型的字段是更改。

    • 应用 comment.updatedAt 类型的字段更改。

    src/js/components/Comment.es6

    importReactfrom'react';importCommentActionsfrom'actions/CommentActions';exportdefaultReact.createClass({
     propTypes: {
     comment:React.PropTypes.shape({
     content:React.PropTypes.string.isRequired,
     updatedAt:React.PropTypes.number.isRequired }).isRequired },
     onRemove() {
     CommentActions.removeComment(this.props.comment.id)
    . then(() => {
     alert('removed!');
     });
     returnfalse;
     },
     render() {
     return (
     <div> { this.props.comment.content } - { newDate(this.props.comment.updatedAt).toDateString() }
     <a href="#" onClick={ this.onRemove }>remove</a></div> );
     }
    });

    在浏览器中打开 http://localhost:3000 插件。 并检查你的应用程序使ajax请求正确。

    将fetchComments操作添加到 CommentActions

    src/js/actions/CommentActions.es6

    importRefluxfrom'reflux';exportdefaultReflux.createActions({
     fetchComments: {
     asyncResult:true },
     createComment: {
     asyncResult:true },
     removeComment: {
     asyncResult:true }
    });
    • 在呈现后使CommentSite触发器 fetchComment。 ( componentDidMount )

    src/js/components/CommentSite.es6

    importReactfrom'react';importRefluxfrom'reflux';import_from'underscore';importCommentfrom'components/Comment';importCommentStorefrom'stores/CommentStore';importCommentActionsfrom'actions/CommentActions';functiongetStoreState() {
     return {
     comments:CommentStore.value()
     };
    }exportdefaultReact.createClass({
     mixins: [
     Reflux.listenTo(CommentStore, 'onStoreChange')
     ],
     getInitialState() {
     returngetStoreState();
     },
     componentDidMount() {
     CommentActions.fetchComments();
     },
     onStoreChange() {
     this.setState(getStoreState());
     },
     onCreateComment() {
     let content =React.findDOMNode(this.refs.newComment).value;
     CommentActions.createComment(content)
    . then(() => {
     alert('created!');
     });
     returnfalse;
     },
     render() {
     return (
     <div><h3>Comments</h3> { _.map(this.state.comments, comment=> (
     <Comment comment={ comment } key={ comment.id } /> )) }
     <form onSubmit={ this.onCreateComment }><textarea ref="newComment"></textarea><button>Comment!</button></form></div> );
     }
    });
    • 实现提取方法

    src/js/mixins/DBMixin.es6

    importunderscoreDBfrom'underscore-db';import_from'underscore';import $ from'jquery';importurlJoinfrom'url-join';import { Promise } from'q';_.mixin(underscoreDB);functionajaxRequest(options) {
     returnnewPromise((resolve, reject) => {
     $.ajax(options)
    . then(resolve)
    . fail(reject);
     });
    }exportdefaultfunctionDBMixin(type) {
     let result = {
     db: []
     };
     let methods =_(result.db);
     _.extend(result, methods);
     _.extend(result, {
     insert(attributes) {
     returnajaxRequest({
     type:'POST',
     url:urlJoin(type),
     data: attributes
     })
    . then(response=> {
     return response;
     })
    . then(response=>methods.insert(response));
     },
     removeById(id) {
     returnajaxRequest({
     type:'DELETE',
     url:urlJoin(type, id)
     })
    . then(() =>methods.removeById(id));
     },
     fetch(id) {
     returnajaxRequest({
     type:'GET',
     url:urlJoin(type, id)
     })
    . then(response=>_.isArray(response) ?_.map(response, _response=>methods.insert(_response)) :methods.insert(response)
     );
     }
     });
     return result;
    }

    src/js/stores/CommentStore.es6

    importRefluxfrom'reflux';importCommentActionsfrom'actions/CommentActions';importDBMixinfrom'mixins/DBMixin';import { Promise } from'q';exportdefaultReflux.createStore({
     mixins: [newDBMixin('comments')],
     listenables: [CommentActions],
     onFetchComments() {
     CommentActions.fetchComments.promise(
     newPromise((resolve, reject) => {
     this.fetch()
    . then(comments=>resolve(comments))
    . then(() =>this.trigger())
    . catch(reject);
     })
     );
     },
     onCreateComment(content) {
     CommentActions.createComment.promise(
     newPromise((resolve, reject) => {
     this.insert({
     content,
     updatedAt:newDate().getTime()
     })
    . then(comment=>resolve(comment))
    . then(() =>this.trigger())
    . catch(reject);
     })
     );
     },
     onRemoveComment(commentID) {
     CommentActions.removeComment.promise(
     newPromise((resolve, reject) => {
     this.removeById(commentID)
    . then(comment=>resolve(comment))
    . then(() =>this.trigger())
    . catch(reject);
     })
     );
     }
    });

    在浏览器中打开 http://localhost:3000 插件。 并检查你的应用程序在初始呈现后发出请求,并且你的注释正确呈现。

    将 db.json 添加到. gitignore

    gitignore

    
    node_modules
    
    
    db.json
    
    
    
    

    相关链接


    learn  STEP  Frontend  
    相关文章