iT邦幫忙

2022 iThome 鐵人賽

DAY 29
0
Modern Web

30天全端網頁學習之旅系列 第 29

範例練習(前端)

  • 分享至 

  • xImage
  •  

創建一個React資料夾名為client

npx create-react-app client

將client放進sample(上一章的後端資料夾)裡,如下
https://ithelp.ithome.com.tw/upload/images/20221012/20152607DIkH7Roh6n.png

在client裡下載module(要在client資料夾裡)

npm install react-router-dom axios

client檔案結構如下
https://ithelp.ithome.com.tw/upload/images/20221012/20152607UKELUGrhPp.png

components

將導覽列作為component

components/Nav.js

import React from "react";
import { Link } from "react-router-dom";

const Nav = () => {
  return (
    <nav>
      <h2>台北101導覽</h2>
      <ul>
        <li>
          <Link to="/">Homepage</Link>
        </li>
        <li>
          <Link to="/Contact">Login</Link>
        </li>
      </ul>
    </nav>
  );
};

export default Nav;

services

透過axios讓react(前端)連接到Node.js(後端)

auth.service.js

import axios from "axios";
const API_URL = "http://localhost:8080/api/contact";

class AuthService {
  contact(name, email, phone, need) {
    return axios.post(API_URL + "/method", {
      name,
      email,
      phone,
      need,
    });
  }
}

export default new AuthService();

pages

pages/Home.js

首頁

import React from "react";
import Picture from "../pictures/one.jpg";
import Picture2 from "../pictures/two.jpeg";

const Home = () => {
  return (
    <main className="body">
      <section className="up">
        <img src={Picture} alt="封面" />
        <h1 className="two" id="go">
          台北最美的風景
        </h1>
        <a href="#introduce">開始導覽</a>
      </section>
      <section className="down" id="introduce">
        <div className="left">
          <h1 className="blue">導覽</h1>
          <p>
            台北101是位於臺灣臺北市信義區的摩天大樓,樓高510公尺,地上101層、地下5層,自落成以來即成為台北重要地標與觀光景點之一。台北101是台灣第一高樓、以及唯一樓層超過100層的建築物,曾於2004年12月1日至2010年1月7日間擁有世界第一高樓的紀錄。目前為世界第十一高樓,也是數一數二高的綠建築。大樓內擁有全球第二大、全球唯二開放給遊客觀賞的巨型阻尼器。標高460公尺的101樓上方之觀景台為全球最高的戶外屋頂觀景步道。
          </p>
          <p>
            台北101座落於臺北市的中心商業區——信義計畫區,最初是為了配合臺灣政府的亞太營運中心政策而籌建的金融服務設施,後轉變成綜合性的商辦建築。原本計畫興建5棟建築,後來改為合併成一座摩天大廈,建築高度最終則提升至509.2公尺,以成為當時之世界第一高樓為目標。
          </p>
          <p>
            台北101的地上樓層有101樓,若包括頂部塔尖內不開放遊客參觀的5層樓則有106樓,地下尚有5層樓。根據CTBUH的4項分類建築物高度判斷法,台北101啟用時在其中3項標準中皆為全世界最高的摩天大樓。
          </p>
        </div>
        <div className="right">
          <img src={Picture2} alt="101照片" />
        </div>
      </section>
    </main>
  );
};

export default Home;

pages/Contact.js

聯絡表單

import React, { useState } from "react";
import AuthService from "../services/auth.service";

const Contact = () => {
  let [name, setName] = useState("");
  let [email, setEmail] = useState("");
  let [phone, setPhone] = useState("");
  let [need, setNeed] = useState("");
  let [message, setMessage] = useState("");
  const handleChangeName = (e) => {
    setName(e.target.value);
  };
  const handleChangeEmail = (e) => {
    setEmail(e.target.value);
  };
  const handleChangePhone = (e) => {
    setPhone(e.target.value);
  };
  const handleChangeNeed = (e) => {
    setNeed(e.target.value);
  };
  const handleContact = () => {
    AuthService.contact(name, email, phone, need)
      .then(() => {
        window.alert("Contact succeeds.");
      })
      .catch((error) => {
        console.log(error.response);
        setMessage(error.response.data);
      });
  };
  return (
    <main>
      <section className="contact">
        <section className="contactWord">
          <h2>我的電話: 0900-123-456</h2>
          <h2>我的Email : 123456@gmail.com</h2>
          <h2>方便聯絡時間 : 周一至周六早上八點到晚上七點</h2>
          <h2>其他聯絡方式 : 臉書、IG</h2>
        </section>

        <div className="line"></div>

        <section className="form">
          <div className="form2">
            <div>
              <label for="name">姓名:</label>
              <input
                onChange={handleChangeName}
                type="text"
                id="name"
                name="name"
              />
            </div>
            <br />

            <div>
              <label for="email">郵件:</label>
              <input
                onChange={handleChangeEmail}
                type="email"
                id="email"
                name="email"
              />
            </div>
            <br />

            <div>
              <label for="phone">電話:</label>
              <input
                onChange={handleChangePhone}
                type="text"
                id="phone"
                name="phone"
              />
            </div>
            <br />

            <div>
              <label for="need">需求:</label>
              <textarea
                onChange={handleChangeNeed}
                name="need"
                id="need"
                rows="10"
              ></textarea>
            </div>
            <br />

            <button onClick={handleContact} type="submit">
              提交表單
            </button>
            <div>{message && <div className="error">{message}</div>}</div>
          </div>
        </section>
      </section>
    </main>
  );
};

export default Contact;

App.js

import React, { useState } from "react";
import Nav from "./components/Nav";
import Home from "./pages/Home";
import Contact from "./pages/Contact";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import "./styles/style.css";

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Nav />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/Contact" element={<Contact />} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

Index.js

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Styles

styles/style.css

* {
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
          box-sizing: border-box;
}

a {
  text-decoration: none;
}

nav {
  background-color: #00b3b9;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -ms-flex-wrap: wrap;
      flex-wrap: wrap;
  position: -webkit-sticky;
  position: sticky;
  top: 0px;
  z-index: 3;
  -webkit-box-shadow: 3px 1px 5px 4px #5e5e5e;
          box-shadow: 3px 1px 5px 4px #5e5e5e;
}

nav h2 {
  font-size: 2rem;
  margin-left: 2rem;
  color: white;
}

nav ul {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: end;
      -ms-flex-pack: end;
          justify-content: flex-end;
  margin-right: 3rem;
  list-style-type: none;
}

nav ul li {
  padding: 0.5rem 1rem;
}

nav ul li a {
  font-size: 1.5rem;
  color: white;
}

main section.up {
  position: relative;
}

main section.up img {
  z-index: -1;
  width: 100%;
  height: 100vh;
}

main section.up h1.two {
  position: absolute;
  bottom: 82vh;
  right: 15vw;
  font-size: 3.5rem;
  color: white;
}

main section.up a {
  position: absolute;
  bottom: 20vh;
  right: 22vw;
  font-size: 2rem;
  text-decoration: none;
  background-color: #00b3b9;
  color: black;
  border-radius: 10%;
  padding: 1rem 1.1rem;
}

main section.down {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
      flex-wrap: wrap;
  padding-bottom: 5rem;
  padding-top: 3rem;
}

main section.down div.left {
  -webkit-box-flex: 3;
      -ms-flex: 3 1 500px;
          flex: 3 1 500px;
}

main section.down div.left h1 {
  padding-left: 3rem;
  font-size: 2rem;
}

main section.down div.left p {
  padding: 2rem 3rem;
}

main section.down div.right {
  -webkit-box-flex: 1;
      -ms-flex: 1 1 200px;
          flex: 1 1 200px;
}

main section.down div.right img {
  width: 20vw;
  height: 60vh;
  margin-left: 3rem;
}

main section.contact {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
      flex-wrap: wrap;
  -ms-flex-pack: distribute;
      justify-content: space-around;
  padding: 3rem;
}

main section.contact section.contactWord {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  -webkit-box-pack: space-evenly;
      -ms-flex-pack: space-evenly;
          justify-content: space-evenly;
}

main section.contact div.line {
  width: 4px;
  background-color: #00fff0;
}

main section.contact section.form {
  margin-left: 3rem;
}

main section.contact section.form div.form2 {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  height: 70vh;
}

main section.contact section.form div.form2 div {
  font-size: 1.2rem;
}

main section.contact section.form div.form2 div input,
main section.contact section.form div.form2 div textarea {
  width: 30vw;
  margin: 1rem 1.5rem;
  background-color: #c4c4c4;
}

main section.contact section.form div.form2 div textarea {
  vertical-align: top;
}

main section.contact section.form div.form2 button {
  -ms-flex-item-align: center;
      -ms-grid-row-align: center;
      align-self: center;
  width: 8rem;
  background-color: #00fff0;
  font-size: 1.2rem;
  padding: 0.5rem 0rem;
  border-radius: 10px;
}

@media screen and (max-width: 850px) {
  nav h2 {
    margin-left: 1rem;
  }
  main.body section.up img {
    width: 100%;
    height: 100%;
    z-index: -1;
  }
  main.body section.up h1.two {
    font-size: 1.2rem;
    bottom: 23vh;
    right: 5vw;
  }
  main.body section.up a {
    font-size: 0.5rem;
    bottom: 5vh;
    right: 13vw;
    padding: 0.5rem 0.6rem;
  }
  main.body section.down {
    padding-bottom: 0rem;
  }
  main.body section.down div.left h1 {
    font-size: 1.5rem;
  }
  main.body section.down div.right img {
    width: 60vw;
    height: 50vh;
    margin-left: 5rem;
  }
}
/*# sourceMappingURL=style.css.map */

執行

最後運行2個server做執行
1.client資料夾

npm start

2.sample資料夾

node index.js

恭喜你!現在整個全端網頁都製作完成了!
https://ithelp.ithome.com.tw/upload/images/20221012/20152607g60jp0aHKS.png

【明天將會進行上架的部分】


上一篇
範例練習(後端)
下一篇
範例練習(上架網頁)
系列文
30天全端網頁學習之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言