iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
2
Modern Web

Nuxt - 使用 Vue.js 做 SSR 的第一哩路系列 第 7

07. Nuxt 頁面怎麼切會更好?以電商登入頁為例

本來打算介紹 Nuxt 版面依功能劃分、由哪些區塊組成。

想到六角學院才比完《甜點電商PK賽》,現成切好的版面很好找,參賽選手也不少,拿來說明與練習再適合不過。

所以這篇換成登入頁來解釋頁面怎麼組成?預先切好的版面如何拆分?
登入頁取自 六角校長gonsakon

前置工作

  1. Assets 搬家
    靜態資源待會登入頁需要,將imgsassjs等搬到 Nuxt assets

  2. 模板語言換成 Pug

$ yarn add -D pug pug-plain-loader
  1. 樣式換成 SASS
$ yarn add -D node-sass sass-loader
  1. 安裝 SUSY (這版面用 SUSY 定義格線系統)
$ yarn add -D susy
  1. 定義全域樣式
    nuxt.config.js
  /*
  ** Global CSS
  */
  css: [
    '@/assets/sass/all.sass'
  ],

定義 Page

先新增 pages/login.vue 登入頁

<template lang="pug">
  .col-container
    .p-login.col-row
      form.p-login__account(action="/")

        .p-login__account__block
          h2.p-login__account__block__title
            | 會員登入
          ul.p-login__community__list.h-md-flex.h-p-md-4.h-none
            li
              a(href="#")
                img(src="~/assets/img/ic-facebook.svg",width="108",height="20")
            li
              a(href="#")
                img(src="~/assets/img/ic-google.svg",width="95",height="20")
            li
              a(href="#")
                img(src="~/assets/img/ic-yahoo.svg",width="97",height="23")
          .h-m-md-4
            .l-registered__form.l-registered__form_small.h-flex.h-align-content-between.h-mb-3
              i.fas.fa-user.l-registered__form__icon
              input(type="text",placeholder="電子信箱/手機號碼").l-registered__form__text

            .l-registered__form.l-registered__form_small.h-flex.h-align-content-between.h-mb-3
              i.fas.fa-key.l-registered__form__icon
              input(type="text",placeholder="請輸入使用者密碼").l-registered__form__text
            .p-login__account__block__checkbox.h-mb-3
              input(type="checkbox",id="check")
              label(for="check") 記住我
        a.p-login__account__submit.h-py-3(href="#")
          | 登入帳號
      .p-login__community.h-md-none
        h2.p-login__community__title
          | —— 連結社群帳號 ——
        ul.p-login__community__list.h-md-flex
          li.h-mb-3
            a(href="#")
              img(src="~/assets/img/ic-facebook.svg",width="108",height="20")
          li.h-mb-3
            a(href="#")
              img(src="~/assets/img/ic-google.svg",width="95",height="20")
          li.h-mb-3
            a(href="#")
              img(src="~/assets/img/ic-yahoo.svg",width="97",height="23")
</template>

看看頁面長怎樣
http://localhost:3000/login


關於 Nuxt 頁面結構

Nuxt 如圖切成三塊

  • Page: 對應路由的頁面元件
  • Layout: 供應頁面元件套用的佈局元件
  • Document: 文件主體

Views

常見後端畫面的佈局只切成頁面內容佈局,可以理解成 Nuxt 的 PageDocument + Layout

Layouts

Document {{ APP }} 中塞的頁面佈局,用來定義包 Page 的 <body> 樣板
固定放在 /layouts

預設 - /layouts/default.vue

<template>
  <nuxt/>
</template>

Document (HTML)

最外層的HTML

預設: /app.html

<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>

為IE客製

<!DOCTYPE html>
<!--[if IE 9]><html lang="en-US" class="lt-ie9 ie9" {{ HTML_ATTRS }}><![endif]-->
<!--[if (gt IE 9)|!(IE)]><!-->
  <head>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>

定義 Layout

前幾章舉例頁面沒有指定 layout,其實都套用預設的 layout/default.vue

觀察甜點電商設計稿,所有頁面共用同一組 Header、Footer
很適合切成同一個前台佈局,暫且稱為 layout/front.vue

(往後若要加後台,再增加 layout/admin.vue )

<template>
  <div>
    <Header/>
    <nuxt/>
    <Footer/>
  </div>
</template>

<script>
    import Header from '~/components/Header.vue'
    import Footer from '~/components/Footer.vue'

    export default {
        components: {
            Header,
            Footer
        }
    }
</script>

分拆 Layout Template

依照不同功能區塊,分拆成 Component

components/Header.vue

<template lang="pug">
  .col-container.l-header
    .col-row.h-align-items-center
      a.l-header__bars.h-none.h-md-block
        i.fas.fa-bars.h-none.h-md-inline
      h1.l-header__logo
        a.h-hideText(href="/index.html") logo
      ul.l-header__menu.h-ml-auto.h-flex-row.h-flex.h-md-none
        li
          a(href="index.html") 首頁
        li
          a(href="product.html") 甜點
        li
          a(href="login.html") 登入
      a.l-header__cart(href="cart.html")
        i.fas.fa-shopping-cart
</template>

components/Footer.vue

<template lang="pug">
  section
    .l-registered
      .col-container
        .col-row.h-flex-lg-column.h-pt-4.h-pb-4
          .l-registered__title.h-flex.h-align-items-center.h-mb-lg-4
            img(src="~/assets/img/logo-light.svg",width="40",height="40")
            h3.h-inline 訂閱你我的甜蜜郵件
          form(action="/").l-registered__form.h-flex.h-align-content-between
            i.fas.fa-envelope.l-registered__form__icon
            input(type="text").l-registered__form__text
            button.l-registered__form__submit.h-ml-auto
              i.fas.fa-arrow-right

    .l-footer
      .col-container
        .col-row.h-mb-4
          .l-footer__contact
            .l-footer__contact__logo.h-mb-md-4
              img(src="~/assets/img/logotype-lg-dark.svg",width="171",height="26")
            ul.l-footer__contact__content
              li
                a(href="tel:+0712345678")
                | 07-1234-5678

              li
                a(href="mailto:sweetaste@email.com")
                | sweetaste@email.com
              li
                a(href="https://www.google.com.tw/maps/place/800%E9%AB%98%E9%9B%84%E5%B8%82%E6%96%B0%E8%88%88%E5%8D%80/@22.6284345,120.2987625", target="_blank") 800 高雄市新興區幸福路 520 號
          .l-footer__title.h-md-none
            img(src="~/assets/img/footer__title.svg",witdt="59",height="218")
        .col-row.h-align-items-end.h-align-items-md-start.h-flex-md-column
          ul.l-footer__social.h-flex.h-mb-md-3
            li
              a(href="#")
                img(src="~/assets/img/ic-line@.svg",width="32",height="32")
            li
              a(href="#")
                img(src="~/assets/img/ic-facebook.svg",width="32",height="32")
          .l-footer__copyright © 2018 Sweetaste* All Rights Reserved
  </template>

指定登入頁 layout

<template lang="pug">
    ...
</template>

<script>
    export default {
        layout: 'front'
    }
</script>

到此已長得七八分像囉!

這篇的拆解過程放在 Github


下一篇寫如何加上 SEO / SMO Tag


上一篇
06. Nuxt Routing 規則入門
下一篇
08. Nuxt 客製《甜點電商》SEO 基本資訊
系列文
Nuxt - 使用 Vue.js 做 SSR 的第一哩路32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
yuski
iT邦新手 4 級 ‧ 2018-10-23 09:37:42

關於http://localhost:3000/login
建議不要放本地端網頁,因為沒辦法看到你的網頁..
可以的話用截圖會比較好喔

Ralph iT邦新手 5 級 ‧ 2018-10-23 12:01:06 檢舉

謝謝你的建議,我再補上預覽圖

這文章描述讀者重現這過程的步驟,本地端連結是供讀者操作用的,放外部連結的意義不大。

範例程式碼可從文末repo下載,動手試試吧

yuski iT邦新手 4 級 ‧ 2018-10-23 14:24:00 檢舉

原來是這樣..謝謝您的回應!

0
b8201032
iT邦新手 4 級 ‧ 2022-01-25 11:50:16

照著做不能執行

ERROR Could not compile template /data/jackcheng/awesome-nuxt-app/node_modules/@nuxt/vue-app/template/App.js: Cannot resolve "@/assets/sass/all.sass" from "/data/jackcheng/awesome-nuxt-app/assets/sass/all.sass"

at node_modules/@nuxt/builder/dist/builder.js:723:17
at async Promise.all (index 16)
at async Builder.compileTemplates (node_modules/@nuxt/builder/dist/builder.js:701:5)
at async Builder.generateRoutesAndFiles (node_modules/@nuxt/builder/dist/builder.js:388:5)
at async Builder.build (node_modules/@nuxt/builder/dist/builder.js:319:5)
at async Object._buildDev (node_modules/@nuxt/cli/dist/cli-dev.js:107:5)
at async Object.startDev (node_modules/@nuxt/cli/dist/cli-dev.js:65:7)
at async Object.run (node_modules/@nuxt/cli/dist/cli-dev.js:52:5)
at async NuxtCommand.run (node_modules/@nuxt/cli/dist/cli-index.js:413:7)

我要留言

立即登入留言