[TOC]

flex布局

虽然用了很久的flex,但是关于这东西的一些属性确实一知半解,只是知道有这种效果,但是不知道为啥会出现这种情况,所以找了一些资料总结.
Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。其实说白了就是他会根据自己的宽度去自动调整里面子元素的宽度,即使里面子元素已经设置了宽度;从而达到一种类似于自适应的感觉(虽然实际上并不是自适应)

flex的几个常用属性

布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。不管是position或者float都会造成本身脱离文档流,直接导致父元素没高度,所以还需要额外的代码进行修正

flex轴线和正负自由空间

采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。说白了就是在谁身上写了display:flex谁就是flex容器

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。(说简单点就是默认X轴为主轴,Y为交叉轴)

flex-directio: row(默认值):主轴为水平方向,起点在左端。

     row-reverse:主轴为水平方向,起点在右端。

     column:主轴为垂直方向,起点在上沿。

     column-reverse:主轴为垂直方向,起点在下沿
这个属性不写就是默认X轴线为主轴,如果设定column,那么就是竖着排,其他两个用的不多,这两个东西会决定positive and negative free space(正负自由空间)的计算方式!!!∑(゚Д゚ノ)ノ...这什么鬼?说的这么邪乎,其实就是当主轴为row,里面的子元素的宽加起来不超过父元素的宽,也就是有剩的,那么这部分剩下的空间就是叫做positive free space

反之就是negative free space;也就是超出的那部分宽度;

当主轴为Y轴,那么计算正负自由空间就是元素的高了;这个所谓的正负自由空间也会影响到下面子元素的两个缩放属性flex-grow和flex-shrink

flex-grow

flex-grow 属性指定了flex增长值, 这决定了当positive free space分配时,flex子元素相对于flex容器中的其余flex子元素的增长程度.举个生活场景就是老爹给自己几个儿子留了一笔遗产,这几个儿子该如何根据比例去分配;

假定下面这个外层包裹为600px;a,b均为100,hello为150,那么可分配空间=600-100-100-150=250px;

现在加上样式

a{
    flex-grow:1
}
b{
    flex-grow:1
}
b{
    flex-grow:2
}

现在按照1:1:2的比例去分配250,就得到了每份62.5px,那么就会变成(图有些不准)

当flex-directio:column 也就是主轴设置Y轴之后,那么正自由空间就会以元素的高为基准

flex-sharink

flex-shrink决定了flex-item的缩放值,跟他相关的就是上面提到的另一个属性,负自由空间,即里面的子元素的宽之和加起来大于父元素的宽,那么超出去的部分就叫做negative free space(负自由空间);
负自由空间和正自由空间相似,只不过变成了负值而已,假定父元素600px,底下3个子元素,100,100,500,

负自由空间=600-(100+100+500)=-100;
现在3个子元素的flex-shrink为1,1,2,也就说按照1:1:2的比例分配-100px;
应该得到实际计算宽度:

第一个:(100-100*(2/2+1+2))=60,
第二个(100-100*(1/2+1+2))=80px,
第三个(500-100*(2/2+1+2))=460px;
最后:60+80+460=600px;

骚年,你以为上面的是正确的吗?如果你信了那就是图样图森破ヾ(◍°∇°◍)ノ゙...一开始我也是这样计算的,但是跟浏览器的计算相差了很远,折腾了好久才找到正确的计算方式;

他的计算方式还有些复杂:
先求负空间:
600-(100+100+500)=-100
然后自身flex-shrink乘以自身宽度得到消化值:
`a:100*2=200;
b:100*1=100;
c:500*2=1000;`
再求消化值之和:
200+100+1000=1300;
第三步:计算自身腾出宽度
a:(200/1300)*100=15.38; b:(100/1300)*1=7.69; c:(1000/1300)*100=76.92;...(▼ヘ▼#)
第四步:计算最后宽度:
a:100-15.38=84.62; b:100-7.69=92.31; c:500-76.92=423.08

**所以可以得到一些个结论:
1, 在flex可能会去改变容器里面元素原本设置的绝对宽度,即便你写死了宽度,尤其是在设置了flex-grow和flex-sharink的情况下,他会根据这些比例值去动态计算子元素的宽度
2, 有正自由空间时,flex-grow生效,shrink不生效
3, 有负自由空间时,flex-shrink生效,grow不生效
4, flex-basis在一定程度上等于width;
**

flex-basis

和width一样,他的默认值为auto,把上面几个例子换成width也是一样的。当然工作中最好用flex-basis,更符合规范。

所以在使用flex时候有时候得到了意料之外的宽度时候,明明我写了宽度的啊?ヽ( ̄▽ ̄)ノ.也就知道为啥会得到这个值了...

单个元素靠右

方法1

flex: 1;
text-align: right;

方法二

margin-left:auto;

swiper滑动插件

swiper滑动插件,一款专为手机滑动设计的插件,挺不错的;在做起点官网品牌营销的时候遇到3个地方需要使用,也是相当具有代表性的使用场景(注意这里swiper3和swiper4版本的不同,这里使用的3,4的参数差不多类似,可以看文档);

第一个场景:

在一个页面下可能存在多个swiper区域,所以为了保证唯一性,在实例化的时候传入id是一个机智的选择

这种场景难点在于滑动下面的图片,上面的按钮要跟着切换class,同时,点击上面的按钮下面的图片要跟着切换
做法解析:在滑动结束之后获取当期元素序号,在根据序号匹配上面的按钮;
在swiper实例化的时候可以传入一个对象作为参数,其中有一个回调函数参数onSlideChangeEnd(还有其他的函数,都是一些事件触发),接受当前swiper对象为参数,在滑动结束之后触发,还有一个属性值activeIndex,为当前激活元素的序号,使用这个序号就可以和上面的切换按钮对应起来了;

结构以及代码部分:

var skillSwiper = new Swiper('.skill-model-swiper', { //实例化滑动对象
    pagination : '.swiper-pagination-skill', //分页指示器
    onSlideChangeEnd: function(swiper) { //滑动结束获取当前激活序号,swiper为当前的swiper对象
    var curidx = swiper.activeIndex; //activeIndex关键属性,当前激活元素的序号
    $('.skill-lenli-btn button').eq(curidx).addClass('skill-lenli-btn-act').parent().siblings().find('button').removeClass('skill-lenli-btn-act');
    }
});

第二个场景

这种场景难点在于在一个大div下面嵌套了多个swiper区域,切伴随tab标签页切换效果,跟随上面的切换按钮切换,其实做出来还是比较简单,但是会有一个意料之外的情况,Σ(っ°Д°;)っ除了第一个swiper之外的剩下的swiper都会存在滑动卡顿的情况
解决办法:
在实例化每一个swiper的时候在加上
observer: true, //修改swiper自己或子元素时,自动初始化swiper
observeParents: true, //修改swiper的父元素时,自动初始化swiper
这2个附加参数就可以解决

结构以及代码

 $('.ds-sw>div').click(function(event) {
     var i = $(this).index();
     $(this).addClass('ds-sw-act').siblings().removeClass('ds-sw-act');
     $('.ds-person-item').eq(i).addClass('ds-person-item-act').siblings().removeClass('ds-person-item-act')
});

var dsItemSwiperA = new Swiper('.ds-person-swiper-a', {
    observer: true, //修改swiper自己或子元素时,自动初始化swiper
    observeParents: true, //修改swiper的父元素时,自动初始化swiper
    pagination : '.dsItemSwiperASw'
})//下面每一个swiper都一样的写法,再来个B,C,D

第三个场景

这种场景是一种不规则应用场景,需要在一个元素上漏出上一个和下一个,其实也很简单,只需要记得给每一个swiper-slider给上固定宽度就好了,然后在实例化就好了
结构

var dnrSwiper=new Swiper('.swiper-container-dinner',{
    slidesPerView: 'auto',
    centeredSlides: true,
    spaceBetween: 10,
    autoplay : 3000,
})

一些其他

里面内容过多或者用了自定义的分页器很有可能出现滑动问题,建议延迟300ms初始化
注意,swiper3和swiper3是有些不一样,swiper3和4都没有鼠标移入停止自动播放和离开继续播放的选项,只能手动写入,代码后面补上


墨韵
109 声望0 粉丝