html5+css3之制作header实例与更新


Posted in HTML / CSS onDecember 21, 2020

上次,我们形成了两种header的布局,一种flexbox,一种float,最后与身边做重构的同事交流下来,选择了float的布局。

事实上布局的选型不需要我关注,我的参与或者一些意见多数是自我提升,但要说html结构完全控制于csser的话就不一定了

在整个header组件的代码过程中,我与重构同事就一些地方发生了重复的交流,争论,今天就header组件的布局以及功能实现,聊一聊js与css的配合

然后header组件本身是一个老组件,我们顺便探讨下,这类老组件应该如何翻新比较合适。

最初的结构

最开始重构的同事给了我一个已经做好了的页面:

 html5+css3之制作header实例与更新

我们针对其中一些小的体验上做了讨论,并且知会到设计组,便改了,很顺畅,然后我开始了愉快的代码,这是其中一块HTML的结构:

<header class="cm-header" style="top: 50px;">
   <span class="fl cm-header-icon icon-back "></span>
   <span class="fr cm-header-btn">确认</span>
   <span class="fr cm-header-icon"><i class="icon-home"></i></span>
   <span class="fr cm-header-icon"><i class="icond-list"></i></span>
   <h1 class="cm-page-title">
     页面标题</h1>
 </header>

这里除去h1标签中的文字不说,因为其中可能表现的非常复杂,我们后面再说,其中的按钮有以下功能:

① 第二行:回退按钮 
② 第三行:确认

PS:左边采用float布局所以第一个元素在最右边

③ 第四行:home标签 
④ 第五行:三个点,点击会出一个侧边栏

以上便是HTML的实现,但是对与程序员来说,头部除了按钮(btn)以外就只有图标(icon),所以以上的结构事实上js一般是不买账的

Jser需要的结构

与重构同事交流下来,原因是这样的:

① 因为回退比较特殊,所以多了一个样式,具体什么我没记住了 
② icon代表背景图,icond代表CSS3画的,CSS3画的可扩展性高,比如换颜色什么的 
③ ......

当时双方的讨论还是比较激烈的,但是对icond全部变成icon,重构同事不同意,于是也就作罢,经过一轮讨论,结构变成了这样:

<header class="cm-header" style="top: 50px;">
   <span class="fl cm-header-icon"><i class="icon-back"></i></span>
   <span class="fr cm-header-btn">确认</span>
   <span class="fr cm-header-icon"><i class="icon-home"></i></span>
   <span class="fr cm-header-icon"><i class="icond-list"></i></span>
   <h1 class="cm-page-title">
     页面标题</h1>
 </header>

做了很小的变化,将back的结构与其它icon类型按钮做了统一,于是我开始了愉快的代码

PS:注意,icond与icon类型的标签会不同程度的在header处出现,无法控制

结构的问题

因为公司的header一直便存在,我做的过程中必须考虑到两个方面的问题:

① 方便扩展但是要做到接口兼容 
② 需要通过各个标签的tagname与Hybrid进行联调

也就是说,每个标签叫什么名字,是已经定死了的,甚至一些标签的回调也被限制了,我这里的数据结构大概如下:

{
 left: [],
 center: [],
 right: [
   {
     'tagname': 'home', callback: function () {
       console.log('返回');
     }
   },
   { 'tagname': 'search' },
   {
     'tagname': 'list', callback: function (e) {
        //......
     }
   },
   { 'tagname': 'tel', 'number': '56973144' },
   {
     'tagname': 'commit', 'value': '登录', callback: function () {
       console.log('登录');
     }
   },
   {
     'tagname': 'custom', 'value': '定制化',
     itemFn: function () {
       return '<span class="cm-header-btn fr js_custom">定制化</span>';
     },
     callback: function () {
       console.log('定制化');
     }
   }

可以看到,一个tagname一个按钮,而现在问题来了:我们并不知道某个tagname应该是icon或者是icond 

但是根据是否存在value字段,我们是可以判断其是否应该具有i子标签,这个时候我们是怎么解决的呢?

建立tagname与classname的映射关系,比如:

var map = {
   'home': 'icon',
   'list': 'icond'
 }

当然,这种做法,自然十分让人感到难受,如果小图标统一为icon,我在模板中可以统一如此代码:

<span class="cm-header-icon <%=dir %>  js_<%=item.tagname %>" >
   <% if(item.value) { %>
     <%=item.value %>
   <% } else { %>
     <i class="icon-<%=item.tagname %>"></i>
   <% } %>
 </span>

但是由于多了一个映射关系,我的代码便不好看了,并且业务逻辑还变得复杂了起来,于是带着这些考量再次找到了重构同事,重构同事也很明事理,马上答应改了:

<header class="cm-header" style="top: 50px;">
   <span class="fl cm-header-icon"><i class="icon-back"></i></span>
   <span class="fr cm-header-btn">确认</span>
   <span class="fr cm-header-icon"><i class="icon-home"></i></span>
   <span class="fr cm-header-icon"><i class="icon-list"></i></span>
   <h1 class="cm-page-title">
     页面标题</h1>
 </header>

不考虑h1中的样式的话,搞定上面的代码,对我们来说,真的是太简单了啊!!!

<header class="cm-header">
 <%
 var i = 0, len = 0, j = 0, keyagain = 0;
 var left = left;
 var right =  right.reverse();
 var item = null;
 var dir;
 var btnObj = null;
 %>
 <%for(keyagain=0; keyagain < 2; keyagain++) { %>
   <% 
     if(keyagain == 0) { dir = 'fl'; btnObj = left; } else { dir = 'fr'; btnObj = right; }
   %>
   <% for(i = 0, len = btnObj.length; i < len; i++) { %>
     <% item = btnObj[i]; %>
     <%if(typeof item.itemFn == 'function') { %>
       <%=item.itemFn() %>
     <%} else { %>
       <span class="cm-header-icon <%=dir %>  js_<%=item.tagname %>" >
         <% if(item.value) { %>
           <%=item.value %>
         <% } else { %>
           <i class="icon-<%=item.tagname %>"></i>
         <% } %>
       </span>
     <%} %>
   <%} %>
 <%} %>
 </header>

PS:从代码着色来看,js中用到的left与Right是关键字,这个得处理...

定制化需求

可以看到,一个循环,我们便可以轻易的生成左边和右边的按钮,但是马上问题来了,我们需要扩展怎么办,上面就会有以下问题: 

① tel标签默认是a标签,我们这里却是span标签

<a href="tel:56973144" class="cm-header-btn fr js_tel "><i class="icon-tel"></i></a>

② back按钮我们一般会做成a标签,用以解决javascript出错在Hybrid的假死问题

说白了,就是虽然标签按钮应该有统一的结构,但是需要保留定制化的能力 
这里定制化的工作交给了各个标签的itemFn这个函数,他返回一个字符串,并且具有一定规则,这里取一个代码片段:

handleSpecialParam: function (data) {
   var k, i, len, item;
   for (k in data) {
     if (_.isArray(data[k])) {
       for (i = 0, len = data[k].length; i < len; i++) {
         item = data[k][i];
         if (this['customtHandle_' + item.tagname]) {
           this['customtHandle_' + item.tagname](data[k][i], k);
         } //if
       } //for
     } //if
   } //for
 },
 
 _getDir: function (dir) {
   var kv = { left: 'fl', right: 'fr' };
   return kv[dir];
 },
 
 //处理back的按钮逻辑
 customtHandle_back: function (item, dir) {
   dir = this._getDir(dir);
   item.itemFn = function () {
     var str = '<a href="http://m.ctrip.com/html5/" class="cm-header-btn ' + dir + ' js_' + item.tagname + ' " >';
     if (item.value) {
       str += item.value + '</a>';
     } else {
       str += '<i class="icon-' + item.tagname + '"></i></a>';
     }
     return str;
   };
 },

当发现某个按钮不满足需求或者有定制化需求时,便想办法设置其itemFn即可,时候上这个代码可以直接写到初始化的json串去

花样百出的title

到title时,发现其表现便五花八门了,这个时候一般是根据不同的类型生成不同的HTML结构,框架给默认的几个选项,不支持便自己定制itemFn

<% item = center; %>
 <%if(typeof item.itemFn == 'function') { %>
   <%=item.itemFn() %>
 <%} else if(item.tagname=='title' ||  item.tagname=='subtitle') { %>
   <h1 class="cm-page-title js_<%=item.tagname %>" >
     <%if(typeof(item.value) == 'object' && item.title.value == 2) { %>
       <span class="cm-title-l"><%=item.value[0]%></span>
       <span class="cm-title-s"><%=item.value[1]%></span>
     <%} else { %>
       <%=item.value %>
     <%} %>
   </h1>
 <%} else if(item.tagname=='select'){ %>
   <h1 class="cm-page-select-title js_<%=item.tagname %>" >
     <%=item.value %>
   </h1>
 <%} else if(item.tagname=='tabs') { %>
   <h1 class="cm-page-tabs-title js_<%=item.tagname %>" >
     <%for(j = 0; j < item.data.items.length; j ++) { %>
       <span data-key="<%=item.data.items[j].id %>" class="<%if(item.data.index===j){ %>active<%} %>" ><%=item.data.items[j].name %></span>
     <% } %>
   </h1>
 <% } else{ %>
 
 <%} %>

事件绑定的实现

header组件本身继承至Abstract.View这个类,所以只要设置

this.events = {}

便能以事件代理的方式将事件绑定至根元素,而header的事件一般就是click事件: 

setEventsParam: function () {
   var item, data = this.datamodel.left.concat(this.datamodel.right).concat(this.datamodel.center);
 
   for (var i = 0, len = data.length; i < len; i++) {
     item = data[i];
     if (_.isFunction(item.callback)) {
       this.events['click .js_' + item.tagname] = $.proxy(item.callback, this.viewScope);
     }
   }
 },

这里有一个需要注意的点便是,事件绑定的钩子便是我们的tagname,这个是唯一的,我们会为每个标签动态生成“.js_tagname”的类,以方便事件绑定

老接口的兼容

之前便说了,该组件是一个老组件的翻新,于是各个业务团队已经使用了,比如原来是这样调用的:

this.header.set({
   title: '基本Header使用',
   subtitle: '中间副标题',
   back: true,
   backtext: '取消',
   tel: { number: 1111 },
   home: true,
   search: true,
   btn: { title: "登录", id: 'confirmBtn', classname: 'header_r' },
   events: {
     returnHandler: function () {
       console.log('back');
     },
     homeHandler: function (e) {
     }
   }
 });

而现在我们期望的调用方式是这样的:

this.header.set({
  left: [],
  center: {},
  right: [
    { tagname: 'home', callback: function () { } },
    { tagname: 'tagname', value: 'value', data: {}, itemFn: function(){}, callback: function () { } }
  ]
});

这个时候我们应该怎么做呢?当然是不破不立,先破后立,当然是要求业务团队改!!!然后被无情的喷了回来,于是做了接口兼容 
翻新老组件,接口兼容是必须的,如果不是底层机制发生颠覆,而颠覆可以带来颠覆性的成绩,接口还是不建议改! 
这里上面便是新接口的调用,下面是老接口的调用,效果如下:

 html5+css3之制作header实例与更新

到此这篇关于html5+css3之制作header实例与更新的文章就介绍到这了,更多相关header实例内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章,希望大家以后多多支持三水点靠木!

HTML / CSS 相关文章推荐
css3实现一个div设置多张背景图片及background-image属性实例演示
Aug 10 HTML / CSS
使用CSS3的appearance属性改变任何元素的浏览器默认风格
Dec 24 HTML / CSS
CSS3 @font-face属性使用指南
Dec 12 HTML / CSS
使用CSS3 制作一个material-design 风格登录界面实例
Dec 12 HTML / CSS
使用CSS3来代替JS实现交互
Aug 10 HTML / CSS
HTML5 和小程序实现拍照图片旋转、压缩和上传功能
Oct 08 HTML / CSS
只要五步 就可以用HTML5/CSS3快速制作便签贴特效(图)
Jun 04 HTML / CSS
利用HTML5中Geolocation获取地理位置调用Google Map API在Google Map上定位
Jan 23 HTML / CSS
详解html5 canvas 微信海报分享(个人爬坑)
Jan 12 HTML / CSS
前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)
Jul 12 HTML / CSS
HTML5 新增内容和 API详解
Nov 17 HTML / CSS
css中:last-child不生效的解决方法
Aug 05 HTML / CSS
CSS3中animation实现流光按钮效果
Dec 21 #HTML / CSS
css3中flex布局宽度不生效的解决
Dec 09 #HTML / CSS
html+css3实现的登录界面
Dec 09 #HTML / CSS
CSS3 实现的缩略图悬停效果
Dec 09 #HTML / CSS
CSS3 实现的火焰动画
Dec 07 #HTML / CSS
CSS3 实现的加载动画
Dec 07 #HTML / CSS
CSS3实现的渐变幻灯片效果
Dec 07 #HTML / CSS
You might like
php判断是否为json格式的方法
2014/03/04 PHP
ThinkPHP中RBAC类的四种用法分析
2014/11/24 PHP
php实现当前页面点击下载文件的简单方法
2016/09/22 PHP
JS效率个人经验谈(8-15更新),加入range技巧
2007/01/09 Javascript
50个比较实用jQuery代码段
2011/09/18 Javascript
JS解析json数据并将json字符串转化为数组的实现方法
2012/12/25 Javascript
parentElement,srcElement的使用小结
2014/01/13 Javascript
jquery跨域请求示例分享(jquery发送ajax请求)
2014/03/25 Javascript
Extjs根据条件设置表格某行背景色示例
2014/07/23 Javascript
JavaScript模块化开发之SeaJS
2015/12/13 Javascript
设置点击文本框或图片弹出日历控件的实现代码
2016/05/12 Javascript
javascript封装addLoadEvent实现页面同时加载执行多个函数的方法
2016/07/25 Javascript
JS实现的驼峰式和连字符式转换功能分析
2016/12/21 Javascript
javascript 面向对象function详解及实例代码
2017/02/28 Javascript
yarn的使用与升级Node.js的方法详解
2017/06/04 Javascript
使用vue.js在页面内组件监听scroll事件的方法
2018/09/11 Javascript
layui多图上传实现删除功能的例子
2019/09/23 Javascript
vuex存值与取值的实例
2019/11/06 Javascript
小程序实现录音上传功能
2019/11/22 Javascript
es6函数name属性功能与用法实例分析
2020/04/18 Javascript
selenium 反爬虫之跳过淘宝滑块验证功能的实现代码
2020/08/27 Javascript
JSON 入门教程基础篇 json入门学习笔记
2020/09/22 Javascript
python实现linux服务器批量修改密码并生成execl
2014/04/22 Python
Python实现GUI学生信息管理系统
2020/04/05 Python
python同步windows和linux文件
2019/08/29 Python
python3实现高效的端口扫描
2019/08/31 Python
Python要求O(n)复杂度求无序列表中第K的大元素实例
2020/04/02 Python
Python 多进程原理及实现
2020/12/21 Python
html5 CSS过度-webkit-transition使用介绍
2013/07/02 HTML / CSS
歌颂祖国的演讲稿
2014/05/04 职场文书
初中生考试作弊检讨书
2014/12/14 职场文书
整改通知书格式
2015/04/22 职场文书
2016年村干部公开承诺书(公开承诺事项)
2016/03/25 职场文书
工作总结之小学教师体育工作范文(3篇)
2019/10/07 职场文书
《和时间赛跑》读后感3篇
2019/12/16 职场文书
golang生成vcf通讯录格式文件详情
2022/03/25 Golang