iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
Vue.js

Nuxt.js 3.x 筆記-打造 SSR 專案系列 第 18

D18:Nuxt 3.x 搭配 CSS Framework-以 Bootstrap 5 為例

  • 分享至 

  • xImage
  •  

本篇文章同步更新於個人部落格,歡迎交流指教~謝謝您的閱讀

Bootstrap 版本:v5.3.1
Sass 版本:v1.63.6

在 Nuxt 專案中,我們可以自由選擇 CSS 預處理器、CSS 框架或是 UI Library 來定義樣式。在 CSS 框架百家爭鳴的時代,這幾年熱門的 Tailwind CSS、基於 Vue.js 開發的 Quasar、或是搭配 Vue3 開發的 Element Plus 都能快速上手,協助我們打造精美的網站。

由於工作上較常使用 Bootstrap 協作,本篇將以 Bootstrap 5 搭配 SCSS 進行說明。

Bootstrap 5 簡介

Bootstrap 有豐富的 Sass 變數、mixins、網格系統、元件、JS 插件,Bootstrap 5 與先前版本最大的不同,除了將 jQuery 從相依項目中移除,也新增 Utilities API(基於 Sass Maps 生成 Utilities Class),可以更簡易的管理或擴充樣式,不需手刻太多 CSS 即可完成多元、複雜的畫面。

套件安裝

npm install bootstrap
npm install sass

使用 Bootstrap 樣式搭配自訂樣式

assets/ 靜態資源目錄定義 SCSS,範例 assets/scss/app.scss,需注意 Bootstrap 樣式與自訂樣式引入順序:

不建議直接引入整包 bootstrap components bootstrap/scss/bootstrap ,選擇需要的樣式引入即可,避免 CSS 檔案過大,造成系統負擔

// assets/scss/app.scss

/** 1. 引入 functions,才能操控 color, svg, calc... */
@import "bootstrap/scss/functions";

/** 2. 自訂變數置於 bootstrap variables 前,覆蓋 bootstrap 變數 */
@import "./color";
@import "./variables";

/** 3. 引入 variables, mixins, root */
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import 'bootstrap/scss/maps';
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";

/** 4. 引入 utilities */
@import "~bootstrap/scss/utilities";

/** 5. 自訂、擴充、調整 utilities */
@import "./utilities";

/** 6. 引入需要的 bootstrap components */
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/tables";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/helpers";
/** ... */

/** 7. 使用 utilities 需引入 utilities api(將 sass map 轉換為 utility classes) */
@import "bootstrap/scss/utilities/api";

/** 8. 客製樣式置於最後,覆蓋前面的樣式 */
@import "./style";

自訂樣式檔案結構:

assets/
|—— scss/
  |—— app.scss
  |—— _color.scss
  |—— _variables.scss
  |—— _style.scss

自訂、擴充、調整 utilities:

透過 map-merge 合併 bootstrap utilities,詳細定義方式參考 官方文件

// assets/scss/utilities.scss
$utilities: map-merge(
  $utilities,
  (
    "cursor": (
      property: cursor,
      class: cursor,
      responsive: true,
      values: auto pointer grab
    )
  )
);

配置全域共用 CSS

接著在 nuxt.config 配置全域共用 CSS,接下來整個專案 HTML 都能使用編譯後的樣式

// nuxt.config.js
export default defineNuxtConfig({
  css: [
    '@/assets/scss/app.scss'
  ],
  postcss: { // CSS 屬性加上瀏覽器相容性前綴
    plugins: {
      autoprefixer: true
    }
  }
})

Nuxt 專案已內建 postcss,加上 autoprefixer: true 會自動為屬性加上瀏覽器相容性前綴
範例定義以下樣式:

.container {
  display: flex;
}

編譯後的 CSS:

.container {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}

定義全域共用 Sass / SCSS 變數(搭配 Vite)

如果想在 .vue 檔內的 <style> 直接使用 Sass / SCSS 變數,需搭配 preprocessorOptions 進行配置

// nuxt.config.js
export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: `
            @import "@/assets/scss/_color.scss";
            @import "@/assets/scss/_variables.scss";
          `
        }
      }
    }
  }
});
// assets/scss/_color.scss
$primary: #49240F;
$secondary: #E4A79D;

接著就可以在 SCF(單一元件檔)使用 SCSS 變數

// pages/hello.vue
<template>
  <div>
    <h1>Hello World</h1>
  </div>
</template>

<style lang="scss" scoped>
h1 {
  color: $primary;
}
</style>

加上 scoped,將樣式作用域限制在元件內,避免造成全域污染,如果希望樣式可以渲染到子元件,透過 :deep() 定義如下

:deep(p) {
	color: $primary;
}

使用 Bootstrap Plugins

plugins/ 目錄註冊 Bootstrap JavaScript Plugins

  1. 新增 plugins/bootstrap.client.js

注意:Nuxt 會自動引入(auto imports)plugins,bootstrap plugins 要限制在 client 端使用,否則會拋錯 document is not defined ,檔名需加上 .client 後綴

  1. 透過 Provide 定義全局變數,將需要的 Bootstrap Plugins 注入到 NuxtApp
// plugins/bootstrap.client.js
import * as bootstrap from 'bootstrap';
const { Modal, Collapse } = bootstrap;

export default defineNuxtPlugin(_nuxtApp => {
  return {
    provide: {
      bootstrap: {
        modal: element => new Modal(element),
        collapse: element => new Collapse(element)
      }
    }
  };
});
  1. 使用 Modal Plugins
// pages/about.vue
<template>
  <div>
    <div class="modal fade" tabindex="-1" ref="modalRef">
      <div class="modal-dialog">
        <div class="modal-content">
	      <div class="modal-header">
	        ...
          </div>
          <div class="modal-body">
            ...
          </div>
          <div class="modal-footer">
            <button type="button" data-bs-dismiss="modal">close</button>
          </div>
        </div>
      </div>
    </div>
    <button type="button" class="btn btn-success" @click="showModal">
      點我看 Modal
    </button>
  </div>
</template>

<script setup>
const { $bootstrap } = useNuxtApp();
const modalRef = ref(null);
let modal;
const showModal = () => {
  modal.show();
};

onMounted(() => {
  modal = $bootstrap.modal(modalRef.value);
});

onBeforeUnmount(() => {
  // 加上 dispose,避免切換頁面時或是 HMR 看到殘留畫面
  modal.dispose();
});
</script>

動態樣式

動態樣式定義方式同 Vue3,在 CSS 使用 v-bind function

// pages/hello.vue
<template>
  <div>
    <h1>hello</h1>
    <h2>world</h2>
    <button @click="theme.color = 'red'">change color</button>
  </div>
</template>

<script setup>
const theme = ref({
  color: 'green'
});
</script>

<style lang="scss" scoped>
h1, h2 {
  color: v-bind('theme.color');
}
</style>

參考資源:
https://nuxt.com/docs/getting-started/styling
https://vite.nuxtjs.org/misc/common-issues#styleresources
https://getbootstrap.com/


上一篇
D17:Nuxt 3.x 自訂 Loading 效果
下一篇
D19:Nuxt 3.x 狀態管理 State Management (1)-useState
系列文
Nuxt.js 3.x 筆記-打造 SSR 專案30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言