iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0
Modern Web

Vue.js 什麼意思系列 第 12

Day 12:Router 繞去哪-active-class & exact-active-class

上篇我們為 Navbar 設定好路由之後,接下來的需求則是希望能夠讓選取效果更為明顯,優化使用者體驗:

  • hover 項目時,字體顏色顯示為紅色 ⇒ 跟隨游標移動位置吸引使用者視線
  • 在被選取的路由底部增加裝飾線 ⇒ 便於使用者辨別目前所在的分頁位址

改寫 BootstrapVue 預設樣式

先找到 BootstrapVue 在 <b-nav-item> 元件中的 <a> 有使用了預設樣式如下:

.navbar-light .navbar-nav .nav-link:hover {
	color: rgba(0, 0, 0, 0.7);
}

再改成專案所需的紅色字體即可,留意權重需蓋過預設樣式。(.my_navbar 是在 Navbar 元件最外層 <b-navbar> 所加的自定義 class name,與 BootstrapVue 預設的 .navbar-light 同層)

.my_navbar {
  &.navbar-light .navbar-nav .nav-link:hover {
    color: red;
  }
}

hover

當前路由底部增加裝飾線

上篇我們嘗試使用兩種方式來設定路由,本篇同樣依照這兩種方式進行相應的處理。一樣先在 <b-nav-item> 元件中的 <a> 找到所使用的預設樣式如下;但因為預設使用的是 focus 效果,所以只有在初次點擊導覽項目時才有作用,一旦滑鼠點擊其他位置使其失焦時,導覽項目便會回到原本的字體顏色。

.navbar-light .navbar-nav .nav-link:focus {
	color: rgba(0, 0, 0, 0.7);
}

1. 透過 router 實例方法 router.push()

透過觸發 click 點擊事件後,再指定要導向 route name 為 navItem.name 的位址。

<b-navbar-nav
	class="my_navbar_item"
	v-for="navItem in navList"
	:key="navItem.id"
>
	<b-nav-item href="#" @click="$router.push({ name: navItem.name })">
		{{ navItem.item }}
	</b-nav-item>
</b-navbar-nav>

因為裝飾線只需要加在目前路由上,所以我們為 <b-nav-item> 綁定一個寫好裝飾線樣式的 class name,透過 v-bind 的陣列語法,並利用「條件(三元)運算子」來完成條件綁定,其條件是當目前路由與點擊事件所導向的位址相同時,該 <b-nav-item> 才會產生名為 current_route 的 class,如此一來就能避免同時為所有的 <b-nav-item> 產生裝飾線樣式。

<b-nav-item
	href="#"
	@click="$router.push(navItem.name)"
	:class="[$route.name === navItem.name ? 'current_route' : '']"
>
	{{ navItem.item }}
</b-nav-item>

不過,使用 router.push() 需要特別留意一點,就是當你重複點擊相同路由時,DevTools 會立馬出現錯誤訊息「"NavigationDuplicated: Avoided redundant navigation to current location"」,因為對瀏覽器而言,它已經在當前位址了,搞不懂為什麼還要再 push 到當前位址,所以認為這是多餘的導向行為而報錯。
redundant navigation

避免重複導向的除錯方式有很多種,在此示範兩種方式:

  • catch error 捕獲錯誤,但不用特別處理錯誤

    <b-nav-item
    	href="#"
    	@click="$router.push(navItem.name).catch(error => error)"
    	:class="[$route.name === navItem.name ? 'current_route' : '']"
    >
    	{{ navItem.item }}
    </b-nav-item>
    
  • 使用 router.push(location, onComplete?, onAbort?) 第三個參數,當路由切換失敗時才會執行onAbort callback function。

    <b-nav-item
    	href="#"
    	@click="$router.push({ name: navItem.name }, () => {}, (error) => error)"
    	:class="[$route.name === navItem.name ? 'current_route' : '']"
    >
    	{{ navItem.item }}
    </b-nav-item>
    

2. 使用 <router-link> 元件

我們先來觀察一下點擊導覽項目時的編譯結果變化。

點擊第一個導覽項目時:
first nav

點擊第二個導覽項目時:
second nav

發現了嗎?每次被點擊的路由都會產生 .router-link-exact-active.router-link-active 的 class!

這兩個 class 其實分別是 <router-link> props 中 exact-active-class 及 active-class 的預設值,前者代表精準(exact)比對出當前路由,後者則為模糊比對當前路由,因此可以利用這兩個既有的 class 屬性,直接設定我們所需要的裝飾線樣式即可。

回頭參考 App.vue,也是在 <style> 中對 .router-link-exact-active 設定樣式,使得當前路由在 Home 或 About 時會呈現綠色字體,就是這麼回事!

#nav {
  padding: 30px;

  a {
    font-weight: bold;
    color: #2c3e50;

    &.router-link-exact-active {
      color: #42b983;
    }
  }
}

最後,增加當前路由裝飾線的需求也成功解決了!
final

參考資料


上一篇
Day 11:Router 怎麼繞-router-link、router-view
下一篇
Day 13:巢狀路由的孩子-Nested Routes
系列文
Vue.js 什麼意思30

尚未有邦友留言

立即登入留言