实现电影列表检索案例 - Zikzin/Angular.js-study GitHub Wiki

一、准备(搭建项目骨架)

二、安装项目依赖

  • 1、$ bower install bootstrap --save

  • 2、npm在package.json中的script节点中可以定义脚本任务,如:

    • "scripts": { "postinstall": "bower install", "prestart": "npm install", "start": "./node_modules/.bin/hs -a localhost -p 9000 -o" },
  • 3、$ npm run start(相当于:$ npm start,start、test是特殊脚本,可以省略run,其他不可)

    • 该命令执行完后,脚本任务都执行完毕,并且帮我们打开了一个9000端口的网页,可以在app/里看到已经用路由搭建好的简单骨架。可用此进行项目搭建。
  • 4、.gitignore文件可写忽略文件:如:

    • node_modules
    • bower_components
  • 5、README.md文件:可写项目说明。

  • 6、.editorconfig文件:统一不同开发者的不同开发工具的不同开发配置。比如可以统一项目编码配置等等。

    • 在Sublime中使用需要安装一个EditorConfig的插件。(sublime中如何安装插件?)
    • webstorm打开项目的时候会提示已经使用.editorconfig文件的配置。
  • 7、.gitattributes文件:声明文件的类型:二进制文件、文本文件...

    • 默认为文本文件:* text=auto。
    • 比较少用,只是git做文件管理时候。二进制文件不需要进行比对,哪行文本发生了变化;而文本文件需要做比对。
  • 8、app目录是编码真正要写的目录。这里是一个简单编码骨架。

  • 9、为NG做一个项目骨架的目的是为了快速开始一个新的项目。(按开发习惯创建骨架)

    • ng官方骨架:angular-seed
    • google脚手架:web-starter-kit

三、构建基本页面结构和设计路由

  • 1、使用模板:http://v3.bootcss.com/examples/dashboard/ (bootstrap官网——起步——案例精选——控制台)
  • 2、直接查看源代码将body里的页面内容替代index.html的body的页面内容,并且将dashboard.css复制到app.css。引入bootstarp.ccs。
  • 3、将view1等相关文件夹、文件改成项目需要的文件夹以及文件。
  • 4、根据模板设置路由

四、豆瓣api以及postman基本使用

豆瓣API

  • 地址:https://developers.douban.com——开发文档——豆瓣Api V2(测试版)
  • API:应用程序编程接口(Application Programming Interface)
  • 常见API:
    • 1、WebAPI(通过WEB方式提供结构叫做WebAPI)
    • 2、Math.randow() —— 也是个api?
    • 所有有输入有输出的事物都可以是API——总之都是函数

测试WebAPI的工具:postman(chorme的一个应用)

五、绑定假数据

  • 1、结构都直接从http://v3.bootcss.com里拿。(全局css样式——列表组、媒体对象、徽章)
  • 2、如果在src上直接绑定表达式,会导致页面一加载,但ng还未执行的时候,当成图片地址去请求,但实际上应该是将结果拿出来再去取的,应该换成ng-src(如:请求图片地址时候)
  • 3、调用数组的函数:(1)toString() (2)join(),可传拼接的字符串。(如:取多种类型)
  • 4、调用对象的函数:ng-repeat(a、列表项 b、展示多个元素,如取多个导演姓名)

六、异步请求数据 $http (详见文档)

  • 1、异步请求的两种方式:(1)通过浏览器的XMLHttpRequest (2)JSONP:通过引入脚本的方式,手写比jq里的还重要。
  • 2、用的是promise的方式:then...(ES6的方式),比回调的方式好,回调嵌套容易出现回调黑洞的问题,而promise将函数并列,可以避免回调嵌套。
  • 3、除了常见方式,还有快捷方式。
  • 4、请求本地数据文件时,要写绝对路径,相对路径不建议,因为添加路由时目录结构可能会发生变化,写“/”表示当前文件的根目录。
  • 5、豆瓣API不完全支持jsonp的callback参数。

七、跨域的方式和问题

为什么会有跨域:因为XMLHttpRequest,该对象不支持跨域请求。

  • 1、传统浏览器ajax请求(XMLHttpRequest):如:
    • (1)index.html 开始执行
    • (2)发送一个异步请求data.json(同域情况下)(就会触发callback函数)
  • 2、支持跨域请求的对象
    • (1)img:以前常用作网站统计链接,支持跨域但是无法实现获取服务端返回的数据。
    • (2)iframe:可接受服务端的数据,但过程复杂。
    • (3)link:css渲染阶段会报错。
    • (4)script:可以,常用callback参数。
  • 3、script对象(跨域处理方式?)
    • (1)ng中,都是将函数挂在callback参数上,不会污染全局,是比较好的方式。
    • (2)jq中,还是定义全局的方式,相对来说,ng更好。
  • 4、小知识:此处的分号,是严谨写法。某些时候进行代码合并时避免因上一段代码缺少分号的错误发生。 <script> ;function(){ // body } </script>
  • 5、加载动画:这里的jsonp是手写的,并不是ng官方的,需要引入$apply。
    • $apply的作用就是让指定的表达式重新同步。(或者所有的都重新同步一下,这里是subjects和loading)

八、手写jsonp实现(详见demo:crossdomain)

  • 1、挂载回调函数。(不推荐将callback直接挂到全局环境里,最好带一个参数如:cb.my_json_cb_,这里是因为豆瓣不支持。)
  • 2、将data转换成url字符串的形式,如:{id:1,name:'zhangsan'} => id=1&name=zhangsan(遍历的方式)。
  • 3、处理url地址中的回调参数。
  • 4、创建一个script标签(节点)。
  • 5、将script标签放到页面中。

九、实现分页(配置路由的方式)

  • 1、每页显示多少条。如:10条。
    • p1:start:0,count:10
    • p2:start:10,count:10
    • p3:start:20,count:10
    • start = ( page - 1 ) * count;
    • pageCount = Math.ceil ( total / count );
  • 2、在路由的配置中加上分页参数。
  • 3、在控制器中提取page参数。
  • 4、分页按钮组件:http://v3.bootcss.com/components/#pagination

十、使用指令的方式实现左侧自动焦点

  • 1、正则表达式?
  • 2、自定义指令?

十一、异步方式加载包

  • 1、直接将js文件在页面引入的方式是同步的,会影响页面加载速度。
  • 2、通过一个库,异步加载ng,以及和ng的所有包。通过$scripe函数,第一个参数:要加载的库文件。第二个参数:加载完之后执行的回调。
  • 3、load.js(国内)、script.js(国外)、head.js都可以帮助我们异步的方式加载js文件。
    • 1、可以用bower下载:bower install script.js --offline --save
    • 2、在页面head里引入包(体积很小,不会影响页面加载)
  • 4、基本使用

<script> $script('you want to load', function(){ console.log($) }); </script>

  • 5、第二种方式:第一个参数传数组,第二个参数传回调。

$script([ './bower_components/angular/angular.js', './bower_components/jquery/dist/jquery.js' ],function(){ console.log(angular); console.log(jQuery); });

  • 1、有个问题:数组里面的包,是并行加载的,如果比较小的包,会先执行,可能其依赖的包还未加载完,就会报错。

  • 2、解决问题:一步一步去加载。 $script('jquery.js', function () { $script('my-jquery-plugin.js', function () { $script('my-app-that-uses-plugin.js') }) })

  • 6、angular-loader的作用就是在使用一些异步加载脚本的库的时候,会自动控制依赖顺序。引入script.js之后,引入这个包即可。

  • 7、load.js实现

  • 8、jsonp回调

    • 1、豆瓣电影的例子中自己写的jsonp有个不完美的地方:单页应用始终停留在这个页面,最外层的dom对象永远不会得到释放也就是说页面只要不刷新最外层的head、body这些会一直在用,我们点击下一页的时候,每次都会多一个script请求。(有可能会无穷大,这不太好。)
    • 2、解决操作:script对象有append操作必须要有个remove操作。
    • 3、思考:什么时候remove?正确做法是:callback执行完才可以remove。01、根据异步请求的地址拼接一个callback参数。 02、将这个地址当做一个script文件请求。就是callback(data); 原因:有可能callback还未执行完就被remove,所以要先执行完,最合适做法:自己调完自己remove。详见demo:http.js

十二、搜素模块实现

十三、详细页面实现(配置路由的方式)

  • 1、注意路由的引用顺序(这里一共两个路由:/:category/:page 和 /detail/:id),确定detail的路由应该在category的前面。(因为如:/detail/1232455这个也能匹配上/:category/:page,这样就不会去匹配 /detail/:id了。)解决如下:

    • 1、在index.html引入子模块时候,先引入 <script src="movie_detail/controller.js"></script> 再引入<script src="movie_list/controller.js"></script>
    • 2、或者在app.js里模块引入时候,先引入'movielist.movie_detail',再引入'movielist.movie_list'。
  • 2、单页应用程序不用考虑回退的问题,因为锚点的变化在url地址里面本身就是可以回退的。

  • 3、在进行第三方的异步请求过后,必须用$apply重新对数据进行绑定。

十四、抽象一个配置

  • 1、可以抽象的配置:
    • 1、一个应用程序的页码应该是统一的(分页)。可以抽象出来。
    • 2、豆瓣的API地址。(v2版本)
  • 2、凡是有可能发生变化的量,都定义成变量。对于变量最好做成配置。
  • 3、实现:
    • 1、定义变量:.constant('name',value)(app.js中)
    • 2、使用变量:直接在app控制器中注name(app.js中)
    • 3、模块依赖:在有用到上面变量的地方注入模块。(如:list中controller里'AppConfig',var count = AppConfig.pageSize; ...)
  • 4、注意在公共模块定义的组件(如SearchController),子模块是拿不到的。
⚠️ **GitHub.com Fallback** ⚠️