2016.10.29更新 本文存在大量的错误,仅供参考。

不知不觉在前端领域马上一个年头就要过去了,然而再看看自己的代码,果然够烂,那么为什么代码一直没有用面向对象的思维去写CSS呢?首先有两点:一点就是感觉没必要,还有一点就是难控制。为什么这么说呢?作为刚入门的人来说,第一写的代码就少,平时也不会感觉到代码有什么问题,等开发多了,虽然感觉到问题了,但是你还是很难去按照面向对象的思维去写,因为按照面向对象去思维写需要你把握全局观,更是面向未来编程,把握不好,越写越乱。所以很多新手一直都还是按照面向过程来写。今天我主要用一些实际的例子讲解面向对象的CSS以及JS让你写更少的代码,让你越来越懒。这篇文章绝对不是侃侃而谈,这些例子都是我实际开发中的问题,写这篇文章的目的就是让自己以后写更好的代码,同时分享给大家一起共勉。

CSS懒人篇

写页面的时候发现好几处的按钮都是这种样式,于是把这个按钮的样式单独提取出来放着全局css文件中

  1. .base-btn {
  2. display: block;
  3. width: 90%;
  4. height: 54px;
  5. line-height: 54px;
  6. text-align: center;
  7. background-color: #14B5A9;
  8. color: #fff;
  9. font-size: 1.4rem;
  10. margin: 0 auto;
  11. }

但这绝对是个不正确的做法,还不如不提取,因为写的太死,这也就是新手为什么不喜欢用面向对象的方式写代码的原因,因为新手很难考虑周全,最后反而还不如直接写的好。看看这个页面的按钮。

这里不应该写width:90%margin:0 auto因为这些都是不固定的因素,因此有些是不能共用的。

  1. .base-btn {
  2. display: block;
  3. height: 54px;
  4. line-height: 54px;
  5. text-align: center;
  6. background-color: #14B5A9;
  7. color: #fff;
  8. font-size: 1.4rem;
  9. }

这样就好很多了,但还是很有问题的,尤其是命名,严重的问题,因为不只是有这一种按钮,看上面的图片,是有两种按钮样式的,因此我们命名也得改一下。

  1. .btn{
  2. display: block;
  3. height: 54px;
  4. line-height: 54px;
  5. text-align: center;
  6. font-size: 1.4rem;
  7. }
  8. .btn-14B5A9{
  9. background-color: #14B5A9;
  10. color: #fff;
  11. }

我的习惯是用背景颜色命名,主要原因是颜色叫不出名字T_T,当然这种方式还是不同好的,用的时候还得试颜色,如果你有好的命名颜色方法还望能够分享一下。这里定义了两个类是很有必要的,一个是基础样式,就是说90%以上的按钮都会有这个样式就叫它基础样式,而下面的.btn-14B5A9是某个特定的按钮才有的样式,因此得单独写,另外还有宽度和高度,如果页面大部分都一样的话,还是可以提取出来写一个class的,但注意关于宽度和高度是易变的所以千万不要写在.btn里面,除非你有一万份把握。

  1. .btn-w45-h140{
  2. width: 140px;
  3. height: 45px;
  4. line-height: 45px;
  5. }

虽然这样写下来还算有那么一点面向对象的样子,但还是有太多的问题,尤其在命名上,因此我建议还是通过组件化来写。对于基本样式还是提取出来,然后写组件。

如这一块我们可以把它写成一个组件。

话说虽然市面上有很多写组件的框架或者库,但我还是不太满意,因为往往项目都没有必要使用那么大的框架,只是一点点东西而已,但苦于HTML没有导入另外一个HTML的功能,这句话搁在以前是对的,但HTML5已经支持导入另外一个页面了,详情可以搜索link import html但可惜的大部分浏览器都不支持,安卓的微信倒是支持,不过IOS不支持,UC也不支持,好吧,还是不能用。于是想起了ES6里面的模板字符串,于是有了下文。

我想把这个tab做成组件,下次用的时候直接导入就可以使用,先来看看怎么使用吧。

  1. <div id="tab"></div>
  2. <script src="tab.js"></script>
  3. <script>
  4. tab({
  5. title:[
  6. 'CSS',
  7. 'Javascript',
  8. 'HTML5&&CSS3'
  9. ],
  10. content:[
  11. '这是一篇CSS文章',
  12. '这是一篇Javascript文章',
  13. '这是一篇HTML5和CSS3文章'
  14. ]
  15. })
  16. </script>

定义一个id,这个id和tab组件名字一样。然后引入组件文件,最后传递数据。

效果如下:

组件代码:

  1. function tab(obj){
  2. var html = `
  3. <nav class="title">
  4. <a href="#a">${obj.title[0]}</a>
  5. <a href="#b">${obj.title[1]}</a>
  6. <a href="#c">${obj.title[2]}</a>
  7. </nav>
  8. <ul class="content">
  9. <li id="a">${obj.content[0]}</li>
  10. <li id="b">${obj.content[1]}</li>
  11. <li id="c">${obj.content[2]}</li>
  12. </ul>
  13. `;
  14. var sty = `
  15. <style>
  16. body,div,nav,ul,li{
  17. margin:0;
  18. padding:0;
  19. }
  20. ul{
  21. list-style:none;
  22. }
  23. #tab{
  24. width:300px;
  25. margin:100px auto;
  26. }
  27. #tab .title a{
  28. float:left;
  29. width:33.333333333%;
  30. height:35px;
  31. line-height:35px;
  32. text-align:center;
  33. border:1px solid #dedede;
  34. box-sizing:border-box;
  35. text-decoration:none;
  36. }
  37. #tab .title a:nth-last-of-type(-n+2){
  38. border-left:none;
  39. }
  40. #tab .content{
  41. clear:both;
  42. position:relative;
  43. }
  44. #tab .content li{
  45. width:100%;
  46. height:300px;
  47. outline:1px solid #dedede;
  48. background-color:#fff;
  49. position:absolute;
  50. left:0;
  51. top:0;
  52. z-index:-999;
  53. }
  54. #tab .content li:first-of-type{
  55. z-index:2;
  56. }
  57. #tab .content li:target{
  58. z-index:3;
  59. }
  60. </style>
  61. `;
  62. document.getElementById('tab').innerHTML = html;
  63. document.getElementsByTagName('head')[0].innerHTML += sty;
  64. }

其实原理和字符串拼接一样,只不过用了ES6的语法,这样看起来更加方便,之所以还有传递一个数据过去是因为名称啥的可能不一样,如果说这个组件的内容什么的都是固定的,那就没有必要留接口了。不过这虽然解决了一下小问题,但还是不足的,可扩展性不怎么好。

  1. document.getElementById('tab').innerHTML = html;
  2. var oHead = document.getElementsByTagName('head')[0];
  3. oHead.innerHTML = sty + oHead.innerHTML;

把style放在最上面,这样下面就可以去修改里面的代码。

还有一些细节的问题,就是组件命名,比如说tab,可能有多种样式的,就是有不同的tab组件,那究竟是都放在一个文件里面,还是另外再创建一个文件?如果是都放在一个js文件里面,那么命名应该如何去名?既然都是tab就不能名字都一样,所以这也是我们得解决的问题,我的想法就是按照一个顺序,或者说按照效果,或者功能去命名。

这种方式显然也不太好,命名确实也是一个头疼的问题,实际上我最不满意的是HTML代码结构是写死了的,如果有些地方和这个组件只是相差一点点,可能我们都得重新写过,想想这段代码。

你敢保证都是三条数据?这样的组件还不如不要,宁愿用字符串拼接。看来这种方式还是不太行,不过有一种情况是可行的,就是对于不太可能改动的组件,可以使用这种方式,对于改动较大的还是别用这种方式写。

先说一下这里用了ES6的语法所以有些浏览器不支持,我们还得借助一些工具将ES6转换成兼容的代码。转换教程看这里将ES6转换成ES5

2016.09.28更新

经过这两天的研究,最终的结果很遗憾,目前的组件化还是存在着太多的问题,其中最严重的问题就是可扩展性,市面上大部分组件化的结构都是写死的,如果我需要在里面增加一个元素或者删除一个元素,都是比较麻烦的。虽然有很多不错的框架,但它们和我想要的结果还是不太一样,我需要的是简单,对于不变的组件,直接引入就行。

对于需要传递数据的应该这样。

但尽管这样,一旦HTML,CSS,JS混合一起必然组件化可扩展性就不可能完美,类似这一个

我们有必要把这个做成组件吗?最终考虑是没有必要,其一如果组件了那么究竟用什么标签?如果这不是问题,那么这个组件了使用方便吗?引入一个JS?可扩展性呢?你会发现如果用组件化那么会越来越乱,我的想法是用CSS面向对象的方式写,至少在可扩展性上比较好,这里一再强调可扩展性是因为,我们之所以想要组件化就是为了方便,不需要重复的写代码,但如果说事情不是这样,那么就没有必要组件化了。

这种头部啥的都是一模一样,也不怎么需要改动的,还是建议用组件化的,也不要引什么框架了,就这么个东西还引的话反而麻烦了。记住组件目的就是:简单,实用,可扩展。

这篇文章会不断的更新,有好的想法有补充上来,也希望如果你有不错的建议,也能分享出来。

JS可扩展性

一个时间格式化组件引出的学问,后台给返回一个总毫秒数,我得格式化成这个样子。

  1. Vue.filter('timeFormat',function(value,select,split){
  2. var date = new Date(value);
  3. var time = {
  4. y:date.getFullYear(),
  5. d:toS(date.getDate()),
  6. m:toS(date.getMonth()+1)
  7. };
  8. function toS(value){
  9. return value>10?value:'0' + value;
  10. }
  11. var txt = '';
  12. for(var i=0,len=select.length;i<len;i+=1){
  13. if(i==len-1){
  14. txt+= time[select[i]];
  15. }else{
  16. txt+= time[select[i]] + split;
  17. }
  18. }
  19. return txt;
  20. })

这里用了Vue.js,你如果不了解不要紧,因为重点不在这,而是思路。

使用:

  1. <time class="base-gray">时间:{{ item.time | timeFormat 'ymd' '-'}}</time>

这里主要的优点就是它根据你输入的y,m,d而进行输出,重点还在于如果你需要新增一个字段,也不必改变代码,只需要在time里面加一个就好了,其他的都不用动,之所以有这种好处就是因为这里没有用判断,而是用了time[select[i]]根据用户的选择来输出,当然这段代码也并不是完美的,多少还是有些问题,但至少会比你直接写死的好。

2016.09.28更新

上面说了组件化的缺与失,主要原因就是,没有完美的东西,但如果不考虑整体组件化,那么情况就会好很多,下面通过一个例子演示。

我想页面中有很多这种单选效果吧,但注意千万不要把整个功能当做一个组件,那样会有很多问题,我只能要它的一部分,也就是功能!我们把它的单选功能封装起来。

  1. <style>
  2. span{
  3. float:left;
  4. width:100px;
  5. height:35px;
  6. line-height:35px;
  7. text-align:center;
  8. border:1px solid #ccc;
  9. cursor:pointer;
  10. }
  11. </style>
  12. <span id="radius1">111</span>
  13. <span id="radius2">222</span>
  14. <script>
  15. function Radiu(radius1,radius2){
  16. this.n1 = document.querySelector(radius1);
  17. this.n2 = document.querySelector(radius2);
  18. }
  19. Radiu.prototype = {
  20. init:function(callback){
  21. this.click(callback);
  22. },
  23. click:function(callback){
  24. this.n1.onclick = function(){
  25. callback(1,this.n1,this.n2);
  26. }.bind(this);
  27. this.n2.onclick = function(){
  28. callback(2,this.n2,this.n1);
  29. }.bind(this);
  30. }
  31. };
  32. new Radiu('#radius1','#radius2').init(function(num,currentEl,siblingEl){
  33. currentEl.style.color = 'red';
  34. siblingEl.style.color = '#000';
  35. });
  36. </script>

这里一个很简单的封装,但可扩展性很好,因为只提供一个callback,给一个当前单击的元素,和一个兄弟元素,以及一个num表示第几个(可能会有需要),这种封装可比你直接把所有功能都封装起来好,直接把所以的都封装,可扩展性必然就很差。

  1. <div class="method" data-method="2">
  2. <a href="javascript:;" class="claimMethod_select"><span></span><em>邮寄</em>
  3. </a>
  4. <a href="javascript:;" class="claimMethod_selected"><span></span><em>自取</
  5. em></a>
  6. </div>
  7. <script>
  8. function Radiu(radius1,radius2){
  9. this.n1 = document.querySelector(radius1);
  10. this.n2 = document.querySelector(radius2);
  11. }
  12. Radiu.prototype = {
  13. init:function(callback){
  14. this.click(callback);
  15. },
  16. click:function(callback){
  17. this.n1.onclick = function(){
  18. callback(1,this.n1,this.n2);
  19. }.bind(this);
  20. this.n2.onclick = function(){
  21. callback(2,this.n2,this.n1);
  22. }.bind(this);
  23. }
  24. };
  25. new Radiu('.method>a:nth-of-type(1)','.method>a:nth-of-type(2)').init(
  26. function(num,currentEl,siblingEl){
  27. currentEl.className = 'claimMethod_selected';
  28. siblingEl.className = 'claimMethod_select';
  29. });
  30. </script>

完全不必在乎结构长什么样子,这就是可扩展性的好处。

写完后发现,组件化还是有很长一段路要走,因为有太多的不足,虽然有太多不足,但并不代表不重要,不需要,也希望你看完这篇文章有一点小小的启发。

待更新...

来,一起让我们越来越懒,面向CSS、JS未来编程。(9.28已更新)的更多相关文章

  1. 一个小公司的前端笔试HTML CSS JS

    网上有这套题的答案,版本也很多,我做了很多参考.本文就当个小笔记,可能有错误,还望指正~ 第1章  Html篇 1. 你做的网页在哪些浏览器测试过?这些浏览器的内核分别是什么? 浏览器类型 内核 Fi ...

  2. 1. web前端开发分享-css,js入门篇

    关注前端这么多年,没有大的成就,就入门期间积累了不少技巧与心得,跟大家分享一下,不一定都适合每个人,毕竟人与人的教育背景与成长环境心理活动都有差别,但就别人的心得再结合自己的特点,然后探索适合自己的学 ...

  3. web前端开发分享-css,js入门篇(转)

    转自:http://www.cnblogs.com/jikey/p/3600308.html 关注前端这么多年,没有大的成就,就入门期间积累了不少技巧与心得,跟大家分享一下,不一定都适合每个人,毕竟人 ...

  4. 面向GC的Java编程

    转自http://hellojava.info/?p=341 HelloJava微信公众账号网站 面向GC的Java编程 Leave a reply 这是内部一个同事(沐剑)写的文章,国外有一家专门做 ...

  5. asp.net mvc项目实记-开启伪静态-Bundle压缩css,js

    百度这些东西,还是会浪费了一些不必要的时间,记录记录以备后续 一.开启伪静态 如果不在web.config中配置管道开关则伪静态无效 首先在RouteConfig.cs中中注册路由 routes.Ma ...

  6. 基于 OSGi 的面向服务的组件编程,helloworld

    基于 OSGi 的面向服务的组件编程 OSGi(Open Services Gateway Initiative,开放服务网关协议)提供了一个面向服务组件的编程模型,基于 OSGi 编程,具有模块化, ...

  7. web前端开发分享-css,js入门篇

    学习没有捷径,但学习是有技巧与方法.   一,css入门篇:   推荐书籍:css哪些事儿,精通css. 理由:css那些事儿,他是一本介绍css基础类的书,是入门的经典读物. 系统的介绍了css的选 ...

  8. 前端工程师面试问题归纳(一、问答类html/css/js基础)

    一.参考资源 1.前端面试题及答案整理(一) 2.2017年前端面试题整理汇总100题 3.2018最新Web前端经典面试试题及答案 4.[javascript常见面试题]常见前端面试题及答案 5.W ...

  9. 基于 OSGi 的面向服务的组件编程

    作者:曹 羽中 (caoyuz@cn.ibm.com), 软件工程师, IBM中国开发中心 出处:http://www.ibm.com/developerworks/cn/opensource/os- ...

随机推荐

  1. 初步了解nodejs

    什么是Node.js? 很多初学者并没有真正地理解Node.js到底是什么.nodejs.org网站中的描述也没有多大帮助. 首先要清楚Node不是一个Web服务器,这十分重要.它本身并不能做任何事情 ...

  2. Webpack 配置摘要

    open-browser-webpack-plugin 自动打开浏览器 html-webpack-plugin 通过 JS 生成 HTML webpack.optimize.UglifyJsPlugi ...

  3. .NET Core采用的全新配置系统[9]: 为什么针对XML的支持不够好?如何改进?

    物理文件是我们最常用到的原始配置的载体,最佳的配置文件格式主要由三种,它们分别是JSON.XML和INI,对应的配置源类型分别是JsonConfigurationSource.XmlConfigura ...

  4. FragmentTabHost的基本用法

    开通博客以来已经约莫1个月了.几次想提笔写写东西,但总是由于各种各样的原因并没有开始.现在,年假刚结束,项目也还没有开始,但最终促使我写这篇博客的是,看了一篇博友写的新年计划,说是要在新的一年中写50 ...

  5. mybatis_个人总结

    在使用mybatis框架开发数据访问层的过程中,我在这段时间遇到很多细节问题困住我,在这里我来分享一下我遇到的坑,希望能帮到大家. 一.mybatis动态代理方式开发的规范: 1.注意在mybatis ...

  6. 算法与数据结构(十四) 堆排序 (Swift 3.0版)

    上篇博客主要讲了冒泡排序.插入排序.希尔排序以及选择排序.本篇博客就来讲一下堆排序(Heap Sort).看到堆排序这个名字我们就应该知道这种排序方式的特点,就是利用堆来讲我们的序列进行排序.&quo ...

  7. c#多线程

    一.使用线程的理由 1.可以使用线程将代码同其他代码隔离,提高应用程序的可靠性. 2.可以使用线程来简化编码. 3.可以使用线程来实现并发执行. 二.基本知识 1.进程与线程:进程作为操作系统执行程序 ...

  8. C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(1)

    一看这个标题,是不去取名有点绕呢?或者是,还有些问题?报告LZ...你的标题取得有问题,是个病句!↖(^ω^)↗!!!先不要急,其实我今天带给大家的就是CoreCLR中的coreclr.其中它是在名字 ...

  9. Html.DropDownLis绑定数据库

    效果: 方法一: View: <div class="col-md-md-4"> <div class="input-group"> & ...

  10. Docker与CI持续集成/CD

    背景        Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制 ...