在vue.js之类的mvvm的框架大行其道的当下,开辟中最罕见的场景就是经由过程转变数据来展现页面或模块的差别状况,当我们把mvvm玩的不亦乐乎的时刻,偶然也会停下了想一想:在某些项目中不能用vuejs之类的框架时,我们怎样经由过程转变数据来修正页面或许模块的状况呢。
嗯。说到状况,就想到了状况形式
状况形式:
在许多状况下,一个对象的行动取决于一个或多个动态变化的状况属性,如许的对象叫做有状况的(stateful)对象,对象的状况是从事前定义好的一系列状况值中掏出的。当状况对象与外部事宜发生互动时,其内部状况就会转变,从而使得体系的行动也随之发生变化。
状况形式重要处理的题目:
当掌握对象状况的前提表达式过于庞杂时的状况,把状况的推断逻辑转移到示意差别的状况的一系列类或许要领当中,能够把庞杂的逻辑推断简朴化
下面我们看看状况形式在web前端开辟中得一些罕见运用场景
tab标签的切换
tab标签切换是web开辟中最罕见的交互了,交互递次大抵是如许子:
1.平常会有2-3个标签,对应了2-3个tab内容块。个中一个默许tab会是active状况
2.点击其他tab标签,则:去掉active的tab标签款式,隐蔽对应的区块,给点击的tab增加active款式,显现这个tab对应的区块。
哎。。想一想须要挨个tab找对应的元素然后去remove掉class再add一个class。。。好烦琐。。能不能少写点js,简简朴单的完成tab切换呢。。。
运用状况形式处理tab切换示例以下:
html 代码
<div class="tab-box-wrap" data-tab-index="tab01" id="tab_box_wrap">
<ul>
<li data-tab="tab01">我是tab01</li>
<li data-tab="tab02">我是tab02</li>
<li data-tab="tab03">我是tab03</li>
</ul>
<div tab-box="tab01">
我是tab01 的内容
</div>
<div tab-box="tab01">
我是tab02的内容
</div>
<div tab-box="tab01">
我是tab03的内容
</div>
</div>
css代码
.tab-box-wrap {
height: 500px;
width: 900px;
margin: 0 auto;
}
.tab-list {
list-style: none;;
height: 32px;
border-bottom: 1px solid #6856f9;
position: relative;
padding: 0 50px;
margin: 0;
}
.tab-list li {
float: left;
height: 20px;
padding: 5px;
border: 1px solid #6856f9;
line-height: 20px;
font-size: 14px;
margin-right: -1px;
border-bottom: 1px solid transparent;
background: #fff;
cursor: pointer;
}
[data-tab-index="tab01"] [tab-index="tab01"] {
border-bottom: 2px solid #fff;
}
[data-tab-index="tab02"] [tab-index="tab02"] {
border-bottom: 2px solid #fff;
}
[data-tab-index="tab03"] [tab-index="tab03"] {
border-bottom: 2px solid #fff;
}
.tab-box {
padding: 20px;
height: 500px;
border: 1px solid #6856f9;
border-top: 0 none;
display: none;
}
[data-tab-index="tab01"] [tab-box="tab01"] {
display: block;
}
[data-tab-index="tab02"] [tab-box="tab02"] {
display: block;
}
[data-tab-index="tab03"] [tab-box="tab03"] {
display: block;
}
js代码以下
var tab_box_wrap = document.getElementById("tab_box_wrap");
tab_box_wrap.addEventListener("click",function(event){
var ele = event.target;
var tab = ele.getAttribute("tab-index");
if(tab){
var t = tab_box_wrap.getAttribute("data-tab-index");
if(t!==tab){
tab_box_wrap.setAttribute("data-tab-index",tab);
}
}
},false)
点击检察demo
代码很少,重要的代码其实在css内里, 我们用属性选择器[data-tab-index=”xxx”]来掌握页面的tab切换,js里只须要猎取对应的tab点击然后变动属性的值就好了。
瑕玷:css有点多,须要罗列每一个tab的状况,css属性选择器ie8+才支撑,
长处:js代码很少,逻辑掌握全在css里,有什么修改 (比方增加tab) 我们只须要改css就好了。一听只改css,是否是很开森^_^
下面我们看一个庞杂的例子
重如果物流概况状况的动画,这个动画会依据对应的运单号的状况来展现对应的动画节点。那末我们一共有10个运单状况,以下:
{statusDesc: "揽收", status: "PICKEDUP",}
{statusDesc: "运输中", status: "SHIPPING"},
{statusDesc: "脱离辟件国", status: "DEPART_FROM_ORIGINAL_COUNTRY"},
{statusDesc: "抵达目标国", status: "ARRIVED_AT_DEST_COUNTRY"},
{statusDesc: "妥投", status: "SIGNIN"}
{statusDesc: "待揽收", status: "WAIT4PICKUP"},
{statusDesc: "抵达待取", status: "WAIT4SIGNIN"}
{statusDesc: "妥投失利", status: "SIGNIN_EXC"},
{statusDesc: "交航失利", status: "DEPART_FROM_ORIGINAL_COUNTRY_EXC"},
{statusDesc: "清关失利", status: "ARRIVED_AT_DEST_COUNTRY_EXC"}
无状况的时刻动画状况以下:
妥投状况动画截图以下:
每一个一般节点中心都邑有一个非常节点,【抵达目标国】和【妥投】之间会有一个【抵达待取】状况,
【揽收】和【脱离辟件国】之间会有一个【运输中】状况
下面我们来思索我们的代码应当怎样写。。。
无状况灰色div里放一个背景图片,上面的笔墨是html节点。
灰色模块上面附一层紫色block,笔墨也是html节点,差别状况设置差别的div的width就好了。
状况笔墨零丁是节点一共10个状况笔墨节点
我希冀转变一个div属性全部动画都邑响应的变化
html代码以下
<div img-animate="init" id="waybill_img_box" class="waybill-img-box" >
<div class="waybill-img01"></div>
<div id="waybill_img_color" class="waybill-img02 dot-scale"></div>
<b class="waybill-no-color-01">揽收</b>
<b class="waybill-no-color-02">脱离辟件国</b>
<b class="waybill-no-color-03">抵达目标国</b>
<b class="waybill-no-color-04">妥投</b>
<b class="waybill-color-01">揽收</b>
<b class="waybill-color-02">脱离辟件国</b>
<b class="waybill-color-03">抵达目标国</b>
<b class="waybill-color-04">妥投</b>
<b class="waybill-color-05">抵达待取</b>
<b class="waybill-color-06">运输中</b>
</div>
我们给#waybill_img_box 这个div增加一个img-animate的属性,用来掌握他的子节点的展现。
waybill-img01这个div用来放灰色的图片
waybill_img_color 这个div放的是彩色图片,我们变动她的width来完成动画,它是相对定位的
剩下的一堆b标签都是笔墨内容的定位。固然他们也是相对定位的
css代码以下:为了简短,我只列举了两种状况
/*初始化的时刻一切的紫色模块的字全都应当隐蔽*/
[img-animate="init"] .waybill-color-01,
[img-animate="init"] .waybill-color-02,
[img-animate="init"] .waybill-color-03,
[img-animate="init"] .waybill-color-04,
[img-animate="init"] .waybill-color-05,
[img-animate="init"] .waybill-color-06 {
z-index: -1;
}
[img-animate="init"] .waybill-img02 {
width: 0;
}
/*紫色元素的字的默许状况*/
.waybill-color-01,
.waybill-color-02,
.waybill-color-03,
.waybill-color-04,
.waybill-color-05,
.waybill-color-06 {
text-align: center;
font-weight: 500;
position: absolute;
top: 78px;
left: 12px;
z-index: 20;
color: #fff;
background: #4b4ebe;
padding: 4px 5px;
height: 12px;
line-height: 12px;
border-radius: 3px;
display: none\9;
-moz-transform: scale(0);
-webkit-transform: scale(0);
-o-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
}
.waybill-color-02 {
left: 208px;
top: 28px;
min-width: 35px;
}
.waybill-color-03 {
left: 419px;
top: 30px;
min-width: 70px;
}
.waybill-color-04 {
left: 636px;
top: 75px;
min-width: 50px;
}
.waybill-color-05 {
left: 562px;
top: 50px;
min-width: 50px;
}
.waybill-color-06 {
left: 105px;
top: 42px;
min-width: 50px;
}
/*
*下面写揽收状况的款式
*PICKEDUP
*/
[img-animate="PICKEDUP"] .waybill-no-color-01,
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-no-color-01 {
-moz-transition: all 0.3s ease-in 0s;
-webkit-transition: all 0.3s ease-in 0s;
-o-transition: all 0.3s ease-in 0s;
transition: all 0.3s ease-in 0s;
-moz-transform: translate(8px, 95px) scale(0);
-webkit-transform: translate(8px, 95px) scale(0);
-o-transform: translate(8px, 95px) scale(0);
-ms-transform: translate(8px, 95px) scale(0);
transform: translate(8px, 95px) scale(0);
}
[img-animate="PICKEDUP"] .waybill-color-01,
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-no-color-02{
-moz-transition: all 0.3s ease-in 0s;
-webkit-transition: all 0.3s ease-in 0s;
-o-transition: all 0.3s ease-in 0s;
transition: all 0.3s ease-in 0s;
-moz-transform: scale(1);
-webkit-transform: scale(1);
-o-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
z-index: 20;
}
[img-animate="PICKEDUP"] .waybill-color-02,
[img-animate="PICKEDUP"] .waybill-color-03,
[img-animate="PICKEDUP"] .waybill-color-04,
[img-animate="PICKEDUP"] .waybill-color-06,
[img-animate="PICKEDUP"] .waybill-color-05 {
z-index: -1;
}
/*写一个脱离辟件国的状况
* DEPART_FROM_ORIGINAL_COUNTRY
*/
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-color-03,
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-color-04{
z-index: -1;
}
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-no-color-01{
-moz-transform: translate(8px, 85px) scale(0);
-webkit-transform: translate(8px, 85px) scale(0);
-o-transform: translate(8px, 85px) scale(0);
-ms-transform: translate(8px, 85px) scale(0);
transform: translate(8px, 85px) scale(0);
}
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-color-01{
-moz-transition: all 0.3s ease-in 0s;
-webkit-transition: all 0.3s ease-in 0s;
-o-transition: all 0.3s ease-in 0s;
transition: all 0.3s ease-in 0s;
-moz-transform: scale(1);
-webkit-transform: scale(1);
-o-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
z-index: 20;
}
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-no-color-02{
-moz-transition: all 0.3s ease-in 0s;
-webkit-transition: all 0.3s ease-in 0s;
-o-transition: all 0.3s ease-in 0s;
transition: all 0.3s ease-in 0s;
-moz-transform: translate(8px, 20px) scale(0);
-webkit-transform: translate(8px, 20px) scale(0);
-o-transform: translate(8px, 20px) scale(0);
-ms-transform: translate(8px, 20px) scale(0);
transform: translate(8px, 20px) scale(0);
}
[img-animate="DEPART_FROM_ORIGINAL_COUNTRY"] .waybill-color-02{
-moz-transition: all 0.3s ease-in 0s;
-webkit-transition: all 0.3s ease-in 0s;
-o-transition: all 0.3s ease-in 0s;
transition: all 0.3s ease-in 0s;
-moz-transform: scale(1);
-webkit-transform: scale(1);
-o-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
z-index: 20;
}
大抵思绪和tab的完成是一样的,我们在css内里罗列了每一个状况下每一个模块应当对应的状况。 我们把c通用的css写在一个款式里,其他的每一个状况只须要重置特定的款式就能够了
接下来看状况形式在js里的运用
js内里我们把状况对应到每一个函数内里就好了。动画运用了jquery的动画。js代码以下
var statusAnimateMap={
PICKEDUP: function(callback){
var self = waybillDetail;
//更具对应的状况设置动画
//var w = ONEWAYBILL?32:32;
self.waybill_img_colorBox.animate(
{
width:32
},500,function(){
self.waybill_img_box.attr("img-animate",'PICKEDUP');
if(callback&&typeof callback==="function"){
callback();
}
});
},
DEPART_FROM_ORIGINAL_COUNTRY: function(callback){
var self = waybillDetail;
//更具对应的状况设置动画
var w = ONEWAYBILL?345:243;
this.PICKEDUP(function(){
self.waybill_img_colorBox.animate(
{
width:w
},800,function(){
self.waybill_img_box.attr("img-animate",'DEPART_FROM_ORIGINAL_COUNTRY');
if(callback&&typeof callback==="function"){
callback();
}
});
});
},
}
//运用的时刻很简朴
function statusAnimate(status){
if(status&& statusAnimateMap[status]){
statusAnimateMap[status]();
}
}
statusAnimate("PICKEDUP");
这里用到了jquery的animate动画。而且营业请求:
每一个状况完毕才实行下一个状况的动画,比方DEPART_FROM_ORIGINAL_COUNTRY这个状况就须要
1.先实行PICKEDUP的动画
2.再实行DEPART_FROM_ORIGINAL_COUNTRY的动画,
听起来是否是很耳熟,嗯有点promise的觉得。。额不过这么一个简朴的场景固然不须要劳烦promise的大驾了。。。我们给animate绑定一个回调要领就好了。
嗯,详细的完成见这个demo
这个页面另有个单条查询的概况状况,页面构造会不一样,左边列表会隐蔽。。。。检察示例,图片会拉长,也就是说每一个状况都须要零丁写一个单条的查询的款式。。。额还好我们的状况都写在css里我们只须要给页面加一个属性[oneMailNo]然后重置一下每一个状况下各个节点的位置就好了,js只须要修正一下waybill_img_color的宽度就好了。嗯改css的本钱很低的。。bingo
以上就是状况形式在现实开辟中得运用,我们连系了css html js 综合运用状况形式。能够大大削减项目内里的逻辑代码。进步开辟效力,剩下的时候能够去和设计师美眉聊聊生涯。。谈谈人生抱负。。。。
详见我的博客https://www.56way.com