玩转前端总结

by 程序范儿 2014-01-05 22:15

适合读者

前端工程师,想做小站的程序员

我的需求

以前写的几个博客都荒废了,最近想重新拾荒,开始考虑在WordPress上搭建,但这样一来就没有了玩程序的感觉,后来又看上了GitHub Pages这个服务,因为朋友们在上面玩的都不错,这里也推荐一个博客,如果你对IOS感兴趣可以看看lzyy.github.com,这个博客就是基于GitHub Pages的,如果你想了解这种博客是怎样维护的,你可以看看他写的文章使用github作为博客引擎,当然如果你很懒也可以直接fork他的项目https://github.com/lzyy/lzyy.github.com,在这个基础上直接改出你的博客。

Github自己也说的很清楚,这不是他们自己的技术,而是整合了Jekyll,有兴趣的同学可以自己看看。

最终我没有采纳这种形式,于是着手开始自己写,这样一个小东西远没有我以前写的任何系统高端上档次,能让我感觉到的就是生活比较轻松,状态比较自然,也不用考虑那么多性能和带宽方面的问题。

Bootstrap

现在人们的阅读都在从PC上向移动端转移,像博客这样的系统,最好能够在不同尺寸的屏幕上都有良好的阅读体验,于是能想到的就是Bootstrap,它能够实现自适应的版面和布局,如果你能够按照它的方式编写HTML和CSS,在不同的终端下都有很好的体验效果。

有兴趣的同学可以看一下这几个官方的例子:

http://v3.bootcss.com/examples/grid/

http://v3.bootcss.com/examples/jumbotron/

改变一下浏览器的尺寸看看,效果应该都不错,当然这里也推荐一个小插件Window Resizer,在Chrome和Firefox下都有,这个插件可以很方便的改变尺寸,让你看到效果:

Window Resizer

Bootstrap官方网站其实就是一个很好的宣传:

网页尺寸


网页尺寸

手机尺寸


手机尺寸

右上角那个是可以点开的,上面一排仅仅是被折叠了而已。

最近也为新公司开发了一套后台,以前写后天界面就要折腾半天,终于找到了一套基于Bootstrap的后台模板,可以说算是比较养眼的,而且套上去也不费力,名字叫Matrix Admin,我截了两张图,一张是正常浏览器尺寸下的,另外一张是屏幕缩小以后的:

网页尺寸


Matrix Admin正常

手机尺寸


Matrix Admin缩小

引用bootstrap的方法也很简单,只需要引入三个文件:

<link rel="stylesheet" href="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/css/bootstrap.min.css"> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="http://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script> <script src="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script> 

如果想用Bootstrap的js插件,JQuery要同时被引入进来。

AngularJS

选定了Bootstrap作为CSS的首选,接下来要选择JS框架,选择AngularJS有那么几个原因:

  1. 他能很干净的实现JS的MVC,几乎在HTML文件里不会再看到任何JS代码,都被封装到了不同的Controller里,这和一般的后端框架使用起来是一样的。
  2. 他的Template比我以前用的其它JS模板都要强悍,普通的JS模板只能实现变量的替换,稍微强一点的可以实现一些控制语句,如IF LOOP等,部分模板可以实现对时间等特殊变量的重新格式化,我能想到的需求它都可以满足。
  3. 以前写JS为了让数据和展示同步,例如用户的登录信息等,都需要自己来处理,在AngularJS这是它的标准能力,你渲染完模板以后,如果你的数据被重新加载,那么模板会自动重新渲染。
  4. 它可以很友好的让不同JS之间共享数据或服务,例如我们需要维护用户的Session信息,这些都可以轻松的搞定。
  5. 他可以把HTML上的事件和Controller里的方法直接关联起来,这样代码会更干净。

例如程序范儿的JS结构是这样的:

/js /js/app.js /js/app /js/app/controller /js/app/controller/articlelist.js /js/app/controller/comment.js /js/app/controller/login.js /js/app/controller/site.js /js/app/service.js 

我在渲染页面当中文章列表的时候,我就用上了模板:

<div ng-controller="CArticleList" ng-init="init()"> <div ng-repeat="item in items"> <div><h3><a href="/article?id="></a></h3></div> <p>by <a href="/">程序范儿</a> <mydate>0NaN-NaN-NaN NaN:NaN</mydate></p> <div ng-bind-html="item.summary"></div> </div> </div> 

这里的CArticleList就是/js/app/controller/articlelist.js文件对应的类,这里的工作就是把绑定在CArticleList上文章列表数据渲染出来,贴一下实现:

myApp.controller('CArticleList', function($scope, session, $http, $sce) { $scope.pos = 0; $scope.len = 10; $scope.items = []; $scope.init = function() { $scope.items = []; $scope.list(); } $scope.actionMore = function() { $scope.list(); } $scope.list = function() { $http.get('/api/article/list?&pos=' + $scope.pos + '&len=' + $scope.len).success(function(res) { if(res.code == 0) { items = res.data.items; for(i in items) { items[i]['summary'] = $sce.trustAsHtml(items[i]['summary']); $scope.items.push(items[i]); } $scope.pos = res.data.pos; } }); } }); 

所以AJAX被封装在Controller里和HTML分离的很干净,如果你改变了$scope.items的内容,那么HTML这一端会自动重新渲染,不需要程序员费心。

你可以看到了程序范儿最早的设计是有用户登录这个环节的,后来我给雪藏了,因为这里只有文章也没有别的什么值得大家筑巢的。

但是我也贴一段旧代码,体验一下如何设计登录和维护Session信息,先贴Session设计/js/app/service.js

myApp.factory('session', function($http) { var data = null; $http.post('/do/session').success(function(res) { if(res.code == 0) { data = res.data; } }); return { set:function(d) { $http.post('/do/session').success(function(res) { if(res.code == 0) { data = res.data; } }); }, get:function() { return data; }, clean:function() { $http.post('/do/logout').success(function(res) { if(res.code == 0) { data = null; } }); } }; }); 

代码也比较简洁,直接从接口里读取,Service是AngularJS当中一种可以用来共享数据的方法,我在/js/app/controller/site.js里获取到了共享的session信息:

myApp.controller('CSite', function($scope, session) { $scope.session = session; $scope.pos = 0; $scope.len = 10; $scope.articles = []; $scope.getSession = function() { return session.get(); } $scope.actionLogout = function() { $scope.session.clean(); } $scope.actionAdd = function() { if($scope.session.get()==null) $scope.actionLogin(); } $scope.actionLogin = function() { if(!$scope.isLogin == false) { return; } $scope.dialogTemplatePath = "/login"; $('#g-dialog').modal(true); } }); 

接着我就可以在HTML里面去展示用户的登录状态:

<body ng-controller="CSite"> //...省了一千字 <ul ng-if="getSession()"> <li> <a href="#" data-toggle="dropdown"><b></b></a> <ul> <li></li> <li> <a href="#" ng-click="actionLogout();">退出</a> </li> </ul> </li> </ul> <ul ng-if="!getSession()"> <li> <a href="#" ng-click="actionLogin()">登录</a> </li> <li> <a href="#">注册</a> </li> </ul> 

ng-if是一个很不错的标记,只有当getSession()返回数据的时候才会显示,如果没有回来数据就显示登录界面,当用户登录成功写入session信息/js/app/controller/login.js:

myApp.controller('CLogin', function($scope, session) { $scope.session = session; $('#g-login-form').validate({ submitHandler: function(form) { $(form).ajaxSubmit({ dataType: "json", beforeSubmit: function() { }, success: function(res) { if(res.code == 0) { $scope.session.set(); $('#g-dialog').modal('hide'); } else { } } }); } }); }); 

所以相当于CLoginCSite共享了session服务。

Uglify

MVC化的JS写起来很方便,但AngularJS并没有解决引用问题,如果想在当前页面使用CSite你首先要先引用它:

<script type="text/javascript" src="/js/libs/angularjs/1.2.7/angular.js"></script> <script type="text/javascript" src="/js/app/service.js"></script> <script type="text/javascript" src="/js/app/controller/site.js" ></script> 

自从使用JQuery以后也知道min.js后缀的意义,就是被压缩的JS,Uglify算是公认的比较理想的压缩工具。所以程序范儿的引入的JS是:

<script type="text/javascript" src="/res/js/main.min.js?v=2" ></script> 

JS被压缩了,所以很难看到刚才讲到的那些JS结构,这个压缩的JS包括了:

  • JQuery
  • Bootstrap
  • AngularJS
  • Other

Grunt

虽然Uglify能很好的压缩JS,但平时开发的时候,如果你每写一句就要去编译一次哪也是很麻烦的,所以Grunt出现了,可以利用Gruntwatch功能,实现对JS代码或者CSS代码的监控,当代码被改变自动合并或者压缩代码。

平时工作的时候为了简单高效,虽然也是合并出main.min.js但这个文件不是用Uglify压缩的,而是采用grunt-contrib-concat进行了合并,这样编译的速度会快很多,基本上这边保存,立即就能生成结果。

当我去发布正式版本的时候,我才会执行:

grunt uglify grunt cssmin 

后面那个命令用来压缩css,前面那个是用来压缩js。

所以Grunt的另外一个好处是他可以实现更复杂的功能,可以全面照顾到CSS和JS。

开发的时候我只需要一个命令:

grunt watch 

这个命令会一直观察我的文件改动情况,当我保存了代码,就会立即重新生成新的main.min.jsmain.min.css文件。

Grunt虽然很智能,但配置起来还是需要点功夫,我贴一下我自己的Grunt配置:

module.exports = function (grunt) { var jsrc = [ '../lib/jquery/jquery-1.10.2.js', '../lib/jquery/**/*.js', '../lib/angular/angular.js', '../sass/javascripts/bootstrap/modal.js', '../sass/javascripts/bootstrap/dropdown.js', '../js/app.js', '../js/app/service.js', '../js/app/controller/**/*.js' ]; var csrc = [ 'stylesheets/main.css', '../lib/font-awesome/css/font-awesome.css' ]; var sasssrc = [ '../sass/sass/*.scss', '../sass/include/*.scss', ]; grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), compass: { dist: { options: { config: '../sass/config.rb' } } }, concat: { js: { src: jsrc, dest: '../../wwwroot/res/js/<%= pkg.name %>.min.js' }, css: { src: csrc, dest: '../../wwwroot/res/css/<%= pkg.name %>.min.css' } }, cssmin: { css: { src: csrc, dest: '../../wwwroot/res/css/<%= pkg.name %>.min.css' } }, uglify: { options: { banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n', mangle: false }, build: { src: jsrc, dest: '../../wwwroot/res/js/<%= pkg.name %>.min.js' } }, watch: { //js: { files: jsrc, tasks: [ 'uglify' ,'compass'] }, js: { files: jsrc, tasks: ['concat'],}, css: { files: sasssrc, tasks: ['compass', 'concat'] }, livereload:{ options:{ livereload:true }, files:[ '../sass/sass/*.scss', '../sass/include/*.scss', '../js/app/**/*.js', '../../layout/**/*.php', '../lib/jquery/**/*.js', ] } } }); // load plugins grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-compass'); grunt.loadNpmTasks('grunt-contrib-cssmin'); // register at least this one task grunt.registerTask('default', [ 'watch' ]); grunt.registerTask('css', [ 'compass', 'concat' ]); }; 

这里的亮点是这几行配置:

livereload:{ options:{ livereload:true }, files:[ '../sass/sass/*.scss', '../sass/include/*.scss', '../js/app/**/*.js', '../../layout/**/*.php', '../lib/jquery/**/*.js', ] } 

LiveReload

程序员一般有两个屏幕,如果你还没有两个显示器,希望你赶快让公司帮你改善一下环境,作为程序员你太可怜了。

左边用来编写代码,右边用来放浏览器查看结果,以前我们需要手工去刷新浏览器,现在用LiveReload(http://livereload.com/),你可以监控一些文件,当他们改变的时候让你的浏览器自动刷新。

所以我的流程就变成了写JS或者CSS/保存/concat合并/LiveReload自动刷新

这里另外一个亮点是这一行:

'../../layout/**/*.php' 

当我的PHP模板改变了以后,也会自动刷新我右边的浏览器,这样的效果的确是不错的。

Sass & Compass

虽然Bootstrap可以满足我大部分的样式需求,但你肯定还有自己的需要,这时候你需要从LessSass当中选一种方式,我选了Sass,这也意味着我同时选择了Compass,这两个之间的关系就是一对儿好基友的关系,就像Ruby on Rails,CompassSass的加强。

如果你还不了解它们,我推荐你读几篇文章,都是一个人写的,这个人的博客你也可以多留意:

  1. SASS用法指南
  2. Compass用法指南

这人的文章写的干净简洁,很不错。

Sass可以让你写CSS更有逻辑性,Compass可以帮你解决很多CSS的兼容性问题,例如圆角。

cssmin

这个没什么太多可讲的,就是压缩css用的,要结合grunt用。

Fontawesome

我以前不知道有这么个东西,当我去用Matrix Admin的时候我才知道,这个东西很神奇,把我们常用的ICON变成了特殊的字体,这样就不用为去找那些常用ICON烦恼了,以前都是去easyicon找ICON。

Fontawesome一共369个ICON,使用方法很简单:

<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"> <i></i>RSS 

这就是程序范儿右上角那个RSS的图标,不是美工的设计,是一个特殊的字体,可以改变大小、颜色也可以被鼠标选中。

我现在用的这个Markdown编辑器也支持Fontawesome,这个编辑器叫StackEdit,支持向各种云存储同步,这样写内容不会丢失,但StackEdit仅仅是Chrome浏览器的一个插件,用的时候也不用到处去找。

RequireJS

在使用Grunt之前,也尝试了一下RequireJS,它可以帮我动态的加载JS,但一定要符合AMD规范,这种方法也不错,一样可以让AngularJS跑起来,不过配置的东西太多,按照同事的说话,CSS和JSS全部合并起来也就是一张图片的size何必计较太多呢,于是改成了Grunt。

--EOF--

若无特别说明,本站文章均为原创,转载请保留链接,谢谢

玩转前端总结