分類
發燒車訊

HotCorner:讓Windows 10擁有macOS的觸發角特性!

目錄

  • 簡介
  • 軟件功能
  • 下載
  • 安裝
  • 卸載
  • 使用
  • License
  • 作者
  • FAQ

簡介

macOS上有一個很方便的功能:“觸發角”。通過這個功能可以設置當鼠標移動到屏幕的四個角時的觸發事件,例如觸發啟動屏幕保護程序等,显示桌面等功能。和我們習慣的熱鍵相對應,macOS將其稱之為“Hot Corners(熱角)”。筆者接下來要介紹的軟件“HotCorner“就是用於讓Windows系統擁有像macOS那樣的觸發角,實現下面動圖展示的效果:

當鼠標移動到屏幕的左上角時,自動打開Windows的時間軸試圖,實現快捷切換任務。

這個程序來源於一個國外大神(Google的信息安全工程師)Tavis Ormandy 的一個小項目 hotcorner,他創作這個項目是因為習慣於一款Linux操作系統桌面:GNOME 3,這款桌面可以在鼠標移動到左上角時觸發任務視圖。他發現每當自己使用Windows 10時,總是會忘記Windows中並沒有這個功能,四處尋找替代軟件都無法令他滿意,因此自己用C語言手擼了一個小程序來實現這個功能。但這個小程序只有一個功能:屏幕左上角觸發Windows時間軸視圖。並且軟件的安裝,卸載都需要通過命令行或者手動實現,十分不方便。

筆者在原先的項目基礎上做出了如下改動:

  1. 用屏幕的左下角來觸發開始菜單
  2. 將軟件打包成安裝引導程序(安裝包)
  3. 給軟件添加圖標
  4. 安裝時可選擇軟件開機啟動
  5. 編寫中文文檔

下面一張動圖演示了筆者添加的左下角觸發開始菜單的功能

軟件功能

  • 當鼠標移動至屏幕左上角時显示Windows 10時間軸視圖
  • 當鼠標移動至屏幕右下角時显示Windows 開始菜單

下載

Github地址:下載地址

碼雲地址:下載地址

如果你不打算參与本軟件開發,只需要下載HotcornerInstaller.exe這個安裝程序即可
國內推薦使用碼雲地址進行下載,速度比較快,但如果你需要提交issue,請前往Github地址。

安裝

從上述下載地址將HotcornerInstaller.exe下載下來之後,雙擊打開即可開始安裝。

卸載

找到軟件的安裝位置(默認是C:\Program Files (x86)\HotCorner),雙擊該文件夾下的unins000.exe即可完成卸載。在卸載之前請先停止軟件運行(同時按下Ctrl+Alt+C)。

使用

軟件安裝完成之後會自動添加到開始菜單的應用列表中,在其中找到HotCorner,單擊之後軟件即可後台運行。如果你使用了如圖所示的屏幕縮放,並且縮放比例不是100%時,則需要進行下面的配置

正常情況下,軟件可以自動獲取屏幕的高度,但是在系統使用屏幕縮放時,會導致軟件獲取到的不是屏幕的真實高度,因此你需要編輯軟件安裝路徑(默認是C:\Program Files (x86)\HotCorner)下的config.txt文件,在這個文件中寫入屏幕的真實高度,例如圖中的屏幕真實高度為1080(無單位),然後重啟軟件。(config.txt中的默認值是0,表示自動獲取屏幕高度。)

在軟件運行過程中同時按下Ctrl+Alt+C可以關閉程序

License

代碼使用GPL3協議進行開源,如需使用代碼請遵循CPL3協議相關規定。

作者

  • Tavis Ormandy @taviso – Original Author
  • Ahmed Samy @asamy – HotKey support
  • Yuchao Huang @misterchaos – Application Package

FAQ

  • Q: 屏幕左上角可以觸發時間軸視圖,但是屏幕右下角沒有反應?

  • A: 你可能使用了屏幕縮放,查看配置說明

  • Q: 我想修改屏幕角觸發的事件,怎麼辦?

  • A: 目前只能自己下載源代碼進行修改,然後重新編譯運行。

  • Q: 軟件運行之後怎麼關閉?

  • A: 在軟件運行過程中同時按下Ctrl+Alt+C可以關閉程序

  • Q: 怎麼讓軟件在開機時運行?

  • A: 在安裝過程中可以選擇開機啟動,如果安裝時沒有選擇,可以手動實現(方法自己百度即可)

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

分類
發燒車訊

比思域更快的大眾家轎才14.59萬起步,買車還不用排隊

這樣的加速放眼這個價位,可以說是數一數二了。當你大腳油門跺下去時,馬牌的MC5輪胎雖然捉地力不錯,但還是響着胎竄出去了,確實有那麼點性能車的味道。儘管動力確實不俗,但是代號DQ380的7速濕式雙離合變速箱還是小小地拖了一下後腿。

大眾在中國深耕多年,絕大部分車系都賣得相當不錯,今天要給大家講講的是奢適寬體轎跑——凌渡。這款車在今年1至3月累計賣出了超過4萬台,實力不用小覷。

動力可以說是凌渡一個小小的賣點,TSI+DSG這套黃金組合併沒有讓我們失望。即便是凌渡的1.4T低功版車型,在實測時,也能有9.1s左右的零百成績。不過在起步時不能憋轉速,這點對於那些玩家來說,還是有點小遺憾。

1.8T車型的零百成績為7.9s,表現比1.4T車型好不少。雖然都是7擋雙離合,但1.8T車型採用的是7擋濕式雙離合。這套雙離合較好地改善了凌渡低速蠕行時的頓挫問題,1/2擋之間的切換不再顯得猶豫。

不過這套7擋雙離合也是有一點點問題,那就是為了平順性,犧牲了一點換擋速度。急加速時的降擋會稍微慢了那麼一點,但也在一個合理的範圍內。如果不是一個對駕駛有很高要求的人,這樣的動力響應已然不錯。

2.0T GTS車型可以說是凌渡的精華所在,220馬力推動僅1475kg的車身,出來的便是6.9s的零百加速。這樣的加速放眼這個價位,可以說是數一數二了。當你大腳油門跺下去時,馬牌的MC5輪胎雖然捉地力不錯,但還是響着胎竄出去了,確實有那麼點性能車的味道。

儘管動力確實不俗,但是代號DQ380的7速濕式雙離合變速箱還是小小地拖了一下後腿。這套變速箱的表現與1.8T車型上的那副相近,都是平順為先,急加速時的降擋還是稍顯拖沓了一些。

除了轎跑這個賣點外,奢適也是凌渡的一大優點。前懸架採用的是麥弗遜式獨立懸架,后懸架則為多連桿獨立懸架,這種結構在同級車中極為常見,但凌渡的調校在操控與舒適之間拿捏得恰到好處。

在過濾路面的震動時,凌渡表現出了足夠的厚實感。即便是在遇到一些大坑窪時,車身的拋跳也不會很明顯。走高速遇到一些接縫位置時,凌渡的底盤貼服性相當不錯。

既然說是奢適寬體轎跑,空間自然不得不提。175cm的體驗者坐在前排時,能獲得3指左右的頭部空間,同時前排的包裹性和舒適性都做得不錯,只是中央扶手的位置稍微低了一些。

二排來看,由於車身偏低矮,所以175cm的體驗者坐在裏面直接就頂頭了,還好腿部依然有兩拳的空間。凌渡的二排中央地板凸起較為明顯,對於中間的乘客不太友好,不過勝在帶有中央頭枕。同時,整個二排的橫向空間表現不錯,坐滿三人時也不會覺得過於擁擠,這點還是值得表揚。

總結

可以看到凌渡這款車表現得頗為全面,無愧於奢適寬體轎跑的名號。動力水平高,儘管換擋稍稍慢了一些,但整體平順性確實好;底盤調校得有高級感,容易討好乘客;最大問題恐怕還是二排頭部空間稍微小了一些。目前凌渡的終端優惠能有5萬塊左右,喜歡的人可以果斷出手了。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

分類
發燒車訊

6秒破百很厲害?國內10來萬買SUV更應該看這點!

值得說明的是,國內媒體測試的多為旱地剎車成績,而在售車型大多採用四季胎,在暴雨天氣下剎車距離或會明顯變長,所以各位在暴雨天氣下最好加長與前車距離。我們可以看到市面上多款SUV車型的100-0km/h剎停成績差異頗大,這也是因為大部分用戶對於剎車方面的關注度不高,導致廠家有出現“偷懶”情況。

大家有沒有發現汽車廠家往往會把宣傳重點放在動力性能和發動機技術上,但是對於剎車性能往往置於末位。而只要您多加留意,就會和朗編一樣發現各個級別中不少熱點車型都以動力性能作為賣點!

連柯迪亞克、途觀L和冠道這類型大尺寸的SUV車型都在極力宣傳動力性能,但這明顯是為迎合國內消費者喜好而做出的選擇,畢竟用戶大多認為動力表現能直接決定行駛的順暢感,或者說是快感!但是這份快感的權重能比得上行車安全性嗎?

再者,我國的高速公路最高限速為120km/h,過多的發動機功率是否必要還有待商榷。

而在我們日常行車過程中,能看見最多的車禍是啥?可能許多人會和朗編一樣會想到追尾事故,四車連環追尾、六車連環追尾等事故經常霸佔着新聞的首頁版面,而且在雨霧天氣,追尾事故發生的幾率也將大幅度上升。

而據之前相關的統計數據显示,汽車追尾在整個道路交通事故中約佔70%以上,造成追尾事故自然有一部分是駕駛員意識、駕駛技術的原因,同時也有一部分是駕駛員意識到位了但車輛的剎車性能不到位而造成的。

現在銷售火爆的15萬級別合資/自主SUV車型它們是否注重剎車性能?

值得說明的是,國內媒體測試的多為旱地剎車成績,而在售車型大多採用四季胎,在暴雨天氣下剎車距離或會明顯變長,所以各位在暴雨天氣下最好加長與前車距離!

我們可以看到市面上多款SUV車型的100-0km/h剎停成績差異頗大,這也是因為大部分用戶對於剎車方面的關注度不高,導致廠家有出現“偷懶”情況。

其實能影響剎車性能的元素有很多,除了輪胎規格、輪胎抓地力以外,還有剎車片和剎車盤的性能,剎車片和剎車盤的材料優劣,摩擦係數的大小都會直接影響到制動力的大小!

而且值得注意的還有剎車分泵的活塞數量,一般家用車型每個分泵只有一個活塞,其性能自然沒有性能車身上的多活塞設計那般剎車力度大而且均勻。

由此可見想要提升剎車性能其實是相當複雜而困難的,比較有效的方法是系統而專業地改裝剎車系統,這裏面包含了輪胎、剎車盤、剎車片、剎車分泵、剎車油等多個配件的升級。

另外一個方法就是廠家在研發車輛時強化車輛剎車系統的調校,優化配件選材以提升原廠車的剎車表現,當然了這要投入更多成本,但是長遠來看,廠家若以優異的剎車性能來作為賣點招攬顧客的話,或會效果斐然!

最後提點題外話,那就是歐洲人為什麼會這麼喜歡高爾夫GTI這一類小鋼炮車型?很重要的就是歐洲的某些高速公路限速更高,在高速區域剎車性能的重要性就完全體現出來了,對於安全性也有更明顯的影響!而咱們國內的汽車消費市場也應該對剎車性能有更高要求,從而倒逼廠家重視提升剎車性能!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

分類
發燒車訊

Jmeter(十) – 從入門到精通 – JMeter邏輯控制器 – 中篇(詳解教程)

1.簡介

Jmeter官網對邏輯控制器的解釋是:“Logic Controllers determine the order in which Samplers are processed.”。

意思是說,邏輯控制器可以控制採樣器(samplers)的執行順序。由此可知,控制器需要和採樣器一起使用,否則控制器就沒有什麼意義了。放在控制器下面的所有的採樣器都會當做一個整體,執行時也會一起被執行。

JMeter邏輯控制器可以對元件的執行邏輯進行控制,除僅一次控制器外,其他可以嵌套別的種類的邏輯控制器。

2.邏輯控制器分類

JMeter中的Logic Controller分為兩類:
(1)控制測試計劃執行過程中節點的邏輯執行順序,如:Loop Controller、If Controller等;
(2)對測試計劃中的腳本進行分組、方便JMeter統計執行結果以及進行腳本的運行時控制等,如:Throughput Controller、Transaction Controller。

3.預覽邏輯控制器 

首先我們來看一下JMeter的邏輯控制器,路徑:線程組(用戶)->添加->邏輯控制器(Logic Controller);我們可以清楚地看到JMeter5中共有17個邏輯控制器,如下圖所示:

如果上圖您看得不是很清楚的話,宏哥總結了一個思維導圖,關於JMeter5的邏輯控制器類型,如下圖所示: 

 通過以上的了解,我們對邏輯控制器有了一個大致的了解和認識。下面宏哥就給小夥伴或則童鞋們分享講解一些通常在工作中會用到的邏輯控制器。 

4.常用邏輯控制器詳解

  這一小節,宏哥就由上而下地詳細地講解一下常用的邏輯控制器。

4.1Critical Section Controller

我們先來看一下,官方原汁原味的解釋:The Critical Section Controller ensures that its children elements (samplers/controllers, etc.) will be executed by only one thread as a named lock will be taken before executing children of controller.

宏哥這個二把刀的翻譯,給你們翻譯一下這段鳥語看看到底是什麼意思,大致意思是: Critical Section Controller(臨界區控制器),確保它的子元素(samplers /控制器等)在執行控制器的子程序之前只執行一個線程作為指定的鎖。呵呵!看到這句話是不是覺得一頭霧水啊,摸一摸自己所剩無幾的頭髮陷入沉思中…..沒有關係的,不要糾結了,宏哥後邊會用具體實例講解一下,看完實例后,再回過頭來閱讀這句話,你就會恍然大悟了。

 1、我們先來看看這個Critical Section Controller長得是啥樣子,路徑:線程組 > 添加 > 邏輯控制器 > 臨界部分控制器,如下圖所示:

2、關鍵參數說明如下:

Name:名稱,可以隨意設置,甚至為空;

Comments:註釋,可隨意設置,可以為空;

Lock name:鎖名稱,這裏可以填入其子節點下執行的線程的名稱,這個線程作為一個全局鎖存在

4.1.1實例講解 

這部分主要是通過配合實例我們來理解一下開始那句話到底什麼意思。

1、宏哥這裏先說一個訪問宏哥博客園的JMeter系列文章的測試場景:我們第一步首先要訪問博客園的首頁,第二步找到宏哥的訪問宏哥博客園的首頁,第三步點擊JMeter類別。按順序完成三步,才能完成這個測試場景。那麼我們根據這個場景用JMeter來添加多個請求的取樣器。如下圖所示:

2、腳本調試是通了,運行JMeter,查看結果樹,如下圖所示:

3、從上個圖,查看結果樹中显示請求結果數據不是按照順序請求,不符合預期,這個時候增加一個critical section controller(臨界部分控制器),增加一個鎖,就能控制執行順序。如下圖所示:

4、腳本調試是通了,運行JMeter,查看結果樹,可以清楚地看出來是按預期的順序執行請求的。但是這樣響應時間會過長,這個後邊再做講解。如下圖所示: 

 4.1.2鎖名分類

(1)鎖名為空,認為每個鎖為不同的鎖

1、宏哥通過具體實例,來看一下,創建鎖名為空的臨界部分控制器,如下圖所示:

2、運行JMeter,查看結果樹,如下圖所示:

(2)鎖名相同,多個鎖認為是同一個鎖,同一個時間點只能存在一個運行中

1、宏哥通過具體實例,來看一下,創建鎖名相同的臨界部分控制器,如下圖所示:

2、運行JMeter,查看結果樹,如下圖所示:

(3)鎖名為變量,根據變量值來判斷是不是屬於同一個鎖,變量值為相同時,則認為是同一個鎖

1、宏哥通過具體實例,來看一下,創建鎖名為變量的臨界部分控制器,如下圖所示:

2、運行JMeter,查看結果樹,如下圖所示:

4.2ForEach Controller

ForEach 控制器:一般搭配用戶變量使用。依次調用用戶定義的變量,直到最後一個,結束循環。為了滿足ForEach Controller提取數據,變量命名的格式一般為“變量名_数字”,其中数字從1開始。
1、即遍歷循環控制器,顧名思義是定義一個循環規則。
2、用來遍歷當前元素的所有可執行場景。
3、在用戶自定義變量中讀取一系列相關的變量,該控制器下的採樣器或控制器都會被執行一次或多次,每次讀取不同的變量值。
4、這個控制器一般配合配置元件 → 正則表達式提取器來一起使用,可對頁面上的某些元素進行重複處理。

1、我們先來看看這個ForEach Controller長得是啥樣子,路徑:線程組 > 添加 > 邏輯控制器 > ForEach控制器,如下圖所示: 

2、關鍵參數說明如下:

Name:名稱,可以隨意設置,甚至為空;

Comments:註釋,可隨意設置,可以為空;

Input variable prefix:輸入變量前綴,可以在“用戶自定義變量”中定義一組變量,循環控制器可以從中獲取到變量對應的值,然後作為循環控制器的循環條件,還可以輸出變量作為取樣器的參數。

Start index for loop:循環變量下標起點。循環指數開始(唯一)→ 遍歷查詢的變量範圍,開始的值(這裏如果不填寫,默認從 1 開始,如果沒有 1 開始的變量,執行時會報錯)

End index for loop:循環變量下標終點。循環指數結束(包含)→ 遍歷查詢的變量範圍,結束的值

Output variable name:輸出變量名稱,循環控制器生成的變量名稱。後續可通過${}引用

Add “_” before number ?: 變量前綴后是否加“_”作為分隔符。如果定義的變量名中有下劃線的話就要勾選此項,否則找不到;反之,沒有的話不要勾選,否則同樣找不到變量

4.2.1實例講解

1、首先在自定義5個前綴為 北京宏哥 的變量,值分別為 a b c d e。並且 北京宏哥 後面的数字是連續的,如果不連續,則不會被循環到,如下圖所示:

2、配置ForEach控制器,如下圖所示:

3、添加請求 訪問博客園首頁 + 輸出值:${宏哥},輸出值是在控制器的輸出變量 宏哥,通過 ${宏哥} 取到輸出變量的值,如下圖所示:

4、添加查看結果樹,運行JMeter,查看結果樹,如下圖所示: 

注意:敲黑板,敲腦袋!!!

1、輸入變量的後綴數值一定要連續,比如 北京宏哥_1, 北京宏哥_2, 北京宏哥_3 … 這樣,如果中間有不連續的,循環會中斷

2、循環開始的設定:如果變量為北京宏哥_1, 北京宏哥_2, 北京宏哥_3,而設定的開始為 1,則會從北京宏哥_2 開始循環

3、循環結束的設定:如果變量有3個 北京宏哥_1, 北京宏哥_2, 北京宏哥_3,而設定的結束為5,則只會循環 北京宏哥_1, 北京宏哥_2, 北京宏哥_3 ,如果設定的結束為2,則會循環  北京宏哥_1, 北京宏哥_2 。

4.3Include Controller

Include控制器用來導入外部的測試片段(非完整的測試計劃),在執行時會執行導入的測試計劃,但是被導入的測試計劃有特殊要求,它不能有線程組,只能包含簡單的控制器及控制器下的元件。換句話說就是相當於加了一個執行單元,一個封裝了的業務操作單元,類似我們程序開發中的函數(方法)一樣。例如一個查詢學生信息的業務操作我們用取樣器來模擬,然後放到簡單控制器中作為一個執行單元,別的地方也要用到時,我們可以不用重複造輪子直接引用過來。

一般來說,Include控制器和測試片段(Test Fragment)配合使用的比較常見。

1、我們先來看看這個include Controller長得是啥樣子,路徑:線程組 > 添加 > 邏輯控制器 > Include控制器,如下圖所示:

2、關鍵參數說明如下:

Name:名稱,可以隨意設置,甚至為空;

Comments:註釋,可隨意設置,可以為空;

Filename:文件名,必輸字段,如果沒有,就會報錯。通過Filename的路徑和文件名引用外部的jmx文件。

宏哥推薦小夥伴或者童鞋們可以將 Include控制器 Module控制器(傳送門)一起對比着學習,Include控制器 是從外部文件引用,只能引用整個測試片段的內容,Module控制器 是從內部文件中引用,引用上相對比較靈活,可以只引用部分測試片段或模塊內容。這樣一內一外不僅容易理解也容易記憶和學習。

4.3.1實例

(1)當Filename路徑的值為空,程序執行報錯,腳本執行中止,不會繼續執行下面的腳本內容。

1、首先創建一個Filename路徑為空的測試計劃,如下圖所示:

2、運行JMeter,查看結果樹(程序執行報錯,腳本執行中止,不會繼續執行下面 訪問博客園首頁 的取樣器),如下圖所示: 

(2)當Filename路徑中的文件不存在,程序直接彈窗報錯並停止執行。

1、首先創建一個Filename路徑中的文件不存在的測試計劃,點擊“保存”按鈕的時候,就會直接彈窗報錯。如下圖所示:

(3)當Filename路徑的文件中不包含測試片段,跳過控制器,繼續向下執行。

1、首先創建一個外部引用沒有測試片段的測試計劃,如下圖所示:

2、創建一個Filename路徑的文件中不包含測試片段的測試計劃,將上邊的外部引用-無測試片段文件添加到Include控制器中,如下圖所示:

3、運行JMeter,查看結果樹(跳過控制器,繼續向下執行 訪問博客園首頁 的取樣器),如下圖所示: 

(3)當Filename路徑的文件中包含測試片段,執行完控制器,再繼續向下執行。

1、首先創建一個外部引用有測試片段的測試計劃,如下圖所示:

2、創建一個Filename路徑的文件中包含測試片段的測試計劃,將上邊的外部引用-有測試片段文件添加到Include控制器中,如下圖所示:

3、運行JMeter,查看結果樹(執行完控制器里的測試片段,再繼續向下執行 訪問博客園首頁 的取樣器),如下圖所示: 

到這裏,大家應該理解了  Include Controller 和  Test Fragment 了吧。宏哥的理解就是,Test Fragment 相當於一個獨立的部分,可以被其他測試計劃引用,實現 樣例的片段化,模塊化,遇到重複需要的,比如登錄、註冊之類的,就可以用Test FragmentInclude Controller 了。這樣可以避免重複造輪子,做許多無用功。

5.小結

   好了,今天關於邏輯控制器的上篇就講解到這裏,這一篇主要介紹了 Critical Section ControllerForEach ControllerInclude控制器

 

您的肯定就是我進步的動力。如果你感覺還不錯,就請鼓勵一下吧!記得隨手點波  推薦  不要忘記哦!!!

別忘了點 推薦 留下您來過的痕迹

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

分類
發燒車訊

Jmeter基礎004—-增加參數化

一、參數化概述

1、參數化概念

      參數化就是動態的獲取並設置數據,當執行批量操作時,如批量插入或批量刪除,之前每執行完一次就需要修改一次,效率太低,參數化可以代替人工獲取並設置數據,安全且高效!

2、Jmeter參數化組件

  • CSV Data Set Config—-CSV數據設置組件
  • 用戶參數
  • 用戶定義的變量
  • 函數

二、參數化實現之CSV Data Set Config

1、概述

     CSV Data Set Config—-CSV數據設置組件,是參數化的實現組件之一,通過這個組件可以動態獲取並設置數據,實現批量操作,如:批量添加操作(執行一次,將多條數據插入到數據庫)。

2、實例1:參數化登錄賬號

      我們錄製的腳本,內容都是固定的,比如手機號、驗證碼都是我們再錄製過程中輸入的,如果我們希望模擬不同用戶登陸,那麼我們並不需要錄製很多個腳本,而只要將腳本中的用戶名、密碼變成變量,而線程執行時,不同線程取得不同的變量值即可。
     下面我們就舉例說明如何參數化登陸賬號。

(1)測試登錄接口:如下圖,新建登陸的HTTP請求並運行,確保登錄接口運行正常。

 

(2)創建一個文本文檔,標準的CSV格式文件,如下圖包括3條數據,每一行數據對應一條登錄信息,不同字段之間使用英文逗號分隔。

(3)線程組右鍵—添加—配置元件—CSV Data Set Config—-CSV,創建一個CSV組件,並聲明數據源、編碼集以及解析格式,如下圖所示:

(4)設置線程組的線程數為3(因為文件中有三條登錄數據),並修改HTTP請求中的參數值,調用CSV數據文件設置中定義的變量,調用格式${變量名},如下圖所示:

 

 (5)運行測試計劃,查看結果樹的運行結果,如下圖所示:

 

 

 3、實例2:批量添加

 實現思想:

 

 

 實現步驟:

(1)創建CSV 數據文件設置,如下圖所示:

 (2)創建HTTP請求,並在請求中調用CSV中定義的變量

 (3)編輯文本文檔,存儲要添加的三條數據

 (4)設置線程組循環次數為3,並運行測試計劃,查看察看結果樹显示。

 

三、參數化之用戶參數

1、用戶參數與CSV參數化的區別

    用戶參數和CSV都是將數據設置進第三方,然後循環讀取數據,區別在於:CSV是將數據設置進外部的文本文檔,而用戶參數是將數據設置進Jmeter內置組件。

2、實現流程  

(1)搭建框架:創建測試計劃、線程組、HTTP請求(請求的JSON數據先不設置)。注意:執行次數是3次(不是設置循環次數,而是設置線程數)

(2)創建Jmeter內置組件存儲要插入的數據:測試計劃右鍵—-添加—-前置處理器—-用戶參數,在用戶參數組件界面添加4個變量、3個用戶,如下圖所示:

 注意:因為此處添加的是用戶,每個用戶對應一個線程 ,添加幾個用戶就應該設置幾個線程,所以這裏設置的是線程組而不是循環次數。

 

(3)將用戶參數組件中的變量名稱設置進HTTP請求的Json數據格式中,調用格式:${變量名},如下圖所示:

 (4)運行測試計劃,查看察看結果樹。

 

四、參數化之用戶定義的變量

1、需求

     當系統執行增刪改查操作時,資源路徑不一定相同,但存在部分相同,如:都是/api/departments/開頭,為了提高編寫路徑的效率,可以將公共路徑定義成變量,然後再在路徑中使用${變量名}調用變量。注:一般定義、存儲全局使用的變量。

2、實現過程

(1)將公共的路徑數據提取出來使用一個組件存儲,如:/api/departments/。測試計劃右鍵—-添加—-配置元件—-用戶定義的變量,創建用戶定義的變量組件,添加自定義變量,如下圖所示:

(2)分別創建HTTP請求,在路徑中公共部分調用定義的路徑變量,非公共部分路徑與原來一致,如下圖所示:

 (3)運行測試計劃,查看結果樹。

 

五、參數化之函數

1、需求

     函數是程序中最基本的封裝單元,封裝了一些常用的功能,比如計數器。在實際應用中當我們需要循環10次查詢信息時,結果數的請求名稱都是一樣的,我們可以使用計數函數添加標號以示區分。

2、實現流程

(1)打開Jmeter內置的函數組件,一共有三種方式:

  •  選項+函數助手對話框
  •  ctrl+shift+F1
  • 工具欄倒數第二個圖標

(2)選擇要使用的函數,給函數傳參,並用Jmeter生成調用格式,如下圖:

 

注:__counter函數的參數:true,每一個用戶單獨一個計數器;false,所有用戶共用一個計數器.

(3)在需要調用函數的位置使用Jmeter生成的調用格式:${_函數名(參數)}

 

 

 (4)運行測試計劃,查看結果樹,如下圖所示:

六、總結

1、參數化—-CSV Data Set Config

     概念:動態獲取並設置數據,操作數據高效安全(程序代替人工)

     實現思想+具體流程:

2、參數化—-用戶參數

實現思想:將數據單獨存儲,然後再將數據讀取到http請求的JSON 數據中

實現流程:

  • 設置執行次數(用戶數)
  • 添加組件用戶參數存儲多條記錄
  • 讀取數據格式: ${變量名 )

3、參數化—-用戶定義的變量

作用:存儲全局性數據 

添加格式:添加用戶定義的變量組件—–鍵和值

調用格式:${變量名}

4、參數化—-函數

概念:程序中的功能單元,封裝了部分實現 

實現: 

  • 打開函數功能模塊
  • 選擇要調用的函數+設置參數+生成調用格式
  • 在需要使用的位置調用即可

5、四種參數化方案比較

  •   CSV和用戶參數使用思想一致,流程上後者更簡單,但是實際應用中,使用CSV居多,因為數據量大時,CSV更方便
  •   用戶定義的變量一般用來存儲全局變量,但是使用場景較少
  •   函數實現更為靈活且內置了好多實現。

總結:最常用的是參數化方法是:CSV+函數

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

分類
發燒車訊

Vue結合路由配置遞歸實現菜單欄

作者:小土豆biubiubiu

博客園:https://www.cnblogs.com/HouJiao/

掘金:https://juejin.im/user/58c61b4361ff4b005d9e894d

微信公眾號:土豆媽的碎碎念(掃碼關注,一起吸貓,一起聽故事,一起學習前端技術)

作者文章的內容均來源於自己的實踐,如果覺得有幫助到你的話,可以點贊給個鼓勵或留下寶貴意見

前言

在日常開發中,項目中的菜單欄都是已經實現好了的。如果需要添加新的菜單,只需要在路由配置中新增一條路由,就可以實現菜單的添加。

相信大家和我一樣,有時候會躍躍欲試自己去實現一個菜單欄。那今天我就將自己實現的菜單欄的整個思路和代碼分享給大家。

本篇文章重在總結和分享菜單欄的一個遞歸實現方式代碼的優化菜單權限等不在本篇文章範圍之內,在文中的相關部分也會做一些提示,有個別不推薦的寫法希望大家不要參考哦。

同時可能會存在一些細節的功能沒有處理或者沒有提及到,忘知曉。

最終的效果

本次實現的這個菜單欄包含有一級菜單二級菜單三級菜單這三種類型,基本上已經可以覆蓋項目中不同的菜單需求。

後面會一步一步從易到難去實現這個菜單。

簡單實現

我們都知道到element提供了 NavMenu 導航菜單組件,因此我們直接按照文檔將這個菜單欄做一個簡單的實現。

基本的布局架構圖如下:

菜單首頁-menuIndex

首先要實現的是菜單首頁這個組件,根據前面的布局架構圖並且參考官方文檔,實現起來非常簡單。

<!-- src/menu/menuIndex.vue -->
<template>
    <div id="menu-index">
        <el-container>
            <el-header>
                <TopMenu :logoPath="logoPath" :name="name"></TopMenu>
            </el-header>
            <el-container id="left-container">
                <el-aside width="200px">
                    <LeftMenu></LeftMenu>                    
                </el-aside>
                <el-main>
                    <router-view/>
                </el-main>
            </el-container>
        </el-container>
    </div>
</template>
<script>
import LeftMenu from './leftMenu';
import TopMenu from './topMenu';
export default {
    name: 'MenuIndex',
    components: {LeftMenu, TopMenu},
    data() {
        return {
            logoPath:  require("../../assets/images/logo1.png"),
            name: '員工管理系統'
        }
    }
}
</script>
<style lang="scss">
    #menu-index{
        .el-header{
            padding: 0px;
        }
    }
</style>

頂部菜單欄-topMenu

頂部菜單欄主要就是一個logo產品名稱

邏輯代碼也很簡單,我直接將代碼貼上。

<!-- src/menu/leftMenu.vue -->
<template>
    <div id="top-menu">
        <img class="logo" :src="logoPath" />
        <p class="name">{{name}}</p>
    </div>
</template>
<script>
export default {
    name: 'topMenu',
    props: ['logoPath', 'name']
}
</script>
<style lang="scss" scoped>
    $topMenuWidth: 80px;
    $logoWidth: 50px;
    $bg-color: #409EFF;
    $name-color: #fff;
    $name-size: 18px;
    #top-menu{
        height: $topMenuWidth;
        text-align: left;
        background-color: $bg-color;
        padding: 20px 20px 0px 20px;
        .logo {
            width: $logoWidth;
            display: inline-block;
        }
        .name{
            display: inline-block;
            vertical-align: bottom;
            color: $name-color;
            font-size: $name-size;
        }
    }
</style>

這段代碼中包含了父組件傳遞給子組件的兩個數據。

props: ['logoPath', 'name']

這個是父組件menuIndex傳遞給子組件topMenu的兩個數據,分別是logo圖標的路徑產品名稱

完成后的界面效果如下。

左側菜單欄-leftMenu

首先按照官方文檔實現一個簡單的菜單欄。

<!-- src/menu/leftMenu.vue -->
<template>
    <div id="left-menu">
        <el-menu 
            :default-active="$route.path" 
            class="el-menu-vertical-demo" 
            :collapse="false">
            <el-menu-item index="1">
                <i class="el-icon-s-home"></i>
                <span slot="title">首頁</span>
            </el-menu-item>
            <el-submenu index="2">
                <template slot="title">
                    <i class="el-icon-user-solid"></i>
                    <span slot="title">員工管理</span>
                </template>
                <el-menu-item index="2-1">員工統計</el-menu-item>
                <el-menu-item index="2-2">員工管理</el-menu-item>
            </el-submenu>
            <el-submenu index="3">
                <template slot="title">
                    <i class="el-icon-s-claim"></i>
                    <span slot="title">考勤管理</span>
                </template>
                <el-menu-item index="3-1">考勤統計</el-menu-item>
                <el-menu-item index="3-2">考勤列表</el-menu-item>
                <el-menu-item index="3-2">異常管理</el-menu-item>
            </el-submenu>
            <el-submenu index="4">
                <template slot="title">
                    <i class="el-icon-location"></i>
                    <span slot="title">工時管理</span>
                </template>
                <el-menu-item index="4-1">工時統計</el-menu-item>
                <el-submenu index="4-2">
                    <template slot="title">工時列表</template>
                    <el-menu-item index="4-2-1">選項一</el-menu-item>
                    <el-menu-item index="4-2-2">選項二</el-menu-item>
                </el-submenu>
            </el-submenu>
        </el-menu>
    </div>
</template>
<script>
export default {
    name: 'LeftMenu'
}
</script>
<style lang="scss">
    // 使左邊的菜單外層的元素高度充滿屏幕
    #left-container{
        position: absolute;
        top: 100px;
        bottom: 0px;
        // 使菜單高度充滿屏幕
        #left-menu, .el-menu-vertical-demo{
            height: 100%;
        }
    }
</style>

注意菜單的樣式代碼,設置了絕對定位,並且設置topbottom使菜單高度撐滿屏幕。

此時在看下界面效果。

基本上算是實現了一個簡單的菜單布局。

不過在實際項目在設計的時候,菜單欄的內容有可能來自後端給我們返回的數據,其中包含菜單名稱菜單圖標以及菜單之間的層級關係

總而言之,我們的菜單是動態生成的,而不是像前面那種固定的寫法。因此下面我將實現一個動態生成的菜單,菜單的數據來源於我們的路由配置

結合路由配置實現動態菜單

路由配置

首先,我將項目的路由配置代碼貼出來。

import Vue from 'vue';
import Router from "vue-router";

// 菜單
import MenuIndex from '@/components/menu/menuIndex.vue';

// 首頁
import Index from '@/components/homePage/index.vue';

// 人員統計
import EmployeeStatistics from '@/components/employeeManage/employeeStatistics.vue';
import EmployeeManage from '@/components/employeeManage/employeeManage.vue'

// 考勤
// 考勤統計
import AttendStatistics from '@/components/attendManage/attendStatistics';
// 考勤列表
import AttendList from '@/components/attendManage/attendList.vue';
// 異常管理
import ExceptManage from '@/components/attendManage/exceptManage.vue';

// 工時
// 工時統計
import TimeStatistics from '@/components/timeManage/timeStatistics.vue';
// 工時列表
import TimeList from '@/components/timeManage/timeList.vue';
Vue.use(Router)


let routes = [
    // 首頁(儀錶盤、快速入口)
    {
        path: '/index',
        name: 'index',
        component: MenuIndex,
        redirect: '/index',  
        meta: {
            title: '首頁',    // 菜單標題
            icon: 'el-icon-s-home',  // 圖標
            hasSubMenu: false, // 是否包含子菜單,false 沒有子菜單;true 有子菜單

        },
        children:[
            {
                path: '/index',
                component: Index
            }
        ]
    },
    // 員工管理
    {
        path: '/employee',
        name: 'employee',
        component: MenuIndex,
        redirect: '/employee/employeeStatistics', 
        meta: {
            title: '員工管理',    // 菜單標題
            icon: 'el-icon-user-solid',  // 圖標
            hasSubMenu: true,   // 是否包含子菜單
        },
        children: [
            // 員工統計
            {
                path: 'employeeStatistics',
                name: 'employeeStatistics',
                meta: {
                    title: '員工統計',    // 菜單標題,
                    hasSubMenu: false    // 是否包含子菜單
                },
                component: EmployeeStatistics,
            },
            // 員工管理(增刪改查)
            {
                path: 'employeeManage',
                name: 'employeeManage',
                meta: {
                    title: '員工管理',    // 菜單標題
                    hasSubMenu: false    // 是否包含子菜單
                },
                component: EmployeeManage
            }
        ]
    },
    // 考勤管理
    {
        path: '/attendManage',
        name: 'attendManage',
        component: MenuIndex,
        redirect: '/attendManage/attendStatistics',
        meta: {
            title: '考勤管理',    // 菜單標題
            icon: 'el-icon-s-claim',  // 圖標
            hasSubMenu: true, // 是否包含子節點,false 沒有子菜單;true 有子菜單
        },
        children:[
            // 考勤統計
            {
                path: 'attendStatistics',
                name: 'attendStatistics',
                meta: {
                    title: '考勤統計',    // 菜單標題   
                    hasSubMenu: false    // 是否包含子菜單               
                },
                component: AttendStatistics,
            },
            // 考勤列表
            {
                path: 'attendList',
                name: 'attendList',
                meta: {
                    title: '考勤列表',    // 菜單標題   
                    hasSubMenu: false    // 是否包含子菜單                 
                },
                component: AttendList,
            },
            // 異常管理
            {
                path: 'exceptManage',
                name: 'exceptManage',
                meta: {
                    title: '異常管理',    // 菜單標題  
                    hasSubMenu: false    // 是否包含子菜單                  
                },
                component: ExceptManage,
            }
        ]
    },
    // 工時管理
    {
        path: '/timeManage',
        name: 'timeManage',
        component: MenuIndex,
        redirect: '/timeManage/timeStatistics',
        meta: {
            title: '工時管理',    // 菜單標題
            icon: 'el-icon-message-solid',  // 圖標
            hasSubMenu: true, // 是否包含子菜單,false 沒有子菜單;true 有子菜單
        },
        children: [
            // 工時統計
            {
                path: 'timeStatistics',
                name: 'timeStatistics',
                meta: {
                    title: '工時統計',    // 菜單標題
                    hasSubMenu: false    // 是否包含子菜單        
                },
                component: TimeStatistics
            },
            // 工時列表
            {
                path: 'timeList',
                name: 'timeList',
                component: TimeList,
                meta: {
                    title: '工時列表',    // 菜單標題
                    hasSubMenu: true    // 是否包含子菜單        
                },
                children: [
                    {
                        path: 'options1',
                        meta: {
                            title: '選項一',    // 菜單標題
                            hasSubMenu: false    // 是否包含子菜單        
                        },
                    },
                    {
                        path: 'options2',
                        meta: {
                            title: '選項二',    // 菜單標題
                            hasSubMenu: false    // 是否包含子菜單        
                        },
                    },
                ]
            }
        ]
    },
];
export default new Router({
    routes
})

在這段代碼的最開始部分,我們引入了需要使用的組件,接着就對路由進行了配置。

此處使用了直接引入組件的方式,項目開發中不推薦這種寫法,應該使用懶加載的方式

路由配置除了最基礎的pathcomponent以及children之外,還配置了一個meta數據項。

meta: {
    title: '工時管理',    // 菜單標題
    icon: 'el-icon-message-solid',  // 圖標
    hasSubMenu: true, // 是否包含子節點,false 沒有子菜單;true 有子菜單
}

meta數據包含的配置有菜單標題(title)、圖標的類名(icon)和是否包含子節點(hasSubMenu)。

根據titleicon這兩個配置項,可以展示當前菜單的標題圖標

hasSubMenu表示當前的菜單項是否有子菜單,如果當前菜單包含有子菜單(hasSubMenutrue),那當前菜單對應的標籤元素就是el-submenu;否則當前菜單對應的菜單標籤元素就是el-menu-item

是否包含子菜單是一個非常關鍵的邏輯,我在實現的時候是直接將其配置到了meta.hasSubMenu這個參數裏面。

根據路由實現多級菜單

路由配置完成后,我們就需要根據路由實現菜單了。

獲取路由配置

既然要根據路由配置實現多級菜單,那第一步就需要獲取我們的路由數據。這裏我使用簡單粗暴的方式去獲取路由配置數據:this.$router.options.routes

這種方式也不太適用日常的項目開發,因為無法在獲取的時候對路由做進一步的處理,比如權限控制

我們在組件加載時打印一下這個數據。

// 代碼位置:src/menu/leftMenu.vue
 mounted(){
    console.log(this.$router.options.routes);
}

打印結果如下。

可以看到這個數據就是我們在router.js中配置的路由數據。

為了方便使用,我將這個數據定義到計算屬性中。

// 代碼位置:src/menu/leftMenu.vue
computed: {
    routesInfo: function(){
        return this.$router.options.routes;
    }
}

一級菜單

首先我們來實現一級菜單

主要的邏輯就是循環路由數據routesInfo,在循環的時候判斷當前路由route是否包含子菜單,如果包含則當前菜單使用el-submenu實現,否則當前菜單使用el-menu-item實現。

<!-- src/menu/leftMenu.vue -->
<el-menu 
    :default-active="$route.path" 
    class="el-menu-vertical-demo" 
    :collapse="false">
    <!--  一級菜單 -->
    <!--  循環路由數據  -->
    <!--  判斷當前路由route是否包含子菜單  -->
    <el-submenu 
        v-for="route in routesInfo" 
        v-if="route.meta.hasSubMenu"
        :index="route.path">
        <template slot="title">
            <i :class="route.meta.icon"></i>
            <span slot="title">{{route.meta.title}}</span>
        </template>
    </el-submenu>
    <el-menu-item :index="route.path" v-else> 
        <i :class="route.meta.icon"></i>
        <span slot="title">{{route.meta.title}}</span>
    </el-menu-item>
</el-menu>

結果:

可以看到,我們第一級菜單已經生成了,員工管理考勤管理工時管理這三個菜單是有子菜單的,所以會有一個下拉按鈕。

不過目前點開是沒有任何內容的,接下來我們就來實現這三個菜單下的二級菜單

二級菜單

二級菜單的實現和一級菜單的邏輯是相同的:循環子路由route.children,在循環的時候判斷子路由childRoute是否包含子菜單,如果包含則當前菜單使用el-submenu實現,否則當前菜單使用el-menu-item實現。

那話不多說,直接上代碼。

<!-- src/menu/leftMenu.vue -->
<el-menu 
    :default-active="$route.path" 
    class="el-menu-vertical-demo" 
    :collapse="false">
    <!--  一級菜單 -->
    <!--  循環路由數據  -->
    <!--  判斷當前路由route是否包含子菜單  -->
    <el-submenu 
        v-for="route in routesInfo" 
        v-if="route.meta.hasSubMenu"
        :index="route.path">
        <template slot="title">
            <i :class="route.meta.icon"></i>
            <span slot="title">{{route.meta.title}}</span>
        </template>
        <!-- 二級菜單 -->
        <!-- 循環子路由`route.children` -->
        <!-- 循環的時候判斷子路由`childRoute`是否包含子菜單 -->
        <el-submenu 
            v-for="childRoute in route.children" 
            v-if="childRoute.meta.hasSubMenu"
            :index="childRoute.path">
            <template slot="title">
                <i :class="childRoute.meta.icon"></i>
                <span slot="title">{{childRoute.meta.title}}</span>
            </template>
        </el-submenu>
        <el-menu-item :index="childRoute.path" v-else> 
            <i :class="childRoute.meta.icon"></i>
            <span slot="title">{{childRoute.meta.title}}</span>
        </el-menu-item>
    </el-submenu>
    <el-menu-item :index="route.path" v-else> 
        <i :class="route.meta.icon"></i>
        <span slot="title">{{route.meta.title}}</span>
    </el-menu-item>
</el-menu>

結果如下:

可以看到二級菜單成功實現。

三級菜單

三級菜單就不用多說了,和一級二級邏輯相同,這裏還是直接上代碼。

<!-- src/menu/leftMenu.vue -->
<el-menu 
    :default-active="$route.path" 
    class="el-menu-vertical-demo" 
    :collapse="false">
    <!--  一級菜單 -->
    <!--  循環路由數據  -->
    <!--  判斷當前路由route是否包含子菜單  -->
    <el-submenu 
        v-for="route in routesInfo" 
        v-if="route.meta.hasSubMenu"
        :index="route.path">
        <template slot="title">
            <i :class="route.meta.icon"></i>
            <span slot="title">{{route.meta.title}}</span>
        </template>
        <!-- 二級菜單 -->
        <!-- 循環子路由`route.children` -->
        <!-- 循環的時候判斷子路由`childRoute`是否包含子菜單 -->
        <el-submenu 
            v-for="childRoute in route.children" 
            v-if="childRoute.meta.hasSubMenu"
            :index="childRoute.path">
            <template slot="title">
                <i :class="childRoute.meta.icon"></i>
                <span slot="title">{{childRoute.meta.title}}</span>
            </template>
            <!-- 三級菜單 -->
            <!-- 循環子路由`childRoute.children` -->
            <!-- 循環的時候判斷子路由`child`是否包含子菜單 -->
            <el-submenu 
                v-for="child in childRoute.children" 
                v-if="child.meta.hasSubMenu"
                :index="child.path">
                <template slot="title">
                    <i :class="child.meta.icon"></i>
                    <span slot="title">{{child.meta.title}}</span>
                </template>
            </el-submenu>
            <el-menu-item :index="child.path" v-else> 
                <i :class="child.meta.icon"></i>
                <span slot="title">{{child.meta.title}}</span>
            </el-menu-item>
        </el-submenu>
        <el-menu-item :index="childRoute.path" v-else> 
            <i :class="childRoute.meta.icon"></i>
            <span slot="title">{{childRoute.meta.title}}</span>
        </el-menu-item>
    </el-submenu>
    <el-menu-item :index="route.path" v-else> 
        <i :class="route.meta.icon"></i>
        <span slot="title">{{route.meta.title}}</span>
    </el-menu-item>
</el-menu>

可以看到工時列表下的三級菜單已經显示了。

總結

此時我們已經結合路由配置實現了這個動態的菜單。

不過這樣的代碼在邏輯上相關於三層嵌套for循環,對應的是我們有三層的菜單。

假如我們有四層五層甚至更多層的菜單時,那我們還得在嵌套更多層for循環。很顯然這樣的方式暴露了前面多層for循環的缺陷,所以我們就需要對這樣的寫法進行一個改進。

遞歸實現動態菜單

前面我們一直在說一級二級三級菜單的實現邏輯都是相同的:循環子路由,在循環的時候判斷子路由是否包含子菜單,如果包含則當前菜單使用el-submenu實現,否則當前菜單使用el-menu-item實現。那這樣的邏輯最適合的就是使用遞歸去實現。

所以我們需要將這部分共同的邏輯抽離出來作為一個獨立的組件,然後遞歸的調用這個組件。

邏輯拆分

<!-- src/menu/menuItem.vue -->
<template>
    <div>
        <el-submenu 
            v-for="child in route" 
            v-if="child.meta.hasSubMenu"
            :index="child.path">
            <template slot="title">
                <i :class="child.meta.icon"></i>
                <span slot="title">{{child.meta.title}}</span>
            </template>
        </el-submenu>
        <el-menu-item :index="child.path" v-else> 
            <i :class="child.meta.icon"></i>
            <span slot="title">{{child.meta.title}}</span>
        </el-menu-item>
    </div>
</template>
<script>
export default {
    name: 'MenuItem',
    props: ['route']
}
</script>

需要注意的是,這次抽離出來的組件循環的時候直接循環的是route數據,那這個route數據是什麼呢。

我們先看一下前面三層循環中循環的數據源分別是什麼。

為了看得更清楚,我將前面代碼中一些不相關的內容進行了刪減。

<!-- src/menu/leftMenu.vue -->

<!--  一級菜單 -->
<el-submenu 
    v-for="route in routesInfo" 
    v-if="route.meta.hasSubMenu">
    <!-- 二級菜單 -->
    
    <el-submenu 
        v-for="childRoute in route.children" 
        v-if="childRoute.meta.hasSubMenu">
        
        <!-- 三級菜單 -->
        <el-submenu 
            v-for="child in childRoute.children" 
            v-if="child.meta.hasSubMenu">
          
        </el-submenu>
    
    </el-submenu>
</el-submenu>

從上面的代碼可以看到:

一級菜單循環的是`routeInfo`,即最初我們獲取的路由數據`this.$router.options.routes`,循環出來的每一項定義為`route`

二級菜單循環的是`route.children`,循環出來的每一項定義為`childRoute`

三級菜單循環的是`childRoute.children`,循環出來的每一項定義為`child`

按照這樣的邏輯,可以發現二級菜單三級菜單循環的數據源都是相同的,即前一個循環結果項的children,而一級菜單的數據來源於this.$router.options.routes

前面我們抽離出來的menuItem組件,循環的是route數據,即不管是一層菜單還是二層三層菜單,都是同一個數據源,因此我們需要統一數據源。那當然也非常好實現,我們在調用組件的時候,為組件傳遞不同的值即可。

代碼實現

前面公共組件已經拆分出來了,後面的代碼就非常好實現了。

首先是抽離出來的meunItem組件,實現的是邏輯判斷以及遞歸調用自身

<!-- src/menu/menuItem.vue -->
<template>
    <div>
        <el-submenu 
            v-for="child in route" 
            v-if="child.meta.hasSubMenu"
            :index="child.path">
            <template slot="title">
                <i :class="child.meta.icon"></i>
                <span slot="title">{{child.meta.title}}</span>
            </template>
            <!--遞歸調用組件自身 -->
            <MenuItem :route="child.children"></MenuItem>
        </el-submenu>
        <el-menu-item :index="child.path" v-else> 
            <i :class="child.meta.icon"></i>
            <span slot="title">{{child.meta.title}}</span>
        </el-menu-item>
    </div>
</template>
<script>
export default {
    name: 'MenuItem',
    props: ['route']
}
</script>

接着是leftMenu組件,調用menuIndex組件,傳遞原始的路由數據routesInfo

<!-- src/menu/leftMenu.vue -->
<template>
    <div id="left-menu">
        <el-menu 
            :default-active="$route.path" 
            class="el-menu-vertical-demo"
            :collapse="false">
            <MenuItem :route="routesInfo"></MenuItem>
        </el-menu>
    </div>
</template>
<script>
import MenuItem from './menuItem'
export default {
    name: 'LeftMenu',
    components: { MenuItem }
}
</script>
<style lang="scss">
    // 使左邊的菜單外層的元素高度充滿屏幕
    #left-container{
        position: absolute;
        top: 100px;
        bottom: 0px;
        // 使菜單高度充滿屏幕
        #left-menu, .el-menu-vertical-demo{
            height: 100%;
        }
    }
</style>

最終的結果這裏就不展示了,和我們需要實現的結果是一致的。

功能完善

到此,我們結合路由配置實現了菜單欄這個功能基本上已經完成了,不過這是一個缺乏靈魂的菜單欄,因為沒有設置菜單的跳轉,我們點擊菜單欄還無法路由跳轉到對應的組件,所以接下來就來實現這個功能。

菜單跳轉的實現方式有兩種,第一種是NavMenu組件提供的跳轉方式。

第二種是在菜單上添加router-link實現跳轉。

那本次我選擇的是第一種方式實現跳轉,這種實現方式需要兩個步驟才能完成,第一步是啟用el-menu上的router;第二步是設置導航的index屬性。

那下面就來實現這兩個步驟。

啟用el-menu上的router

<!-- src/menu/leftMenu.vue -->
<!-- 省略其餘未修改代碼-->
<el-menu 
    :default-active="$route.path" 
    class="el-menu-vertical-demo"
    router
    :collapse="false">
    <MenuItem :route="routesInfo">
    </MenuItem>
</el-menu>

設置導航的index屬性

首先我將每一個菜單標題對應需要設置的index屬性值列出來。

index值對應的是每個菜單在路由中配置的path

首頁        

員工管理    
    員工統計  index="/employee/employeeStatistics"
    員工管理  index="/employee/employeeManage"

考勤管理  
    考勤統計  index="/attendManage/attendStatistics"
    考勤列表  index="/attendManage/attendList"
    異常管理  index="/attendManage/exceptManage"

員工統計  
    員工統計  index="/timeManage/timeStatistics"
    員工統計  index="/timeManage/timeList"
        選項一  index="/timeManage/timeList/options1"
        選項二  index="/timeManage/timeList/options2"

接着在回顧前面遞歸調用的組件,導航菜單的index設置的是child.path,為了看清楚child.path的值,我將其添加菜單標題的右側,讓其显示到界面上。

<!-- src/menu/menuItem.vue -->
<!-- 省略其餘未修改代碼-->
<el-submenu 
    v-for="child in route" 
    v-if="child.meta.hasSubMenu"
    :index="child.path">
    <template slot="title">
        <i :class="child.meta.icon"></i>
        <span slot="title">{{child.meta.title}} | {{child.path}}</span>
    </template>
    <!--遞歸調用組件自身 -->
    <MenuItem :route="child.children"></MenuItem>
</el-submenu>
<el-menu-item :index="child.path" v-else> 
    <i :class="child.meta.icon"></i>
    <span slot="title">{{child.meta.title}} | {{child.path}}</span>
</el-menu-item>

同時將菜單欄的寬度由200px設置為400px

<!-- src/menu/menuIndex.vue -->
<!-- 省略其餘未修改代碼-->
<el-aside width="400px">
    <LeftMenu></LeftMenu>                    
</el-aside>

然後我們看一下效果。

可以發現,child.path的值就是當前菜單在路由中配置path值(router.js中配置的path值)。

那麼問題就來了,前面我們整理了每一個菜單標題對應需要設置的index屬性值,就目前來看,現在設置的index值是不符合要求的。不過仔細觀察現在菜單設置的index值和正常值是有一點接近的,只是缺少了上一級菜單的path值,如果能將上一級菜單path值和當前菜單的path值進行一個拼接,就能得到正確的index值了。

那這個思路實現的方式依然是在遞歸時將當前菜單的path作為參數傳遞給menuItem組件。

<!-- src/menu/menuIndex.vue -->
<!--遞歸調用組件自身 -->
<MenuItem 
    :route="child.children" 
    :basepath="child.path">
</MenuItem>

將當前菜單的path作為參數傳遞給menuItem組件之後,在下一級菜單實現時,就能拿到上一級菜單的path值。然後組件中將basepath的值和當前菜單的path值做一個拼接,作為當前菜單的index值。

<!-- src/menu/menuIndex.vue -->
<el-menu-item :index="getPath(child.path)" v-else> 

</el-menu-item>
<script>
import path from 'path'
export default {
    name: 'MenuItem',
    props: ['route','basepath'],
    data(){
        return {
           
        }
    },
    methods :{
        // routepath 為當前菜單的path值
        // getpath: 拼接 當前菜單的上一級菜單的path 和 當前菜單的path
        getPath: function(routePath){
            return path.resolve(this.basepath, routePath);
        }
    }
}
</script>

再看一下界面。

我們可以看到二級菜單的index值已經沒問題了,但是仔細看,發現工時管理工時列表下的兩個三級菜單index值還是有問題,缺少了工時管理這個一級菜單的path

那這個問題是因為我們在調用組件自身是傳遞的basepath有問題。

<!--遞歸調用組件自身 -->
<MenuItem 
    :route="child.children" 
    :basepath="child.path">
</MenuItem>

basepath傳遞的只是上一級菜單的path,在遞歸二級菜單時,index的值是一級菜單的path值+二級菜單的path值;那當我們遞歸三級菜單時,index的值就是二級菜單的path值+三級菜單的path值,這也就是為什麼工時管理-工時列表下的兩個三級菜單index值存在問題。

所以這裏的basepath值在遞歸的時候應該是累積的,而不只是上一級菜單的path值。因此藉助遞歸算法的優勢,basepath的值也需要通過getPath方法進行處理。

<MenuItem 
    :route="child.children" 
    :basepath="getPath(child.path)">
</MenuItem>

最終完整的代碼如下。

<!-- src/menu/menuIndex.vue -->
<template>
    <div>
        <el-submenu 
            v-for="child in route" 
            v-if="child.meta.hasSubMenu"
            :key="child.path"
            :index="getPath(child.path)">
            <template slot="title">
                <i :class="child.meta.icon"></i>
                    <span slot="title">
                        {{child.meta.title}}
                    </span>
            </template>
            <!--遞歸調用組件自身 -->
            <MenuItem 
                :route="child.children" 
                :basepath="getPath(child.path)">
            </MenuItem>
        </el-submenu>
        <el-menu-item :index="getPath(child.path)" v-else> 
            <i :class="child.meta.icon"></i>
            <span slot="title">
                   {{child.meta.title}}
            </span>
        </el-menu-item>
        
    </div>
</template>
<script>
import path from 'path'
export default {
    name: 'MenuItem',
    props: ['route','basepath'],
    data(){
        return {
           
        }
    },
    methods :{
        // routepath 為當前菜單的path值
        // getpath: 拼接 當前菜單的上一級菜單的path 和 當前菜單的path
        getPath: function(routePath){
            return path.resolve(this.basepath, routePath);
        }
    }
}
</script>

刪除其餘用來調試的代碼

最終效果

文章的最後呢,將本次實現的最終效果在此展示一下。

選項一選項二這兩個三級菜單在路由配置中沒有設置component,這兩個菜單隻是為了實現三級菜單,在最後的結果演示中,我已經刪除了路由中配置的這兩個三級菜單

此處在leftMenu組件中為el-menu開啟了unique-opened

menuIndex組件中,將左側菜單欄的寬度改為200px

關於

作者

小土豆biubiubiu

一個努力學習的前端小菜鳥,知識是無限的。堅信只要不停下學習的腳步,總能到達自己期望的地方

同時還是一個喜歡小貓咪的人,家裡有一隻美短小母貓,名叫土豆

博客園

https://www.cnblogs.com/HouJiao/

掘金

https://juejin.im/user/58c61b4361ff4b005d9e894d

微信公眾號

土豆媽的碎碎念

微信公眾號的初衷是記錄自己和身邊的一些故事,同時會不定期更新一些技術文章

歡迎大家掃碼關注,一起吸貓,一起聽故事,一起學習前端技術

作者寄語

小小總結,歡迎大家指導~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

分類
發燒車訊

亞洲碳中和浪潮下 澳洲總理仍裹足不前捍衛煤炭

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

分類
發燒車訊

全球僅五例! 黃金烏龜身世之謎曝光

摘錄自2020年11月4日聯合新聞網報導

美國媒體《紐約郵報》(New York Post)報導,尼泊爾村莊上周二(27日)發現一隻外貌奇特、金黃色的緣板鱉 (Indian flapshell turtle)。《紐約郵報》指出,這隻緣板鱉是因為基因突變的白變(Leucism),導致體內色素減少,皮膚白皙,蒼白或斑駁,而黃色色素細胞通常會變成主導顏色,與白化症不同。

發現這隻緣板鱉的爬行動物專家德沃柯塔(Kamal Devkota)表示他第一次看到這種特殊顏色的烏龜。牠也是尼泊爾史上第一隻、全世界第五隻患白變的烏龜。研究人員已放生這隻緣板鱉回野外,但德沃柯塔擔心牠會面臨生存問題:「在大自然裡這樣的色差非常罕見,可能會在環境中處於不利地位。」

德沃柯塔補充,烏龜在尼泊爾有重要的宗教和文化價值:「人們相信毗濕奴(印度教最著名的神靈之一)變身烏龜以拯救宇宙免受破壞。」

生物多樣性
國際新聞
尼泊爾
烏龜

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

分類
發燒車訊

民主非人類專利 這三種動物也會選舉罷免

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

分類
發燒車訊

同級最帥的4款轎車,50萬以內沒對手,年輕人就該買這些車

68-68。38萬1、3、5、7系,大家肯定都知道,那4系是什麼鬼。基本上來說,把它“當”成3系的雙門版本准沒錯。這一代寶馬4系其實與3系關聯性非常大,應該說除了外形上的差異,動力系統與机械結構基本一致的。這時候肯定有人會說,“貴這麼多還要少兩扇門這是玩我呢。

基本上每個男生或者喜愛汽車的女性朋友都有着一個跑車夢,開着敞篷跑車在海邊公路上馳騁,或者傍晚獨自在山路享受日落的時間。但現實總是殘酷的,年輕的時候可能礙於經濟實力的原因,基本沒可能會選擇跑車,到了成家立業以後,手頭是寬裕了,可是為了家人買一台敞篷跑車似乎也不是太適合,當然如果是自己的第二第三台車的話就無所謂。那有沒有能作為第一台車,既能滿足家用,也有着想到高的顏值和動感的駕駛體驗呢?答案是有,而且還有4部給閣下選擇。

梅賽德斯-奔馳(進口)- C級

指導價:41.68萬-48.98萬

每次提起奔馳,用優雅這個形容詞最為合適,好像就是它與生俱來的氣質融入到每一款車中,而加上Coupe這個詞之後,這份優雅更能發揮到極致。性感的外形總能給路人留下深刻的印象,經過徹底的革新之後,完全不同於三廂版C級。如果閣下看到這樣一台陌生的屁股,絕對就是Coupe。

C級Coupe不管是300還是200,對應的都是個性化雙門轎跑風格的中型車市場,它們都擁有凌厲而運動的外觀設計,毫不保留的展現出自己的個性,時刻讓你記住一句話,你開的可是奔馳。

英菲尼迪(進口)- Q60

指導價38.98-40.98萬

也許是品牌關係,大家一說到英菲尼迪第一時間想到的就是Q50,然後,就沒有然後了。那現在大家不妨認識一下Q50的Coupe版,Q60,一台詮釋了什麼叫“曲線美”雙門轎跑。各種流暢似水的線條勾勒出絕美的車身輪廓,一副攻擊性十足的前臉相信能瞬間俘獲閣下的心,不說了,先去擦一下口水。

外觀融合了Q50 EauRouge和概念車Q80 Inspiration的設計新元素,使車頭更有衝擊力。內飾相比動感的外觀則溫柔很多,甚至略帶平淡。動力方面目前在售的版本均匹配2.0T發動機搭配7速手自一體變速箱,整體動態跟Q50L相似。

寶馬(進口)- 4系

指導價:41.68-68.38萬

1、3、5、7系,大家肯定都知道,那4系是什麼鬼?基本上來說,把它“當”成3系的雙門版本准沒錯。這一代寶馬4系其實與3系關聯性非常大,應該說除了外形上的差異,動力系統與机械結構基本一致的。這時候肯定有人會說,“貴這麼多還要少兩扇門這是玩我呢?”,這個問題一開始也是這麼想的,直到開上去的那瞬間,那操控手感,那底盤素質。值,非常值。

總結起來4系的特點就是:外觀比3系更寬更低,視覺效果也更震撼,內飾就是一台“寶馬”,沒有驚喜,沒有意外。要說4系最吸引的,還是跟3系的外觀差異,以及紮實的底盤功底。

雷克薩斯-RC

指導價:48.80-58.60萬

雷克薩斯這車在今天講的4部車裡算是比較特別的存在,很多人以為它是IS的雙門版本,但實際上RC可以完全看作單獨專門開發的跑車,而不是衍生車型。

日本紳士最厲害是什麼?當然就是那個固執起來又挺能跟上潮流的性格,RC霸氣的外觀設計會很容易讓人誤以為它有着強大的性能,事實上它對舒適性的妥協較多,很舒服的座椅,很舒服的車內氛圍,在高速上會開到困也不奇怪。性能也是今天講的4部車裡最不“跑車”的,但如果閣下就喜歡跑車造型設計和超級舒適的內在,那麼RC也許就是最適合閣下的那台愛車

結尾

50萬可以買一部思域然後改得“飛天遁地”,也可以買坐上去就舒服到馬上睡着的行政車,但能在外形和內部豪華感上達到平衡且高水準的,目前還是比較少見的。雖然4部都是2.0T汽油發動機,跟“性能”都相去甚遠,但日常在道路找找激情撒撒野還是沒任何問題的。如果閣下是“絕對顏控”,Q60肯定是第一選擇;如果說雙門跑車一定要德國車的話,C級Coupe和4系都不會讓閣下失望,甚至能有點小興奮;至於RC,它除了能給閣下“我很快”的感覺之外,雷克薩斯的匠人品質以及豪華感還能讓圍觀的路人都覺得“你好棒”。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準