今天回到家, 煮了點(diǎn)面吃, 一邊吃面一邊哭, 淚水滴落在碗里, 沒有開燈。

摘要:前言如何寫好這門課是由技術(shù)專家月影老師講的。控制流設(shè)計(jì)原則為什么要用到事件機(jī)制呢因?yàn)橐档徒Y(jié)構(gòu)之間的耦合度,如果不這樣做的話,我們需要做雙向的操控的。
前言
《如何寫‘好’javascript》這門課是由360技術(shù)專家月影老師講的。
這堂課的ppt
說(shuō)實(shí)話,我一直在糾結(jié)要不要寫關(guān)于js的文章,因?yàn)閷?duì)于js來(lái)說(shuō),我的實(shí)際經(jīng)驗(yàn)不足,更不要說(shuō)面向?qū)ο缶幊膛c函數(shù)式編程了,對(duì)于過(guò)程抽象與行為抽象也沒有深入的理解,但想想還是覺得應(yīng)該分享出來(lái),并且我盡量原汁原味的闡述這門課的內(nèi)容,盡量不加入自己主觀理解,因?yàn)閷?duì)于沒有實(shí)際經(jīng)驗(yàn)的我來(lái)說(shuō),如果添加自己主觀的理解只能誤導(dǎo)讀者,好了,不費(fèi)話了~
一、關(guān)燈吃面需求:
點(diǎn)擊紅色按鈕
背景變成黑色
字體color由黑色變成白色
紅色按鈕變成綠色
1.1 版本1light.onclick = function(evt) { if(light.style.backgroundColor !== "green"){ document.body.style.backgroundColor = "#000"; document.body.style.color = "#fff"; light.style.backgroundColor = "green"; }else{ document.body.style.backgroundColor = ""; document.body.style.color = ""; light.style.backgroundColor = ""; } }
對(duì)于我來(lái)說(shuō),要是讓我完成這個(gè)需求,大概應(yīng)該就寫成這樣吧^_^,
想想這樣寫好不好呢?答案肯定是不好的。
這樣寫的問(wèn)題:
用js直接去修改了元素的樣式。
并且代碼只能看出修改了一些元素的樣式,看不出這坨代碼需要完成哪些需求。
假設(shè):如果以后想改需求了,比如開燈時(shí)字體變?yōu)榧t色,或者需要添加一些功能,那我就得去重新看代碼,去改這一坨代碼,這樣的話,維護(hù)起來(lái)就非常難。
1.2 版本2:lightButton.onclick = function(evt) { if(main.className === "light-on"){ main.className = "light-off"; }else{ main.className = "light-on"; } }
這回代碼語(yǔ)義化就比較強(qiáng)了,通過(guò)js去修改className而不是用js來(lái)直接修改style,這樣寫會(huì)比較好一點(diǎn)。
1.3 版本3:其他思路
今天回到家, 煮了點(diǎn)面吃, 一邊吃面一邊哭, 淚水滴落在碗里, 沒有開燈。
這么寫的思路就是不使用js,而是通過(guò)input和label關(guān)聯(lián)來(lái)切換狀態(tài)。
二、復(fù)雜的UI組件的設(shè)計(jì)這是大家最熟悉不過(guò)的輪播圖組件了,如果用面向過(guò)程的寫法,可能會(huì)出現(xiàn)很多bug,那么如何實(shí)現(xiàn)才是最好的呢?
2.1 步驟1:整體思路整體思路
圖片結(jié)構(gòu)是一個(gè)列表型結(jié)構(gòu),所以主體用 和
使用 css 絕對(duì)定位將圖片重疊在同一個(gè)位置
輪播圖切換的狀態(tài)使用修飾符(modifier)
輪播圖的切換動(dòng)畫使用 css transition
2.2 步驟2: API設(shè)計(jì)具體實(shí)現(xiàn):
class Slider{ constructor(id){ this.container = document.getElementById(id); this.items = this.container.querySelectorAll(".slider-list__item, .slider-list__item--selected"); } // 獲得當(dāng)前元素 getSelectedItem(){ const selected = this.container.querySelector(".slider-list__item--selected"); return selected } // 獲得當(dāng)前元素的索引 getSelectedItemIndex(){ return Array.from(this.items).indexOf(this.getSelectedItem()); } // 切換到第index張圖片 slideTo(idx){ const selected = this.getSelectedItem(); if(selected){ selected.className = "slider-list__item"; } const item = this.items[idx]; if(item){ item.className = "slider-list__item--selected"; } } // 切換到下一張圖片 slideNext(){ const currentIdx = this.getSelectedItemIndex(); const nextIdx = (currentIdx + 1) % this.items.length; this.slideTo(nextIdx); } // 切換到上一張圖片 slidePrevious(){ const currentIdx = this.getSelectedItemIndex(); const previousIdx = (this.items.length + currentIdx - 1) % this.items.length; this.slideTo(previousIdx); } } // 通過(guò)new來(lái)實(shí)例化 const slider = new Slider("my-slider"); setInterval(() => { slider.slideNext() }, 3000)2.3 步驟3:控制流設(shè)計(jì) (下方小圓點(diǎn)與左右按鈕設(shè)計(jì))
控制結(jié)構(gòu)
自定義事件
const detail = {index: idx} const event = new CustomEvent("slide", {bubbles:true, detail}) this.container.dispatchEvent(event)
因?yàn)橄路皆c(diǎn)與圖片自動(dòng)切換的下標(biāo)(index)是一致的,所以可以通過(guò)事件機(jī)制,在圖片slide時(shí)候直接給container派發(fā)一個(gè)事件,這樣的話呢,通過(guò)container去監(jiān)聽這個(gè)事件,去更新控制結(jié)構(gòu)上小圓點(diǎn)的狀態(tài)。
具體實(shí)現(xiàn):
class Slider{ constructor(id, cycle = 3000){ this.container = document.getElementById(id); this.items = this.container.querySelectorAll(".slider-list__item, .slider-list__item--selected"); this.cycle = cycle; const controller = this.container.querySelector(".slide-list__control"); if(controller){ const buttons = controller.querySelectorAll(".slide-list__control-buttons, .slide-list__control-buttons--selected"); controller.addEventListener("mouseover", evt=>{ const idx = Array.from(buttons).indexOf(evt.target); if(idx >= 0){ this.slideTo(idx); this.stop(); } }); controller.addEventListener("mouseout", evt=>{ this.start(); }); // 監(jiān)聽slide事件 this.container.addEventListener("slide", evt => { // 拿到slide事件傳來(lái)的index const idx = evt.detail.index const selected = controller.querySelector(".slide-list__control-buttons--selected"); if(selected) selected.className = "slide-list__control-buttons"; buttons[idx].className = "slide-list__control-buttons--selected"; }) } const previous = this.container.querySelector(".slide-list__previous"); if(previous){ previous.addEventListener("click", evt => { this.stop(); this.slidePrevious(); this.start(); evt.preventDefault(); }); } const next = this.container.querySelector(".slide-list__next"); if(next){ next.addEventListener("click", evt => { this.stop(); this.slideNext(); this.start(); evt.preventDefault(); }); } } getSelectedItem(){ let selected = this.container.querySelector(".slider-list__item--selected"); return selected } getSelectedItemIndex(){ return Array.from(this.items).indexOf(this.getSelectedItem()); } slideTo(idx){ let selected = this.getSelectedItem(); if(selected){ selected.className = "slider-list__item"; } let item = this.items[idx]; if(item){ item.className = "slider-list__item--selected"; } const detail = {index: idx} const event = new CustomEvent("slide", {bubbles:true, detail}) this.container.dispatchEvent(event) } slideNext(){ let currentIdx = this.getSelectedItemIndex(); let nextIdx = (currentIdx + 1) % this.items.length; this.slideTo(nextIdx); } slidePrevious(){ let currentIdx = this.getSelectedItemIndex(); let previousIdx = (this.items.length + currentIdx - 1) % this.items.length; this.slideTo(previousIdx); } start(){ this.stop(); this._timer = setInterval(()=>this.slideNext(), this.cycle); } stop(){ clearInterval(this._timer); } } const slider = new Slider("my-slider"); slider.start();
這個(gè)實(shí)現(xiàn)的構(gòu)造函數(shù)會(huì)復(fù)雜一些,但是把timer定時(shí)器也封裝進(jìn)去了,會(huì)有輪播的時(shí)間默認(rèn)為3秒鐘,同樣的也是獲得container,items,cycle(時(shí)間)通過(guò)事件機(jī)制將控制流中的小圓點(diǎn)與圖片聯(lián)動(dòng)起來(lái)。并且還判斷了controler是否存在,假如以后我們不需要小圓點(diǎn)這個(gè)功能了,我們只需要把html中相關(guān)的結(jié)構(gòu)去掉,js也不會(huì)報(bào)錯(cuò),但是這里還有一個(gè)優(yōu)化的點(diǎn)就是slider與controler之間有著比較強(qiáng)的耦合度。
2.4 控制流設(shè)計(jì)原則為什么要用到事件機(jī)制呢?因?yàn)橐档徒Y(jié)構(gòu)之間的耦合度,如果不這樣做的話,我們需要做雙向的操控的。
舉個(gè)栗子文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108041.html
摘要:前端與一枚大三學(xué)生,非常感謝前端星計(jì)劃,在這里學(xué)習(xí)了很多,非常幸運(yùn)獲得的校招實(shí)習(xí),非常感謝面試我的王峰老師和盧岳文老師總的來(lái)說(shuō),這天的學(xué)習(xí),讓我堅(jiān)定了走前端這條路。使用在模式下可以使元素水平居中,但在模式下卻會(huì)失效。 前端與HTML 一枚大三學(xué)生,非常感謝360前端星計(jì)劃,在這里學(xué)習(xí)了很多,非常幸運(yùn)獲得360的校招實(shí)習(xí)offer~,非常感謝面試我的王峰老師和盧岳文老師!總的來(lái)說(shuō),這7天...
摘要:深入課程鏈接一的版本規(guī)范在之前,把所有標(biāo)準(zhǔn)放在一起去管理,這樣推進(jìn)起來(lái)版本升級(jí)比較難,后來(lái)在的版本中,將標(biāo)準(zhǔn)分成幾個(gè)模塊來(lái)管理。 深入CSS 課程ppt鏈接 一、CSS的版本(level) css Level 1 css Level 2(CSS2.2規(guī)范) css Level 3 Color Module Level 3 Selectors Level 3 Media Queri...
摘要:課程一繼承某些元素會(huì)自動(dòng)繼承其父元素的計(jì)算值舉例上述代碼,標(biāo)簽里的就會(huì)繼承父元素的,為。顯示繼承給設(shè)置顯示繼承根元素下所有元素除獨(dú)自設(shè)置如的都是。二初始值當(dāng)向上繼承到頂點(diǎn)還是沒找到值的話,就需要初始值了。 課程ppt 一、css繼承 1.1 某些元素會(huì)自動(dòng)繼承其父元素的計(jì)算值 舉例: This is a test of inherit. p { color: #666; ...
摘要:不久,傳說(shuō)中的月影大大進(jìn)入了視線。目前擔(dān)任奇虎副總監(jiān)技術(shù)委員會(huì)委員兼前端技術(shù)委員會(huì)主席,前端最大團(tuán)隊(duì)奇舞團(tuán)負(fù)責(zé)人,顧問(wèn)。圖靈訪談我知道月影大大在前端方面特別有名,圖靈社區(qū)的好多留言也都感嘆終于有機(jī)會(huì)訪談到月影大大了。 本文僅用于學(xué)習(xí)和交流,不用于商業(yè)目的。非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/Art... 編者語(yǔ) 通往...
閱讀 705·2023-04-26 02:03
閱讀 1066·2021-11-23 09:51
閱讀 1179·2021-10-14 09:42
閱讀 1778·2021-09-13 10:23
閱讀 1002·2021-08-27 13:12
閱讀 872·2019-08-30 11:21
閱讀 1031·2019-08-30 11:14
閱讀 1080·2019-08-30 11:09