摘要:以上就是狀態模式在實際開發中得應用,我們結合了綜合應用狀態模式。
在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 代碼
- 我是tab01
- 我是tab02
- 我是tab03
我是tab01 的內容我是tab02的內容我是tab03的內容
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,是不是很開森^_^
global物流查詢
主要是物流詳情狀態的動畫,這個動畫會根據對應的運單號的狀態來展示對應的動畫節點。那么我們一共有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代碼如下
攬收 離開發件國 到達目的國 妥投 攬收 離開發件國 到達目的國 妥投 到達待取 運輸中
我們給#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: none9; -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 綜合應用狀態模式??梢源蟠鬁p少項目里面的邏輯代碼。提高開發效率,剩下的時間可以去和設計師美眉聊聊生活。。談談人生理想。。。。
詳見我的博客https://www.56way.com
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/49938.html
摘要:前端每周清單半年盤點之與篇前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。與求同存異近日,宣布將的構建工具由遷移到,引發了很多開發者的討論。 前端每周清單半年盤點之 React 與 ReactNative 篇 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為...
摘要:是文檔的一種表示結構。這些任務大部分都是基于它。這個實踐的重點是把你在前端練級攻略第部分中學到的一些東西和結合起來。一旦你進入框架部分,你將更好地理解并使用它們。到目前為止,你一直在使用進行操作。它是在前端系統像今天這樣復雜之前編寫的。 本文是 前端練級攻略 第二部分,第一部分請看下面: 前端練級攻略(第一部分) 在第二部分,我們將重點學習 JavaScript 作為一種獨立的語言,如...
摘要:前端每周清單第期與模式變遷與優化界面生成作者王下邀月熊編輯徐川前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000013279448); 前端每周清單第 51 期: React Context A...
摘要:延伸閱讀學習與實踐資料索引與前端工程化實踐前端每周清單半年盤點之篇前端每周清單半年盤點之與篇前端每周清單半年盤點之篇 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎關注【前端之巔】微信公眾號(ID:frontshow),及時獲取前端每周清單;本文則是對于半年來發布的前端每周清單...
閱讀 3751·2021-09-22 15:49
閱讀 3310·2021-09-08 09:35
閱讀 1426·2019-08-30 15:55
閱讀 2326·2019-08-30 15:44
閱讀 719·2019-08-29 16:59
閱讀 1605·2019-08-29 16:16
閱讀 485·2019-08-28 18:06
閱讀 897·2019-08-27 10:55