大数据......某比萨店的电话铃响了,客服人员拿起电话。
客服:XXX比萨店。您好,请问有什么需要我为您服务?
顾客:你好,我想要一份……
客服:先生,烦请先把您的会员卡号告诉我。
顾客:16846146***。
客服:陈先生,您好!您是住在泉州路一号12楼1205室,您家电话是2646****,您公司电话是4666****,您的手机是1391234****。请问您想用哪一个电话付费?
顾客:你为什么知道我所有的电话号码?
客服:陈先生,因为我们联机到CRM系统。
顾客:我想要一个海鲜比萨……
客服:陈先生,海鲜比萨不适合您。
顾客:为什么?
客服:根据您的医疗记录,你的血压和胆固醇都偏高。
顾客:那你们有什么可以推荐的?
客服:您可以试试我们的低脂健康比萨。
顾客:你怎么知道我会喜欢吃这种的?
客服:您上星期一在中央图书馆借了一本《低脂健康食谱》。
顾客:好。那我要一个家庭特大号比萨,要付多少钱?
客服:99元,这个足够您一家六口吃了。但您母亲应该少吃,她上个月刚刚做了心脏搭桥手术,还处在恢复期。
顾客:那可以刷卡吗?
客服:陈先生,对不起。请您付现款,因为您的信用卡已经刷爆了,您现在还欠银行4807元,而且还不包括房贷利息。
顾客:那我先去附近的提款机提款。
客服:陈先生,根据您的记录,您已经超过今日提款限额。
顾客:算了,你们直接把比萨送我家吧,家里有现金。你们多久会送到?
客服:大约30分钟。如果您不想等,可以自己骑车来。
顾客:为什么?
客服:根据我们CRM全球定位系统的车辆行驶自动跟踪系统记录。您登记有一辆车号为SB-748的摩托车,而目前您正在解放路东段华联商场右侧骑着这辆摩托车。
顾客当即晕倒。
热烈欢迎-- 大数据时代到来了!
格式化区域
Bootstrap Class Description
panel
Denotes a panel with a rounded border. A panel can have a header and a footer.
panel-heading
Creates a heading for a panel.
btn
Creates a button.
well
Groups elements with an inset effect.
格式化TABLE
table
#Applies general styling to table elements and their contents
table-striped
#Applies alternate-row striping to the rows in the table body
table-bordered
#Applies borders to all rows and columns
table-hover
#Displays a different style when the mouse hovers over a row in the table
table-condensed
#Reduces the spacing in the table to create a more compact layout
格式化FORM
<div class="form-group">
<label>Name:</label>
<input name="name" class="form-control" />
</div>
AngularJS 是一个 Web 应用框架,它实现了前端的 MVC 架构,能让开发人员很方便地实现业务逻辑。
举个栗子,要做到下面的效果,以前可能需要写一连串的 JavaScript 代码绑定 N 多事件。而使用 AngularJS 框架,一句 JavaScript 都不用写就能实现了,神奇吧?查看演示。
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <div data-ng-app> 单价: <input type="number" min=0 ng-model="price" ng-init="price = 299"> <br> 数量: <input type="number" min=0 ng-model="quantity" ng-init="quantity = 1"> <br> 总价: {{ quantity * price }} </div> |
这得益于 AngularJS 中的双向数据绑定特性(Two Way Data-Binding),将 Model 和 View 自动关联了起来,在更复杂的业务场景下,还有代码分离的好处,将 DOM 操作和应用逻辑解耦,非常实用。
不过没有银弹,和其他框架一样,AngularJS 也有它的局限。CRUD 类型的操作是它所擅长的,想想看以前写过的管理后台,几乎大部分都是从数据库中读取数据,然后呈现在页面上,进行各种增删改查。AngularJS 约定了一套规范(约定优于配置),于是你可以很便捷地操作数据。而在其他方面,例如开发复杂的 Web 游戏,AngularJS 则是无用武之地了。
一、AngularJS 中的精美特性
双向绑定
上面的例子已经说明了,我们可以像 PHP Smarty 模板一样在 HTML 中写表达式,用 {{ 和 }} 包起来。在 AngularJS 里,View 和 Model 是在 Controller 里面绑定的,所以无论你在 View 的表单中修改了内容,还是在 Controller 里通过代码修改了 Model 值,两边都会即时发生变化,同步更新。因为 AngularJS 会监控 (watch) Model 对象的变化,随时反映到 View 中。
Filter
Filter 类似 Unix 里面的 | 管道概念,AngularJS 把它搬到了前端。还是举个例子,你们感受一下——
<div>{{ 9999 | number }}</div> <div>{{ 9999+1 | number:2 }}</div> <div>{{ 9*9 | currency }}</div> <div>{{ 'Hello World' | uppercase }}</div> |
输出结果:
9,999 10,000.00 $81.00 HELLO WORLD
二、AngularJS 中的一些“坑”
由于过去写 JavaScript 的习惯使然,人们很容易掉进一些 AngularJS 的陷阱里。下面的内容假设你已经了解前端 MVC 概念,并对 AngularJS 有了一定经验,初学者读起来可能比较艰深晦涩。
DOM 操作
避免使用 jQuery 来操作 DOM,包括增加元素节点,移除元素节点,获取元素内容,隐藏或显示元素。你应该使用 directives 来实现这些动作,有必要的话你还要编写自己的 directives。
如果你感到很难改变习惯,那么考虑从你的网页中移除 jQuery 吧。真的,AngularJS 中的 $http
服务非常强大,基本可以替代 jQuery 的 ajax 函数,而且 AngularJS 内嵌了 jQLite —— 它内部实现的一个 jQuery 子集,包含了常用的 jQuery DOM 操作方法,事件绑定等等。但这并不是说用了AngularJS 就不能用 jQuery 了。如果你的网页有载入 jQuery 那么 AngularJS 会优先采用你的 jQuery,否则它会 fall back 到 jQLite。
需要自己编写 directives 的情况通常是当你使用了第三方的 jQuery 插件。因为插件在 AngularJS 之外对表单值进行更改,并不能即时反应到 Model 中。例如我们用得比较多的 jQueryUI datepicker 插件,当你选中一个日期后,插件会将日期字符串填到 input 输入框中。View 改变了,却并没有更新 Model,因为$('.datepicker').datepicker();
这段代码不属于 AngularJS 的管理范围。我们需要编写一个directive 来让 DOM 的改变即时更新到 Model 里。
var directives = angular.module('directives', []); directives.directive('datepicker', function() { return function(scope, element, attrs) { element.datepicker({ inline: true, dateFormat: 'dd.mm.yy', onSelect: function(dateText) { var modelPath = $(this).attr('ng-model'); putObject(modelPath, scope, dateText); scope.$apply(); } }); } }); |
然后在 HTML 中引入这个 direcitve
<input type="text" datepicker ng-model="myObject.myDateValue" /> |
说白了 directive 就是在 HTML 里写自定义的标签属性,达到插件的作用。这种声明式的语法扩展了 HTML。
需要说明的是,有一个 AngularUI 项目提供了大量的 directive 给我们使用,包括 Bootstrap 框架中的插件以及基于 jQuery 的其他很热门的 UI 组件。我之前说过 AngularJS 的社区很活跃嘛,生态系统健全。
ngOption 中的 value
这是个大坑。如果你去查看 ngOption 生成的 <select>
中的 <option>
的选项值(每个 <option value="xxx">
的 value 部分),那绝对是枉费心机。因为这里的值永远都会是 AngularJS 内部元素的索引,并不是你所指定的表单选项值。
还是要转变观念,AngularJS 已经不再用表单进行数据交互了,而是用 Model。使用 $http 来提交 Model,在 php 中则使用 file_get_contents('php://input')
来获取前端提交的数据。
{{ }} 的问题
在页面初始化的时候,用户可能会看到 {{ }},然后闪烁一下才出现真正的内容。
解决办法:
- 使用 ng-cloak directive 来隐藏它
- 使用 ng-bind 替代 {{ }}
将界面与业务逻辑分离
Controller 不应该直接引用 DOM,而应该控制 view 的行为。例如“如果用户操作了 X,应该发生什么事情”,“我从哪里可以获得 X?”
Service 在大部分情况下也不应该直接引用 DOM,它应该是一个单例(singletons),独立于界面,与 view 的逻辑无关。它的角色只是“做 X 操作”。
DOM 操作应该放在 directives 里面。
尽量复用已有功能
你所写的功能很可能 AngularJS 已经实现了,有一些代码是可以抽象出来复用的,使用更 Angular 的方式。总之就是很多 jQuery 的繁琐代码可以被替代。
1. ng-repeat
ng-repeat 很有用。当 Ajax 从服务器获得数据后,我们经常使用 jQuery (比如上面讲过的例子) 向某些 HTML 容器节点中添加更多的元素,这在 AngularJS 里是不好的做法。有了 ng-repeat 一切就变得非常简单了。在你的 $scope 中定义一个数组 (model) 来保存从服务器拉取的数据,然后使用 ng-repeat 将它与 DOM 绑定即可。下面的例子初始化定义了 friends 这个 model
<div ng-init="friends = [{name:'John', age:25}, {name:'Mary', age:28}]"> I have {{friends.length}} friends. They are: <ul> <li ng-repeat="friend in friends"> [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old. </li> </ul> </div> |
显示结果
I have 2 friends. They are: [1] John who is 25 years old. [2] Mary who is 28 years old.
2. ng-show
ng-show 也很有用。使用 jQuery 来根据条件控制界面元素的显示隐藏,这很常见。但是 Angular 有更好的方式来做到这一点。ng-show (以及 ng-hide) 可以根据布尔表达式来决定隐藏和显示。在 $scope 中定义一个变量:
<div ng-show="!loggedIn"> 点击 <a href="#/login">这里</a> 登录 </div> |
类似的内置 directives 还有 ng-disabled, ng-switch 等等,用于条件控制,语法简洁,都很强大。
3. ng-class
ng-class 用于条件性地给元素添加 class,以前我们也经常用 jQuery 来实现。Angular 中的 ng-class 当然更好用了,例子:
<div ng-class="{ errorClass: isError, warningClass: isWarning, okClass: !isError && !isWarning }">...</div> |
在这里 ng-class 接受一个 object 对象,key 为 CSS class 名,值为 $scope 变量控制的条件表达式,其他类似的内置 directives 还有 ng-class-even 和 ng-class-odd,很实用。
$watch 和 $apply
AngularJS 的双向数据绑定是最令人兴奋的特性了,然而它也不是全能的魔法,在某些情况下你需要做一些小小的修正。
当你使用 ng-model, ng-repeat 等等来绑定一个元素的值时, AngularJS 为那个值创建了一个 $watch,只要这个值在 AngularJS 的范围内有任何改变,所有的地方都会同步更新。而你在写自定义的 directive 时,你需要定义你自己的 $watch 来实现这种自动同步。
有时候你在代码中改变了 model 的值,view 却没有更新,这在自定义事件绑定中经常遇到。这时你就需要手动调用 scope.$apply() 来触发界面更新。上面 datepicker 的例子已经说明了这一点。第三方插件可能会有 call back,我们也可以把回调函数写成匿名函数作为参数传入$apply()中。
将 ng-repeat 和其他 directives 结合起来
ng-repeat 很有用,不过它和 DOM 绑定了,很难在同一个元素上使用其他 directives (比如 ng-show, ng-controller 等等)。
如果你想对整个循环使用某个 directive,你可以在 repeat 外再包一层父元素把 directive 写在那儿;如果你想对循环内部的每一个元素使用某个 directive,那么把它放到 ng-repeat 的一个子节点上即可。
Scope
Scope 在 templates 模板中应该是 read-only 的,而在 controller 里应该是 write-only 的。Scope 的目的是引用 model,而不是成为 model。model 就是我们定义的 JavaScript 对象。
$rootScope 是可以用的,不过很可能被滥用
Scopes 在 AngularJS 中形成一定的层级关系,树状结构必然有一个根节点。通常我们用不到它,因为几乎每个 view 都有一个 controller 以及相对应的自己的 scope。
但偶尔有一些数据我们希望全局应用在整个 app 中,这时我们可以将数据注入 $rootScope。因为其他 scope 都会继承 root scope,所以那些注入的数据对于 ng-show 这类 directive 都是可用的,就像是在本地 $scope 中的变量一样。
当然,全局变量是邪恶的,你必须很小心地使用 $rootScope。特别是不要用于代码,而仅仅用于注入数据。如果你非常希望在 $rootScope 写一个函数,那最好把它写到 service 里,这样只有用到的时候它才会被注入,测试起来也方便些。
相反,如果一个函数的功能仅仅是存储和返回一些数据,就不要把它创建成一个 service。
三、AngularJS 项目的目录结构
怎样组织代码文件和目录?这恐怕是初学者一开始就会遇到的问题。AngularJS 应用开发的官方入门项目angular-seed,其文件结构是这样的:
- css/
- img/
- js/
- app.js
- controllers.js
- directives.js
- filters.js
- services.js
- lib/
- partials/
这种结构对于一个简单的单页 app 来说是可行的,只是一旦代码中存在多个 Controller 或者 Service,就很难找到想要寻找的对象了。我们可以对文件按照业务逻辑进行拆分,就像下面这样:
- controllers/
- LoginController.js
- RegistrationController.js
- ProductDetailController.js
- SearchResultsController.js
- directives.js
- filters.js
- models/
- CartModel.js
- ProductModel.js
- SearchResultsModel.js
- UserModel.js
- services/
- CartService.js
- UserService.js
- ProductService.js
这种结构把不同的业务功能拆分为独立的文件,条理清晰,但是仍有一定的局限性。最大的问题是一个业务功能的代码分布在controllers, models, servers 三个不同目录下,要从中挑出正确的文件,建立起代码关联,还是有些麻烦。按照功能进行模块化划分目录结构,应该要更为合理一些:
- cart/
- CartModel.js
- CartService.js
- common/
- product/
- search/
- SearchResultsController.js
- SearchResultsModel.js
- ProductDetailController.js
- ProductModel.js
- ProductService.js
- user/
- LoginController.js
- RegistrationController.js
- UserModel.js
- UserService.js
这样也是适合 RequireJS 等模块加载器的自然直观的代码组织方式。
参考链接:
Ctrl+1 快速修复(最经典的快捷键,就不用多说了)
Ctrl+D: 删除当前行
Ctrl+Alt+↓ 复制当前行到下一行(复制增加)
Ctrl+Alt+↑ 复制当前行到上一行(复制增加)
Alt+↓ 当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)
Alt+↑ 当前行和上面一行交互位置(同上)
Alt+← 前一个编辑的页面
Alt+→ 下一个编辑的页面(当然是针对上面那条来说了)
Alt+Enter 显示当前选择资源(工程,or 文件 or文件)的属性
Shift+Enter 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)
Shift+Ctrl+Enter 在当前行插入空行(原理同上条)
Ctrl+Q 定位到最后编辑的地方
Ctrl+L 定位在某行 (对于程序超过100的人就有福音了)
Ctrl+M 最大化当前的Edit或View (再按则反之)
Ctrl+/ 注释当前行,再按则取消注释
Ctrl+O 快速显示 OutLine
Ctrl+T 快速显示当前类的继承结构
Ctrl+W 关闭当前Editer
Ctrl+K 参照选中的Word快速定位到下一个
Ctrl+E 快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体表示)
Ctrl+/(小键盘) 折叠当前类中的所有代码
Ctrl+×(小键盘) 展开当前类中的所有代码
Ctrl+Space 代码助手完成一些代码的插入(但一般和输入法有冲突,可以修改输入法的热键,也可以暂用Alt+/来代替)
Ctrl+Shift+E 显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作)
Ctrl+J 正向增量查找(按下Ctrl+J后,你所输入的每个字母编辑器都提供快速匹配定位到某个单词,如果没有,则在stutes line中显示没有找到了,查一个单词时,特别实用,这个功能Idea两年前就有了)
Ctrl+Shift+J 反向增量查找(和上条相同,只不过是从后往前查)
Ctrl+Shift+F4 关闭所有打开的Editer
Ctrl+Shift+X 把当前选中的文本全部变味小写
Ctrl+Shift+Y 把当前选中的文本全部变为小写
Ctrl+Shift+F 格式化当前代码
Ctrl+Shift+P 定位到对于的匹配符(譬如{}) (从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)
最近接项目要求,要在svn主干上创建分支,用分支来进行程序的bug修改,而主干上进行新功能的开发。分支上的bug修改完,发布后,可以合并到主干上。项目程序可以在主干和分支之间进行切换,来实现主干和分支的同时维护。
1.创建分支
创建分支实际上就是将程序copy一份到指定的分支目录,如下图示:
在项目名称上点击右键,弹出菜单,选择“Team”,再选择“Branch/Tag”,弹出下面的页面:
上图中的“Copy to URL”填写创建新分支的路径地址,后面会将程序copy到该目录下,形成新的分支。点击“Next”:
选择当前最新的版本,点击“Next”
如果勾选了上图下面的switch working copy to new branch/tag,eclipse的程序项目会自动切换到分支下。这里我们不选择,待会自己切换。
这样就创建了一个1.0的分支
2.合并
可以从主干合并到分支,也可以从分支合并到主干,根据需要可以选择合适的选项,如下图:
上图中的选项:
1) 从主干合并到分支
2) 从分支合并到主干
3) 将主干上的修改合并到分支
4) 合并2个分支到主干
5) 从主干到分支,手工指定不需要合并的修改
6) 从主干到分支,手工指定要合并的修改
上图显示没有任何修改,所以不用进行合并。
3.切换
在项目名称上点击右键,选择“Team” –> “switch to another Branch/Tag/Revision”。
选择需要切换的目的地址,点击ok即可。
这样,在项目里就可以在主干和若干分支间进行任意切换,来实现对不同版本/分支的程序进行修改提交操作。
参考:
Overview of CollabNet Merge Client
https://desktop-eclipse.open.collab.net/servlets/ProjectProcess?pageID=MEuUjb&freeformpage=Merge%20Client
eclipse中将SVN分支合并到主干的方法
http://www.darrenfang.com/merge-branches-to-trunk-in-eclipse.html