实现电影列表检索案例 - Zikzin/Angular.js-study GitHub Wiki
- 1、$ git clone --depth=1 https://github.com/zce/angular-boilerplate.git movielist
- 2、$ cd movielist
- movielist:表示我们要将新建movielist文件夹并将项目放进去。
- --depth=1:表示克隆的深度
-
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、根据模板设置路由
- 地址:https://developers.douban.com——开发文档——豆瓣Api V2(测试版)
- API:应用程序编程接口(Application Programming Interface)
- 常见API:
- 1、WebAPI(通过WEB方式提供结构叫做WebAPI)
- 2、Math.randow() —— 也是个api?
- 所有有输入有输出的事物都可以是API——总之都是函数
- 1、结构都直接从http://v3.bootcss.com里拿。(全局css样式——列表组、媒体对象、徽章)
- 2、如果在src上直接绑定表达式,会导致页面一加载,但ng还未执行的时候,当成图片地址去请求,但实际上应该是将结果拿出来再去取的,应该换成ng-src(如:请求图片地址时候)
- 3、调用数组的函数:(1)toString() (2)join(),可传拼接的字符串。(如:取多种类型)
- 4、调用对象的函数:ng-repeat(a、列表项 b、展示多个元素,如取多个导演姓名)
- 1、异步请求的两种方式:(1)通过浏览器的XMLHttpRequest (2)JSONP:通过引入脚本的方式,手写比jq里的还重要。
- 2、用的是promise的方式:then...(ES6的方式),比回调的方式好,回调嵌套容易出现回调黑洞的问题,而promise将函数并列,可以避免回调嵌套。
- 3、除了常见方式,还有快捷方式。
- 4、请求本地数据文件时,要写绝对路径,相对路径不建议,因为添加路由时目录结构可能会发生变化,写“/”表示当前文件的根目录。
- 5、豆瓣API不完全支持jsonp的callback参数。
- http://api.douban.com/v2/movie/in_theaters?callback=aa_func (可以支持,因为这是一个整体)
- http://api.douban.com/v2/movie/in_theaters?callback=func (可以支持)
- http://api.douban.com/v2/movie/in_theaters?callback=aa.func (不支持)
- ng里都是把全局函数挂在一个对象上,用点的方式。
- 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)
- 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实现
- 1、load.js地址:https://github.com/filamentgroup/loadJS
- 2、自己实现的例子详见 load.html
-
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、查看豆瓣api,观察电影搜素api跟榜单api的区别:多了个q参数。在postman里尝试发现q参数并不会影响榜单的搜素。如:http://api.douban.com/v2/movie/top250?count=1 和 http://api.douban.com/v2/movie/top250?count=1&q=123的搜素结果是一样的。
- 2、$routeParams 的数据来源:1、路由匹配出来的 2、?参数(搜素)
- 3、用添加控制器的方式实现。SearchController
- 4、用指令的方式实现,方便复用。
-
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
'。
- 1、在index.html引入子模块时候,先引入
-
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),子模块是拿不到的。