移动端页面制作2

5:等分,居中等页面布局 

等分

在说等分之前,先抛出一个问题,如下面的emmet代码,footer部分的导航有些页面是三个,有些页面是四个,我们要求的是不论是三个还是四个甚至于5个,都平分宽度。

 

footer.footer>ul.nav-links>li*3
footer.footer>ul.nav-links>li*4

 

float

 

如果采用float技术的话,那估计只有在ul上添加额外的class来设置li的百分比宽度了。

 

.nav-links li{
    float:left;
    width:25%;
}
.percent-half li{
    width:50%;
}
.percent-third li{
    width:33.333%;
}
...

 

这个太蛋疼了,高上大的移动端怎么能用这么老套的东西呢,所以不考虑。

 

table

 

也许这个技术会被很多人忘记,不过用在移动端确实不错,关键是没有兼容问题的。主要设置父元素的display: table;table-layout: fixed;width: 100%;,然后设置子元素为display: table-cell;即可。

 

// table 等分
@mixin table-equal($children: li) {
    display: table;
    table-layout: fixed;
    width: 100%;
    $childrenEle: li div p a span strong;
    @if index($childrenEle, $children) {
        #{$children} {
            display: table-cell;
        }
    }
    @else {
        .#{$children} {
            display: table-cell;
        }
    }
}

.nav-links{
    @include table-equal;
}

 

这个mixin内部定义了一个$childrenEle元素选择器变量集合,如果传入的参数是其中的一个,那么直接使用元素选择器,否则就当class选择器使用,如默认的li解析后就是li{display: table-cell;},而如果传入children,则解析后就是.children{display: table-cell;}。下面的flex同样使用了该方法

 

注:在移动端display: table;同样也是个有利的神器,比起各种float什么的,这个技术还是可以单刀直入,直指问题核心

 

flex

 

flex技术是个好技术,不过最关键的还是其兼容问题,算起来它有三个版本,是有点乱哈哈。不过sandal的css3文件已经封装好了,所以只管调用,它会自动生成对应的兼容代码。

 

// flex 等分
@mixin flex-equal($children: li) {
    @extend %display-flex;
    $childrenEle: li div p a span strong;
    @if index($childrenEle, $children) {
        #{$children} {
            @include flex(1);
        }
    }
    @else {
        .#{$children} {
            @include flex(1);
        }
    }
}

.nav-links{
    @include flex-equal;
}

 

 

 

水平垂直居中

 

以简单的弹窗为例:

 

<div class="overlay">
    <section class="modal">
        <div class="modal-bd">
            <p>青,取之于蓝,而青于蓝;冰,水为之,而寒于水。故木受绳则直,金就砺则利,君子博学而日参省乎己,则知明而行无过矣。</p>
        </div>
    </section>      
</div>

 

也许看到这个结构,很多人都会纳闷,因为大家看到更多的应该是:.overlay+section.modal,即蒙版与弹出内容是兄弟元素,而不是嵌套关系。这里先卖个关子,到modal实例的时候,再分析。

 

flex

 

样式写在父元素上

 

// flex center
// display:flex
%display-flex,%flex-display {
    @include display-flex;
}

@mixin flex-center($direction: both) {
    @extend %display-flex;
    @if $direction == both {
        @include justify-content(center);
        @include align-items(center);
    }
    @else if $direction == x {
        @include justify-content(center);
    }
    @else if $direction == y {
        @include align-items(center);
    }
}

.overlay{
    z-index: 980;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0,0,0,.8);
    @include flex-center; // overlay调用
}
.modal{
    background-color: #fff;
    border-radius: 5px;
    margin: 0 10px;
    overflow: hidden;

    .modal-bd{
        padding: 15px;
    }
}

 

关于flex的单个元素水平垂直居中,新语法直接父元素为flex,子元素设置margin为auto即可,因为移动端还在使用旧语法,所以暂不使用margin这个方法,而是设置父元素的水平及垂直都居中

 

translate

 

样式写在要居中的元素上。原理就是先绝对定位,left/top为50%,然后通过translate偏移-50%回去(translate偏移的百分比为自身宽高的百分比),比从前的margin-top/left设置负值偏移回去高级点,因为设置margin必须得知道自身元素的宽高,然后设置具体的数字,而translate不用管自身的宽高,直接50%就可以搞定

 

// translate 50%
@mixin translate-center($direction: both) {
    position: absolute;
    @if $direction == both {
        top: 50%;
        left: 50%;
        @include translate(-50%, -50%);
    }
    @else if $direction == x {
        left: 50%;
        @include translate(-50%, 0);
    }
    @else if $direction == y {
        top: 50%;
        @include translate(0, -50%);
    }
}

.overlay{
    z-index: 980;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0,0,0,.8);
}
.modal{
    @include translate-center;  // modal调用
    background-color: #fff;
    border-radius: 5px;
    width:300px;
    overflow: hidden;

    .modal-bd{
        padding: 15px;
    }
}

 

上面的flex和translate两个mixin都可以实现单独的水平居中或垂直居中,传入相应的x或y即可。不论是flex还是translate水平垂直居中都有两个很好的优势即无需借助额外的空标签,也无需知道子元素的具体宽高,这比从前的一些方法强多了

 

 

 

左右两端对齐

 

对于左右两端对齐,以前使用最多的可能就是float,position了,现在同样可以采用flex来搞定

 

// justify
@mixin justify($extend: true) {
    @if $extend {
        @extend %justify;
    }
    @else {
        @extend %display-flex;
        @include justify-content(space-between);
    }
}
%justify {
    @include justify(false);
}

.justify{
    @include justify;
}

 

 

 

总结

 

如果你开始做移动端,那么flex和transform这两大属性有必要熟练运用,运用好了能解决很多问题。一般来说flex可以用来实现一些布局,再也不用动不动就float了;而transform中的rotate及translate则可以实现一些旋转及位移移动,旋转可以搞定图标的一些变化,而位移移动则可以实现居中,位移动画等。

具体页面代码如下:


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">

<meta name="robots" content="noindex">
<meta content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" name="viewport">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta content="telphone=no" name="format-detection">
<title>等分</title>
<style id="jsbin-css">
.clearfix:before,.clearfix:after{content:"";display:table;}
.clearfix:after{clear:both;}
html,body{height:100%;}
html{font-family:"Helvetica Neue",Helvetica,STHeiTi,Arial,sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;font-size:62.5%;}
body{margin:0;font-size:1.4rem;line-height:1.5;color:#333;background-color:#fff;}
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}
audio,canvas,progress,video{display:inline-block;vertical-align:baseline;}
audio:not([controls]){display:none;height:0;}
[hidden],template{display:none;}
a{background:transparent;text-decoration:none;-webkit-tap-highlight-color:transparent;color:#08c;}
a:active{outline:0;}
a:active{color:#069;}
abbr[title]{border-bottom:1px dotted;}
b,strong{font-weight:bold;}
dfn{font-style:italic;}
mark{background:#ff0;color:#000;}
small{font-size:80%;}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}
sup{top:-0.5em;}
sub{bottom:-0.25em;}
img{border:0;vertical-align:middle;}
svg:not(:root){overflow:hidden;}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}
pre{overflow:auto;white-space:pre;white-space:pre-wrap;word-wrap:break-word;}
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em;}
button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;}
button{overflow:visible;}
button,select{text-transform:none;}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}
button[disabled],html input[disabled]{cursor:default;}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
input{line-height:normal;}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}
input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto;}
input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;}
input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}
legend{border:0;padding:0;}
textarea{overflow:auto;resize:vertical;}
optgroup{font-weight:bold;}
table{border-collapse:collapse;border-spacing:0;}
td,th{padding:0;}
html,button,input,select,textarea{font-family:"Helvetica Neue",Helvetica,STHeiTi,Arial,sans-serif;}
h1,h2,h3,h4,h5,h6,p,figure,form,blockquote{margin:0;}
ul,ol,li,dl,dd{margin:0;padding:0;}
ul,ol{list-style:none outside none;}
h1,h2,h3{line-height:2;font-weight:normal;}
h1{font-size:1.8rem;}
h2{font-size:1.6rem;}
h3{font-size:1.4rem;}
input::-moz-placeholder,textarea::-moz-placeholder{color:#ccc;}
input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#ccc;}
input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#ccc;}
*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}

.demo{line-height:44px;margin-bottom:20px;text-align:center;background-color:#0078e7;color:#fff;}
.flex-equal,.flex-center,.justify{display:-webkit-box;display:-ms-flexbox;display:-webkit-flex;display:flex;}

.flex-equal li{-webkit-box-flex:1;-ms-flex:1;-webkit-flex:1;flex:1;}
.table-equal{display:table;table-layout:fixed;width:100%;}
.table-equal li{display:table-cell;}

.demo-center{border:1px solid #ccc;margin:20px;height:200px;}
.demo-center .children{background:#0078e7;color:#fff;width:150px;line-height:5;text-align:center;}
.flex-center{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center;}
.translate-center{position:relative;}
.translate-center .children{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);}
.justify{-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;padding:0 10px;background:#0078e7;color:#fff;line-height:32px;}

</style>
</head>
<body>
<h2>flex等分</h2>
<ul class="flex-equal demo">
<li>手机</li>
<li>联系人</li>
<li>信息</li>
<li>主屏</li>
</ul>

<ul class="flex-equal demo">
<li>手机</li>
<li>联系人</li>
<li>信息</li>
</ul>
<h2>table等分</h2>
<ul class="table-equal demo">
<li>手机</li>
<li>联系人</li>
<li>信息</li>
<li>主屏</li>
</ul>
<ul class="table-equal demo">
<li>手机</li>
<li>联系人</li>
<li>信息</li>
</ul>
<h2>flex居中</h2>
<div class="flex-center demo-center">
<div class="children">子元素水平垂直居中</div>
</div>
<h2>translate居中</h2>
<div class="translate-center demo-center">
<div class="children">子元素水平垂直居中</div>
</div>
<h2>两端对齐</h2>
<div class="justify"><h2>左边对齐</h2><span>右边对齐</span></div>


</body>
</html>

6:切入切出动画

transition动画

先定义要运动的元素在视觉范围之外,以左方向进入为例,同时定义transition:

.demo{
    @include translate3D(-2000px, 0, 0);
    -webkit-transition: -webkit-transform 0.3s ease-in-out;
    transition: transform 0.3s ease-in-out;
}

从进入视觉范围来说,不论方向从上下还是左右,最终都归于0,所以进入的时候添加class translate-in,而离开的时候去掉translate-in即可

.translate-in{
    @include translate3D(0, 0, 0);
}

animation动画

先定义要运动的元素在视觉范围之外,同样以左方向为例:

.demo{
    @include translate3D(-2000px, 0, 0);
}

再定义keyframes:

// 从左向右方向进入动画
@mixin left-in($startX: -2000px, $endX: 0) {
    @include keyframes(left-in) {
        0% {
            @include translate3d($startX, 0, 0);
        }
        100% {
            @include translate3d($endX, 0, 0);
        }
    }
    .left-in {
        @include animation-name(left-in);
        @extend %animated;
    }
}

// 从右向左方向消失动画
@mixin left-out($startX: 0, $endX: -2000px) {
    @include keyframes(left-out) {
        0% {
            @include translate3d($startX, 0, 0);
        }
        100% {
            @include translate3d($endX, 0, 0);
        }
    }
    .left-out {
        @include animation-name(left-out);
        @extend %animated;
    }
}

调用上面定义的keyframes,元素进入视觉范围添加class left-in,元素离开视觉范围则替换left-inleft-out,动画结束后调用animationend事件,删除left-out

@include left-in;
@include left-out;

解析后的css为:

.left-in, .left-out {
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}

@-webkit-keyframes left-in {
  0% {
    -webkit-transform: translate3d(-2000px, 0, 0);
  }

  100% {
    -webkit-transform: translate3d(0, 0, 0);
  }
}
@keyframes left-in {
  0% {
    transform: translate3d(-2000px, 0, 0);
  }

  100% {
    transform: translate3d(0, 0, 0);
  }
}
.left-in {
  -webkit-animation-name: left-in;
  animation-name: left-in;
}

@-webkit-keyframes left-out {
  0% {
    -webkit-transform: translate3d(0, 0, 0);
  }

  100% {
    -webkit-transform: translate3d(-2000px, 0, 0);
  }
}
@keyframes left-out {
  0% {
    transform: translate3d(0, 0, 0);
  }

  100% {
    transform: translate3d(-2000px, 0, 0);
  }
}
.left-out {
  -webkit-animation-name: left-out;
  animation-name: left-out;
}

总结

transition动画与animation动画的区别在于:

1、transition动画只能定义开始和结束位置,中间无法定义;而keyframes则可以定义n帧作为中间的过渡帧。

2、对于切入切出动画来说,transition动画我们只需添加删除一个class即可完成,而animation动画则需要切换两个class,再在最后删除class,比较复杂。

3、如果你的动画不需要定制中间帧,那直接使用transition动画即可,切换一个class就可以了,运动结束时候可以js调用transitionend函数,而如果需要定制中间帧,那么还是animation,当然animation的事件有三个animationstart,animationiteration,animationend

 

7:页面图标

背景图片

首先我们会选择sprite形式,把所有的图标都放在一个大图中,然后考虑到retina屏,所以我们的图标应该设计为实际大小的2倍,然后设置background-size为实际大小。以下面的msg icon为例:

icon msg

图中的每个icon大小为24px,实际应用时,我们是以12px来使用的:

%icon-msg{
    display: inline-block;
    vertical-align: -2px;
    background:url(../images/icon-msg.png) no-repeat;
    background-size:26px 26px; // 整个sprite图片大小的一半,注意不要采用50%,百分比是按元素大小来计算的,而不是背景图片大小
}
.icon-info{
    @extend %icon-msg;
    background-position: -14px 0;
    width: 12px;
    height: 12px;
}
.icon-alert{
    @extend %icon-msg;
    background-position: 0 -14px;
    width: 12px;
    height: 12px;
}
...

当然有时候图标比较少,我们为了减少请求,也可以直接把图片转成base64格式写在css中,这里推荐一个在线转的工具:Encode Data URL

直接绘制

凭借优秀的css3,我们可以应用其中一些属性绘制一些简单的图标,如箭头等,这里我们以绘制checkbox两种状态为例:

icon checkbox

html:

<i class="icon-checkbox active"></i>    
<i class="icon-checkbox"></i>

scss:

$primary:                        #0078e7 !default;

.icon-checkbox{
    width: 16px;
    height: 16px;
    display: inline-block;
    vertical-align: middle;
    border: 1px solid #ccc;
    background-color: #fff;
    line-height: 1;
    text-align: center;
    margin-right: 5px;

    &.active{
        border-color: $primary;

        &::after{
            content: "";
            width: 8px;
            height: 3px;
            border-bottom: 2px solid $primary;
            border-left: 2px solid $primary;
            display: block;
            margin-top: 3px;
            margin-left: 2px;
            @include rotate(-45deg);
        }   
    }
}

active状态,通过after生成一个长方形,然后设置其border-bottom和border-left,再通过css3的rotate旋转45即可,那个勾就是两条边框。

@font-face

sandal的字体图标为例,如果你觉得这些图标不适合你,你可以自己在icomoon中挑选合适的。

icons

sandal中字体图标使用方法:

1、下载sandal放在d盘目录下,在你的scss文件中导入sandal的base文件(如果不需要生成样式,则导入function文件即可)及font-face文件

@import "d:/sandal/base";
@import "d:/sandal/ext/font-face/font-face";

2、根据自己需要覆盖font-face文件夹中的变量,注意变量应该在导入font-face之前,可以覆盖的变量如下:

$fontFamily:            icomoon !default;
$fontFilePath:          "../fonts/icomoon" !default;
$fontClassPrefix:       if !default; // icon-font
$fontClassAllSwitch:    true !default;
$fontClassOutput:       () !default;
$fontPseudo:            true !default; // 是否采用伪元素(before)生成图标

下面我们改变下class的前缀,然后输出所有的字体class

@import "d:/sandal/base";
$fontClassPrefix:      icon-font;
@import "d:/sandal/ext/font-face/font-face";

3、把font-face目录下的fonts文件夹拷贝进解析后的css文件夹同目录下,如css,js,fonts,images同目录

根据上面的配置,贴出下面的html和解析后的css代码:

html:

<i class="icon-font-wifi"></i>
<i class="icon-font-comment"></i>
<i class="icon-font-user"></i>
<i class="icon-font-map"></i>
...

css:

.icon-font-wifi::before, .icon-font-comment::before, .icon-font-user::before, .icon-font-map::before,...{
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}
@font-face {
  font-family: icomoon;
  font-weight: normal;
  font-style: normal;
  src: url("../fonts/icomoon.eot");
  src: url("../fonts/icomoon.eot?#iefix") format("eot"), url("../fonts/icomoon.svg#icomoon") format("svg"), url("../fonts/icomoon.woff") format("woff"), url("../fonts/icomoon.ttf") format("truetype");
}
.icon-font-wifi::before, .icon-font-comment::before, .icon-font-user::before, .icon-font-map::before,...{
  display: inline-block;
  vertical-align: -2px;
  font-family: icomoon;
  font-size: 1.6rem;
  line-height: 1;
  speak: none;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.icon-font-wifi::before {
  content: "\e62f";
}
.icon-font-comment::before {
  content: "\e601";
}
.icon-font-user::before {
  content: "\e632";
}
.icon-font-map::before {
  content: "\e61b";
}
...

一般我是直接绘制和字体图标都用,简单的直接绘制就好,所以为了区别两者的class,直接绘制的我使用icon为前缀,而字体图标使用if(icon-font缩写)为前缀,至于为什么要区别这两者的class呢,因为说不定你就得使用css3的属性选择器,比如i[class^="icon-"],i[class^="if-"]方便选择控制样式。

关于变量$fontPseudo这里单独说明下,因为使用字体图标有两种方法,一种是把对应的字符编码直接写在html中,然后设置字体即可,另一种是html为空白标签,通过before或after的content来设置其内容,再设置字体。如果$fontPseudo为false,则解析的css为:

@font-face {
  font-family: icomoon;
  font-weight: normal;
  font-style: normal;
  src: url("../fonts/icomoon.eot");
  src: url("../fonts/icomoon.eot?#iefix") format("eot"), url("../fonts/icomoon.svg#icomoon") format("svg"), url("../fonts/icomoon.woff") format("woff"), url("../fonts/icomoon.ttf") format("truetype");
}
.icon-font-wifi, .icon-font-comment, .icon-font-user, .icon-font-map,...{
  display: inline-block;
  vertical-align: -2px;
  font-family: icomoon;
  font-size: 1.6rem;
  line-height: 1;
  speak: none;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

注:个人只所以采用伪元素及把样式写在伪元素里面,是因为有些时候可能想偷懒,一些图标不直接采用一个空白标签去定义,而是直接写在某个元素的before或after伪元素上,那个时候只需要采用sass的extend对应图标的伪元素即可。

 

8:页面内滚动

原生滚动

原生滚动的属性为:-webkit-overflow-scrolling:touch;,如果是走高富帅的苹果路线,是没问题的,谁让这是人家亲生的呢;如果是安卓的话,我真不知道是支持还是不支持,说不支持吧好像有点缓动效果,说支持吧好像把这条属性砍掉也一样,感兴趣的可以自己测试下(添加或删除这个属性对比下)

iscroll模拟

既然原生的安卓上不太靠谱,那就有必要用js来解决了,因为本人不擅长js,所以直接上iscroll,现在iscroll也已经到第五版本了,iscroll的github上有很全的例子,虽然比较简单,不过入门还是不错的。这里我也搞了两个demo,在demo之前,有必要先说明下使用iscroll应该注意的一些事项:

html结构方面

iscroll要求至少两层结构,wrap是一个固定的容器,overflow为hidden,而scroll为滚动的内容,如果开启translate(默认开启),则使用translate来实现偏移滚动,如果没有则使用left/top来实现偏移滚动。如果wrap下面有多个直接子元素,即scroll有其他兄弟元素则只对第一个子元素滚动,其他的自动忽略。(wrap和scroll的class是随便的,主要就是得有两层结构)

<div class="wrap">
    <div class="scroll">
        ...
    </div>
</div>

如图:

iscoll img

css样式方面

除了要求wrap有宽高及overflow为hidden,还得对scroll元素设置position为relative或absolute,这样才能设置偏移。

js方面

最简单的就是直接new一个IScroll对象即可,其他配置可直接参考官网的说明:

window.addEventListener('load',function(){ var myScroll = new IScroll('.wrap');});
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);

献上两个简单的demo:

由于本人的js水平实在有限,关于这个我也分析不出来什么来龙去脉,摘录几篇文章以供想学习的参考下吧。下面的资料都是iscroll 4的。(虽然官网已经介绍的足够好了,但iscroll的坑还是很多的,多看看总不赖)

参考资料:

 

9:图片滚动

滚动原理

既然说到滚动,那跟我们上篇说到的iscroll多少有点关系吧。下面对swipe的滚动原理和iscroll的滚动原理简单分析下,以相同的结构为例:

<div class="wrap">
    <ul class="scroll">
        <li></li>
        <li></li>
        ...
    </ul>
</div>

相同的是都需要一个可以设置overflow为hidden的容器wrap。不同的是iscroll是对scroll元素进行滚动,通过设置其translate值或left/top值来实现滚动;而swipe是对li进行滚动,每个li有三种状态——prev,current和next,prev状态的时候向左偏移视窗的宽度,current状态正好在视觉范围内,next状态向右偏移视窗的宽度。

实战

同样其github已经有了很好的api使用说明,这里简单说下其参数配置:

window.mySwipe = new Swipe(document.getElementById('slider'), {
  startSlide: 2, //起始图片切换的索引位置,默认为0
  speed: 400, //动画执行时间,单位毫秒,默认为300
  auto: 3000, //设置自动切换时间,单位毫秒,无默认值
  continuous: true, //无限循环的图片切换效果,默认为true
  disableScroll: false, //阻止由于触摸而滚动屏幕,默认为false
  stopPropagation: false, //阻止事件冒泡,默认为false
  callback: function(index, elem) {}, //回调函数,滚动时调用
  transitionEnd: function(index, elem) {} //回调函数,滚动的transition动画结束后调用。
});

除此之外,swipe还提供了几个比较实用的api,如下:

  •  prev()上一页
  •  next()下一页
  •  getPos()获取当前页的索引
  •  getNumSlides()获取所有项的个数
  •  slide(index, duration)滑动方法

demo

1、简单demo

css代码如下,图片大小最大为100%宽度:

.wrap{
  overflow: hidden;
  visibility: hidden;
  position: relative;
  width: 100%;
  height: 150px;
}
.wrap .inline-float{
  overflow: hidden;
  position: relative;
}
.wrap .inline-float li {
  float: left;
  width: 100%;
  position: relative;
  text-align: center;
}
.wrap .inline-float img {
  max-width: 100%;
}

2、多张图片一组demo

即每个li中多放几张图片,然后控制图片的宽度,以防止挤掉

.wrap .inline-float img {
  max-width: 30%;
  margin-left: 10px;
}

3、全屏图片

这个关键在于把图片设置背景图片,然后采用background-size来调整,这里采用的是100%,即li的宽高大小(demo中的四张图片均不同大小,然后缩放统一呈现出来的大小就是li的大小),可以根据自己的需要设置为cover或contain什么的

.wrap .inline-float li {
  float: left;
  width: 100%;
  height: 150px;
  position: relative;
  text-align: center;
  background-repeat:no-repeat;
  background-size: 100% 100%;
  background-color:#f5f5f5;
}

注:上面的几个demo好像是直接调用Swipe函数,而不是new一个对象,js修改为如下(jsbin中一修改链接数字就变了):

window.addEventListener('DOMContentLoaded', function(){ 
  var $slide = document.getElementById('swipeSlide');
  var mySwipe = new Swipe($slide,{
    auto: 1000
  });
});

4、添加子弹导航

js部分,设置callback函数,根据当前的位置为子弹导航添加激活状态

window.addEventListener('DOMContentLoaded', function(){ 
  var $slide = document.getElementById('swipeSlide'),
      aBullet = $slide.querySelectorAll('.icon-bullet'),
      len = aBullet.length;

  var mySwipe = new Swipe($slide,{
    auto: 3000,
    callback: function(i){
      while(len--) {
        aBullet[len].classList.remove('active');
      }
      aBullet[i].classList.add('active');
    }
  });
});

10:侧边栏导航

设计结构如下:

<header class="header"></header>

<div class="wrap-page"> <section class="page"></section> ... </div>

<footer class="footer"></footer>

<section class="panel"></section>

第一种实现方案:

先将panel通过translate偏移负的本身宽度,离开可视区域,然后通过切换active这个class来实现无偏移。当然除此之外,top和bottom的0实现了100%高度,z-index要保证大于header和footer的层级。

$panelWidth:      120px !default;
.panel{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 980;
    width: $panelWidth;
    background-color: #333;
    @include translate3d(-$panelWidth, 0, 0);
    @extend %transition-transform;
}
.panel.active{
    @include translate3d(0, 0, 0);
}

同样我们也可以通过给body添加删除class如panel-active来控制panel的位置。

第二种实现方案

在demo1的基础上根据第二种方案顺便处理下了当panel出现时,内容禁止滚动

因为需要实现整块内容栏(包括header和footer部分)偏移panel的宽度,所以第一反应是应该有个div把整块内容栏包裹下,如下:

<div class="wrap-container">
    <header class="header"></header>
    <div class="wrap-page">
        <section class="page"></section>
        ...
    </div>
    <footer class="footer"></footer>
</div>
<section class="panel"></section>

多了一层结构,看起来有点不爽,不过使用起来还是很爽的。首先panel偏移负的本身宽度,接下来通过控制wrap-container的class来实现内容栏偏移panel的宽度

.panel{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: $zIndexOverlay;
    width: $panelWidth;
    background-color: #333;
    @include translate3d(-$panelWidth, 0, 0);
}
.wrap-container{
    @extend %transition-transform;  
}
.wrap-container.panel-active{
    @include translate3d($panelWidth, 0, 0);
}

既然这里需要一个父元素来实现一个偏移,为什么body不可以呢?所以果断干掉wrap-container,恢复最初的结构

.panel{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: $zIndexOverlay;
    width: $panelWidth;
    background-color: #333;
    @include translate3d(-$panelWidth, 0, 0);
}
body.has-panel{
    @extend %transition-transform;  
}
body.panel-active{
    @include translate3d($panelWidth, 0, 0);
}

总结

一般来说使用比较多的还是第二种方案,因为第一种直接把左边的那个点击图标遮盖住了。而panel实际使用的时候还是挺不太好办的,因为左边的第一个icon一般都是放首页,返回什么的,当然适用不适用还是根据各自业务需要走

 

11:弹框

设计结构如下:

<header class="header"></header>
<div class="wrap-page">
    <section class="page"></section>
    ...
</div>
<footer class="footer"></footer>
<div class="overlay">
    <section class="modal">
        <div class="modal-hd"></div>
        <div class="modal-bd"></div>
        <div class="modal-ft"></div>
    </section>
</div>

前面的第n篇文章提过这个overlay遮罩层的问题,现在这里说明下为什么这么设计。

一般来说看到的overlay都与modal是兄弟元素,而不是嵌套关系。本来我也是这么设计的,这就是习惯。后来由于modal居中的问题,重新审视了下这个问题:

为什么遮罩层的overlay与弹窗内容是兄弟元素?

说实话真想不出什么理由,非得搞成兄弟元素。后来突然意识到以前的遮罩层如果不采用半透明图片的话,就得使用opacity(ie6-8不支持,通过滤镜模拟),而这个属性会对整个子元素都起作用,而且还没办法通过子元素覆写这个值。这是我能想到的一条最佳理由,如果还有其他理由欢迎交流。

对于高上大的移动端来说,都是rgba时代了,所以opacity回家吃饭先。既然这个对子元素的影响已经不是问题,那么嵌套关系就可以成立,而且嵌套还有一个非常好的理由,水平垂直居中,flex小指一动即可。而兄弟元素的水平垂直居中就得设置modal的top和left的值为50%,然后再设置translate的x和y方向都-50%

所以果断抛弃兄弟元素设计换成嵌套关系。

因为overlay采用了flex布局来控制子元素居中,所以不难呢过采用display为none/block来显示隐藏遮罩层overlay,而是通过z-index的层级来控制,而modal部分通过添加删除modal-in这个class来控制显示隐藏

scss代码如下:

.overlay{
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: -1;
    background-color: rgba(0,0,0,.8);
    @include flex-center; // flex水平垂直居中
}
.overlay.active {
  z-index: 980;
}

$modalBarHeight: 40px !default;
$modalBdPadding: 15px;

.modal{
    background-color: #fff;
    border-radius: 5px;
    margin: 0 10px;
    overflow: hidden;
    opacity: 0;
    @include transform(translate3d(0,0,0) scale(0.815));
    @extend %all-transition;
    @include transition-property(transform, opacity);

    &.modal-in{
        opacity: 1;
        @include transform(translate3d(0,0,0) scale(1));
    }

    .modal-hd{
        text-align: center;
        line-height: $modalBarHeight;
        background-color: $primary;
        color: #fff;
    }
    .modal-bd{
        padding: $modalBdPadding;
    }
    .modal-ft{
        border-top: 1px solid $gray;
        @extend %display-flex;
        .btn-modal{
            @include flex(1);
            background-color: #fefefe;
            text-align: center;
            line-height: $modalBarHeight;
            color: $primary;
            &:first-child{
                border-right: 1px solid $gray;
            }
            &:last-child{
                border-right: none;
            }
            &:hover,&:active{
                background-color: #d9d9d9;
            }
        }
    }
}


<script>
$(function(){
var $overlay = $('#overlay');

function modalHidden($ele) {
$ele.removeClass('modal-in');
$ele.one('transitionend',function(){
$ele.css({"display": "none"});
$overlay.removeClass('active');
});
}

$('.modal-link').tap(function(){
var $that = $(this);
$overlay.addClass('active');
var $whichModal = $('.'+$(this).data('modal'));
$whichModal.animate({"display":"block"},100,function(){
$(this).addClass('modal-in');
});

$('.btn-modal').tap(function(e){
modalHidden($whichModal);
e.stopPropagation();
});
$overlay.tap(function(e){
if(e.target.classList.contains('overlay')){
modalHidden($whichModal);
}
});
});
});
</script>

 

 

posted @ 2014-12-03 11:28  axl234  阅读(537)  评论(0编辑  收藏  举报