1.使用vite構(gòu)建vue3
1.1.執(zhí)行命令
npm create vite

輸入項(xiàng)目名字 elm-frontend

選擇框架-vue

選擇js標(biāo)準(zhǔn)-JavaScript
1.2.項(xiàng)目初始化安裝
進(jìn)入項(xiàng)目目錄,安裝默認(rèn)依賴及vue-router,axios,qs,font-awesome
npm i
npm i vue-router
npm i axios
npm i qs
npm i font-awesome
2.項(xiàng)目初始化
2.1.刪除默認(rèn)生成的代碼

11.png
修改App.vue
<template>
<router-view></router-view>
</template>
修改style.css
html,body,div,span,h1,h2,h3,h4,h5,h6,ul,ol,li,p {
margin: 0;
padding: 0;
font-family: "微軟雅黑";
}
html,body,#app {
width: 100%;
}
ul,ol {
list-style: none;
}
a {
text-decoration: none;
}
修改index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" >
<title>餓了么</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
2.2創(chuàng)建路由文件,及修改main.js使用路由
router/index.js
import {createRouter,createWebHashHistory} from 'vue-router'
const routes = [
]
//創(chuàng)建路由實(shí)例
const router = createRouter({
history: createWebHashHistory(),
routes
});
//路由守衛(wèi)
router.beforeEach( (to, from, next) => {
// 檢查 sessionStorage 中是否有登錄信息
const user = sessionStorage.getItem('user')
// 如果目標(biāo)路由需要認(rèn)證且用戶未登錄
if ( !user && to.meta.isAuth ) {
router.push('/login') // 重定向到登錄頁
} else {
next() // 繼續(xù)導(dǎo)航
}
})
export default router;
main.js
import { createApp } from 'vue'
import App from './App.vue'
import './style.css'
import 'font-awesome/css/font-awesome.min.css'
import router from './router';
const app = createApp(App);
app.use(router);
app.mount('#app');
2.3.創(chuàng)建 axios 實(shí)例并封裝,配置攔截器
新建api/index.js
import axios from 'axios';
// 創(chuàng)建 axios 實(shí)例
const request = axios.create({
baseURL: 'http://localhost:9999/elm',
timeout: 3000 // 請求超時時間
});
// 響應(yīng)攔截器
request.interceptors.response.use(
response => {
// 獲取響應(yīng)數(shù)據(jù)
const res = response.data;
//直接返回響應(yīng)數(shù)據(jù)
return res;
},
error => {
// 處理響應(yīng)錯誤
console.log('響應(yīng)錯誤:' + error); // 打印錯誤信息
}
);
export default request;
2.4.通用組件 TabMenu.vue(底部菜單)
<template>
<ul class="footer">
<li @click="toIndex">
<i class="fa fa-home"></i>
<p>首頁</p>
</li>
<li>
<i class="fa fa-compass"></i>
<p>發(fā)現(xiàn)</p>
</li>
<li @click="toOrderList">
<i class="fa fa-file-text-o"></i>
<p>訂單</p>
</li>
<li>
<i class="fa fa-user-o"></i>
<p>我的</p>
</li>
</ul>
</template>
<script setup>
import { useRouter } from "vue-router";
const router = useRouter();
const toIndex = () => {
router.push({ path: "/" });
};
const toOrderList = () => {
router.push({ path: "/orderList" });
};
</script>
<style scoped>
.wrapper .footer {
width: 100%;
height: 14vw;
border-top: solid 1px #ddd;
background-color: #fff;
position: fixed;
left: 0;
bottom: 0;
display: flex;
justify-content: space-around;
align-items: center;
}
.wrapper .footer li {
/*li本身的尺寸完全由內(nèi)容撐起*/
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #999;
user-select: none;
cursor: pointer;
}
.wrapper .footer li p {
font-size: 2.8vw;
}
.wrapper .footer li i {
font-size: 5vw;
}
</style>
3.組件開發(fā)
3.1.Index.vue
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<div class="icon-location-box">
<div class="icon-location"></div>
</div>
<div class="location-text">
東軟河口園區(qū)<i class="fa fa-caret-down"></i>
</div>
</header>
<div class="search">
<div class="search-fixed-top" ref="fixedBox">
<!-- 搜索框部分中間的白框 -->
<div class="search-box">
<i class="fa fa-search"></i>
<input type="text" placeholder="搜索餓了么商家">
</div>
</div>
</div>
<!-- 點(diǎn)餐分類部分 -->
<ul class="foodtype">
<li @click="toBusinessList(1)">
<img src="../assets/dcfl01.png" />
<p>美食</p>
</li>
<li @click="toBusinessList(2)">
<img src="../assets/dcfl02.png" />
<p>早餐</p>
</li>
<li @click="toBusinessList(3)">
<img src="../assets/dcfl03.png" />
<p>跑腿代購</p>
</li>
<li @click="toBusinessList(4)">
<img src="../assets/dcfl04.png" />
<p>漢堡披薩</p>
</li>
<li @click="toBusinessList(5)">
<img src="../assets/dcfl05.png" />
<p>甜品飲品</p>
</li>
<li @click="toBusinessList(6)">
<img src="../assets/dcfl06.png" />
<p>速食簡餐</p>
</li>
<li @click="toBusinessList(7)">
<img src="../assets/dcfl07.png" />
<p>地方小吃</p>
</li>
<li @click="toBusinessList(8)">
<img src="../assets/dcfl08.png" />
<p>米粉面館</p>
</li>
<li @click="toBusinessList(9)">
<img src="../assets/dcfl09.png" />
<p>包子粥鋪</p>
</li>
<li @click="toBusinessList(10)">
<img src="../assets/dcfl10.png" />
<p>炸雞炸串</p>
</li>
</ul>
<!-- 橫幅廣告部分(注意:此處有背景圖片) -->
<div class="banner">
<h3>品質(zhì)套餐</h3>
<p>搭配齊全吃得好</p>
<a>立即搶購 ></a>
</div>
<!-- 超級會員部分 -->
<div class="supermember">
<div class="left">
<img src="../assets/super_member.png" />
<h3>超級會員</h3>
<p>• 每月享超值權(quán)益</p>
</div>
<div class="right">立即開通 ></div>
</div>
<!-- 推薦商家部分 -->
<div class="recommend">
<div class="recommend-line"></div>
<p>推薦商家</p>
<div class="recommend-line"></div>
</div>
<!-- 推薦方式部分 -->
<ul class="recommendtype">
<li>綜合排序<i class="fa fa-caret-down"></i></li>
<li>距離最近</li>
<li>銷量最高</li>
<li>篩選<i class="fa fa-filter"></i></li>
</ul>
<!-- 推薦商家列表部分 -->
<ul class="business">
<li >
<img src="" />
<div class="business-info">
<div class="business-info-h">
<h3>name</h3>
<div class="business-info-like">•</div>
</div>
<div class="business-info-star">
<div class="business-info-star-left">
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
</div>
<div class="business-info-star-right">蜂鳥專送</div>
</div>
<div class="business-info-delivery">
<p>¥28起送 | ¥3配送</p>
</div>
<div class="business-info-explain">
<div>描述</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">新</div>
<p>餓了么新用戶首單立減9元</p>
</div>
</div>
</div>
</li>
</ul>
<!-- 底部菜單部分 -->
<TabMenu></TabMenu>
</div>
</template>
<script setup>
import TabMenu from '../components/TabMenu.vue'
import { ref, onBeforeMount} from "vue";
import { useRouter } from "vue-router";
import axios from '../api'
</script>
<style scoped>
/****************** 總?cè)萜?******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097ff;
display: flex;
align-items: center;
}
.wrapper header .icon-location-box {
width: 3.5vw;
height: 3.5vw;
margin: 0 1vw 0 3vw;
}
.wrapper header .location-text {
font-size: 4.5vw;
font-weight: 700;
color: #fff;
}
.wrapper header .location-text .fa-caret-down {
margin-left: 1vw;
}
/****************** search ******************/
.wrapper .search {
width: 100%;
height: 13vw;
}
.wrapper .search .search-fixed-top {
width: 100%;
height: 13vw;
background-color: #0097ff;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .search .search-fixed-top .search-box {
width: 90%;
height: 9vw;
background-color: #fff;
border-radius: 2px;
display: flex;
justify-content: center;
align-items: center;
font-size: 3.5vw;
color: #aeaeae;
font-family: "宋體";
/*此樣式是讓文本選中狀態(tài)無效*/
user-select: none;
}
.wrapper .search .search-fixed-top .search-box .fa-search {
margin-right: 1vw;
}
.search-box input{
width: 40vw;
height: 5vh;
border: none;
outline: none;
}
.search-box input::placeholder {
color: #AEAEAE;
opacity: 0.8;
}
/****************** 點(diǎn)餐分類部分 ******************/
.wrapper .foodtype {
width: 100%;
height: 48vw;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
/*要使用align-content。10個子元素將自動換行為兩行,而且兩行作為一個整體垂直居中*/
align-content: center;
}
.wrapper .foodtype li {
/*一共10個子元素,通過計(jì)算,子元素寬度在16.7 ~ 20 之間,才能保證換兩行*/
width: 18vw;
height: 20vw;
display: flex;
/*彈性盒子主軸方向設(shè)為column,然后仍然是垂直水平方向居中*/
flex-direction: column;
justify-content: center;
align-items: center;
user-select: none;
cursor: pointer;
}
.wrapper .foodtype li img {
width: 12vw;
/*視頻講解時高度設(shè)置為12vw,實(shí)際上設(shè)置為10.3vw更佳*/
height: 10.3vw;
}
.wrapper .foodtype li p {
font-size: 3.2vw;
color: #666;
}
/****************** 橫幅廣告部分 ******************/
.wrapper .banner {
/**
* 設(shè)置容器寬度95%,然后水平居中,這樣兩邊留白;
* 這里不能用padding,因?yàn)楸尘皥D片也會覆蓋padding
*/
width: 95%;
margin: 0 auto;
height: 29vw;
/*此三個樣式組合,可以保證背景圖片充滿整個容器*/
background-image: url(../assets/index_banner.png);
background-repeat: no-repeat;
background-size: cover;
box-sizing: border-box;
padding: 2vw 6vw;
}
.wrapper .banner h3 {
font-size: 4.2vw;
margin-bottom: 1.2vw;
}
.wrapper .banner p {
font-size: 3.4vw;
color: #666;
margin-bottom: 2.4vw;
}
.wrapper .banner a {
font-size: 3vw;
color: #c79060;
font-weight: 700;
}
/****************** 超級會員部分 ******************/
.wrapper .supermember {
/*這里也設(shè)置容器寬度95%,不能用padding,因?yàn)楸尘吧矔錆Mpadding*/
width: 95%;
margin: 0 auto;
height: 11.5vw;
background-color: #feedc1;
margin-top: 1.3vw;
border-radius: 2px;
color: #644f1b;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .supermember .left {
display: flex;
align-items: center;
margin-left: 4vw;
user-select: none;
}
.wrapper .supermember .left img {
width: 6vw;
height: 6vw;
margin-right: 2vw;
}
.wrapper .supermember .left h3 {
font-size: 4vw;
margin-right: 2vw;
}
.wrapper .supermember .left p {
font-size: 3vw;
}
.wrapper .supermember .right {
font-size: 3vw;
margin-right: 4vw;
cursor: pointer;
}
/****************** 推薦商家部分 ******************/
.wrapper .recommend {
width: 100%;
height: 14vw;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .recommend .recommend-line {
width: 6vw;
height: 0.2vw;
background-color: #888;
}
.wrapper .recommend p {
font-size: 4vw;
margin: 0 4vw;
}
/****************** 推薦方式部分 ******************/
.wrapper .recommendtype {
width: 100%;
height: 5vw;
margin-bottom: 5vw;
display: flex;
justify-content: space-around;
align-items: center;
}
.wrapper .recommendtype li {
font-size: 3.5vw;
color: #555;
}
/****************** 推薦商家列表部分 ******************/
.wrapper .business {
width: 100%;
margin-bottom: 14vw;
}
.wrapper .business li {
width: 100%;
box-sizing: border-box;
padding: 2.5vw;
user-select: none;
border-bottom: solid 1px #ddd;
display: flex;
}
.wrapper .business li img {
width: 18vw;
height: 18vw;
}
.wrapper .business li .business-info {
width: 100%;
box-sizing: border-box;
padding-left: 3vw;
}
.wrapper .business li .business-info .business-info-h {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2vw;
}
.wrapper .business li .business-info .business-info-h h3 {
font-size: 4vw;
color: #333;
}
.wrapper .business li .business-info .business-info-h .business-info-like {
width: 1.6vw;
height: 3.4vw;
background-color: #666;
color: #fff;
font-size: 4vw;
margin-right: 4vw;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .business li .business-info .business-info-star {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2vw;
font-size: 3.1vw;
}
.wrapper
.business
li
.business-info
.business-info-star
.business-info-star-left {
display: flex;
align-items: center;
}
.wrapper
.business
li
.business-info
.business-info-star
.business-info-star-left
.fa-star {
color: #fec80e;
margin-right: 0.5vw;
}
.wrapper
.business
li
.business-info
.business-info-star
.business-info-star-left
p {
color: #666;
margin-left: 1vw;
}
.wrapper
.business
li
.business-info
.business-info-star
.business-info-star-right {
background-color: #0097ff;
color: #fff;
font-size: 2.4vw;
border-radius: 2px;
padding: 0 0.6vw;
}
.wrapper .business li .business-info .business-info-delivery {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2vw;
color: #666;
font-size: 3.1vw;
}
.wrapper .business li .business-info .business-info-explain {
display: flex;
align-items: center;
margin-bottom: 3vw;
}
.wrapper .business li .business-info .business-info-explain div {
border: solid 1px #ddd;
font-size: 2.8vw;
color: #666;
border-radius: 3px;
padding: 0 0.1vw;
}
.wrapper .business li .business-info .business-info-promotion {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.8vw;
}
.wrapper
.business
li
.business-info
.business-info-promotion
.business-info-promotion-left {
display: flex;
align-items: center;
}
.wrapper
.business
li
.business-info
.business-info-promotion
.business-info-promotion-left
.business-info-promotion-left-incon {
width: 4vw;
height: 4vw;
background-color: #70bc46;
border-radius: 3px;
font-size: 3vw;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper
.business
li
.business-info
.business-info-promotion
.business-info-promotion-left
p {
color: #666;
font-size: 3vw;
margin-left: 2vw;
}
.wrapper
.business
li
.business-info
.business-info-promotion
.business-info-promotion-right {
display: flex;
align-items: center;
font-size: 2.5vw;
color: #999;
}
.wrapper
.business
li
.business-info
.business-info-promotion
.business-info-promotion-right
p {
margin-right: 2vw;
}
</style>
3.2.BusinessList.vue 商家列表組件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>商家列表</p>
</header>
<!-- 商家列表部分 -->
<ul class="business">
<li >
<div class="business-img">
<img src="" />
</div>
<div class="business-info">
<h3>商家名</h3>
<p>
¥1起送 | ¥5配送
</p>
<p>商家說明</p>
</div>
</li>
</ul>
<!-- 底部菜單部分 -->
<TabMenu></TabMenu>
</div>
</template>
<script setup>
import Footer from "../components/TabMenu.vue";
import {ref,reactive} from 'vue'
import {useRouter,useRoute} from 'vue-router'
import axios from '@/api'
</script>
<style scoped>
/****************** 總?cè)萜?******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097ff;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 商家列表部分 ******************/
.wrapper .business {
width: 100%;
margin-top: 12vw;
margin-bottom: 14vw;
}
.wrapper .business li {
width: 100%;
box-sizing: border-box;
padding: 2.5vw;
border-bottom: solid 1px #ddd;
user-select: none;
cursor: pointer;
display: flex;
align-items: center;
}
.wrapper .business li .business-img {
/*這里設(shè)置為相當(dāng)定位,成為business-img-quantity元素的父元素*/
position: relative;
}
.wrapper .business li .business-img img {
width: 20vw;
height: 20vw;
}
.wrapper .business li .business-img .business-img-quantity {
width: 5vw;
height: 5vw;
background-color: red;
color: #fff;
font-size: 3.6vw;
border-radius: 2.5vw;
display: flex;
justify-content: center;
align-items: center;
/*設(shè)置成絕對定位,不占文檔流空間*/
position: absolute;
right: -1.5vw;
top: -1.5vw;
}
.wrapper .business li .business-info {
margin-left: 3vw;
}
.wrapper .business li .business-info h3 {
font-size: 3.8vw;
color: #555;
}
.wrapper .business li .business-info p {
font-size: 3vw;
color: #888;
margin-top: 2vw;
}
</style>
3.3.BusinessInfo.vue 商家信息組件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>商家信息</p>
</header>
<!-- 商家logo部分 -->
<div class="business-logo">
<img src="" />
</div>
<!-- 商家信息部分 -->
<div class="business-info">
<h1>商家名</h1>
<p>
¥10起送 ¥5配送
</p>
<p>商家說明</p>
</div>
<!-- 食品列表部分 -->
<ul class="food">
<li>
<div class="food-left">
<img src="" />
<div class="food-left-info">
<h3>食品名</h3>
<p>食品說明</p>
<p>¥10</p>
</div>
</div>
<div class="food-right">
<div>
<i
class="fa fa-minus-circle"
></i>
</div>
<p>
<span>1</span>
</p>
<div>
<i class="fa fa-plus-circle"></i>
</div>
</div>
</li>
</ul>
<!-- 購物車部分 -->
<div class="cart">
<div class="cart-left">
<div class="cart-left-icon">
<i class="fa fa-shopping-cart"></i>
<div class="cart-left-icon-quantity">
3
</div>
</div>
<div class="cart-left-info">
<p>¥100</p>
<p>另需配送費(fèi)3元</p>
</div>
</div>
<div class="cart-right">
<!-- 達(dá)到起送費(fèi) -->
<div class="cart-right-item-not-enough">
去結(jié)算
</div>
</div>
</div>
</div>
</template>
<script setup>
import {ref,reactive} from 'vue'
import {useRouter,useRoute} from 'vue-router'
import axios from '../api'
</script>
<style scoped>
/****************** 總?cè)萜?******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097ff;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 商家logo部分 ******************/
.wrapper .business-logo {
width: 100%;
height: 35vw;
/*使用上外邊距避開header部分*/
margin-top: 12vw;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .business-logo img {
width: 40vw;
height: 30vw;
border-radius: 5px;
}
/****************** 商家信息部分 ******************/
.wrapper .business-info {
width: 100%;
height: 20vw;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.wrapper .business-info h1 {
font-size: 5vw;
}
.wrapper .business-info p {
font-size: 3vw;
color: #666;
margin-top: 1vw;
}
/****************** 食品列表部分 ******************/
.wrapper .food {
width: 100%;
/*使用下外邊距避開footer部分*/
margin-bottom: 14vw;
}
.wrapper .food li {
width: 100%;
box-sizing: border-box;
padding: 2.5vw;
user-select: none;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .food li .food-left {
display: flex;
align-items: center;
}
.wrapper .food li .food-left img {
width: 20vw;
height: 20vw;
}
.wrapper .food li .food-left .food-left-info {
margin-left: 3vw;
}
.wrapper .food li .food-left .food-left-info h3 {
font-size: 3.8vw;
color: #555;
}
.wrapper .food li .food-left .food-left-info p {
font-size: 3vw;
color: #888;
margin-top: 2vw;
}
.wrapper .food li .food-right {
width: 16vw;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .food li .food-right .fa-minus-circle {
font-size: 5.5vw;
color: #999;
cursor: pointer;
}
.wrapper .food li .food-right p {
font-size: 3.6vw;
color: #333;
}
.wrapper .food li .food-right .fa-plus-circle {
font-size: 5.5vw;
color: #0097ef;
cursor: pointer;
}
/****************** 購物車部分 ******************/
.wrapper .cart {
width: 100%;
height: 14vw;
position: fixed;
left: 0;
bottom: 0;
display: flex;
}
.wrapper .cart .cart-left {
flex: 2;
background-color: #505051;
display: flex;
}
.wrapper .cart .cart-left .cart-left-icon {
width: 16vw;
height: 16vw;
box-sizing: border-box;
border: solid 1.6vw #444;
border-radius: 8vw;
background-color: #3190e8;
font-size: 7vw;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
margin-top: -4vw;
margin-left: 3vw;
position: relative;
}
.wrapper .cart .cart-left .cart-left-icon-quantity {
width: 5vw;
height: 5vw;
border-radius: 2.5vw;
background-color: red;
color: #fff;
font-size: 3.6vw;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
right: -1.5vw;
top: -1.5vw;
}
.wrapper .cart .cart-left .cart-left-info p:first-child {
font-size: 4.5vw;
color: #fff;
margin-top: 1vw;
}
.wrapper .cart .cart-left .cart-left-info p:last-child {
font-size: 2.8vw;
color: #aaa;
}
.wrapper .cart .cart-right {
flex: 1;
}
/*達(dá)到起送費(fèi)時的樣式*/
/*
.wrapper .cart .cart-right .cart-right-item {
width: 100%;
height: 100%;
background-color: #38ca73;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
*/
/*不夠起送費(fèi)時的樣式(只有背景色和鼠標(biāo)樣式的區(qū)別)*/
.cart-right-item-not-enough{
width: 100%;
height: 100%;
background-color: #535356;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
display: flex;
justify-content: center;
align-items: center;
}
</style>
3.4.Login.vue組件 登錄組件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>用戶登陸</p>
</header>
<!-- 表單部分 -->
<ul class="form-box">
<li>
<div class="title">手機(jī)號碼:</div>
<div class="content">
<input type="text" placeholder="手機(jī)號碼" />
</div>
</li>
<li>
<div class="title">密碼:</div>
<div class="content">
<input type="password" placeholder="密碼" />
</div>
</li>
</ul>
<div class="button-login">
<button>登陸</button>
</div>
<div class="button-register">
<button>去注冊</button>
</div>
<!-- 底部菜單部分 -->
<TabMenu></TabMenu>
</div>
</template>
<script setup>
import TabMenu from '../components/TabMenu.vue'
import axios from "../api";
import qs from 'qs'
import { useRouter } from "vue-router";
</script>
<style scoped>
/****************** 總?cè)萜?******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097ff;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 表單部分 ******************/
.wrapper .form-box {
width: 100%;
margin-top: 12vw;
}
.wrapper .form-box li {
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
display: flex;
align-items: center;
}
.wrapper .form-box li .title {
flex: 0 0 18vw;
font-size: 3vw;
font-weight: 700;
color: #666;
}
.wrapper .form-box li .content {
flex: 1;
}
.wrapper .form-box li .content input {
border: none;
outline: none;
width: 100%;
height: 4vw;
font-size: 3vw;
}
.wrapper .button-login {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-login button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
color: #fff;
background-color: #38ca73;
border-radius: 4px;
border: none;
outline: none;
}
.wrapper .button-register {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-register button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
/*與上面登陸按鈕不同的只有顏色、背景色、邊框不同*/
color: #666;
background-color: #eee;
border: solid 1px #ddd;
border-radius: 4px;
border: none;
outline: none;
}
/****************** 底部菜單部分 ******************/
.wrapper .footer {
width: 100%;
height: 14vw;
border-top: solid 1px #ddd;
background-color: #fff;
position: fixed;
left: 0;
bottom: 0;
display: flex;
justify-content: space-around;
align-items: center;
}
.wrapper .footer li {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #999;
user-select: none;
cursor: pointer;
}
.wrapper .footer li p {
font-size: 2.8vw;
}
.wrapper .footer li i {
font-size: 5vw;
}
</style>
3.5.Register.vue組件 注冊組件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>用戶注冊</p>
</header>
<!-- 表單部分 -->
<ul class="form-box">
<li>
<div class="title">手機(jī)號碼:</div>
<div class="content">
<input type="text"placeholder="手機(jī)號碼"/>
</div>
</li>
<li>
<div class="title">密碼:</div>
<div class="content">
<input type="password" placeholder="密碼" />
</div>
</li>
<li>
<div class="title">確認(rèn)密碼:</div>
<div class="content">
<input type="password" placeholder="確認(rèn)密碼"/>
</div>
</li>
<li>
<div class="title">用戶名稱:</div>
<div class="content">
<input type="text" placeholder="用戶名稱" />
</div>
</li>
<li>
<div class="title">性別:</div>
<div class="content" style="font-size: 3vw">
<input
type="radio"
value="男"
style="width: 6vw; height: 3.2vw"
/>男
<input
type="radio"
value="女"
style="width: 6vw; height: 3.2vw"
/>女
</div>
</li>
<li>
<div class="title">配送地址:</div>
<div class="content">
<input type="text" placeholder="配送地址" />
</div>
</li>
</ul>
<div class="button-login">
<button>注冊</button>
</div>
<!-- 底部菜單部分 -->
<TabMenu></TabMenu>
</div>
</template>
<script setup>
import TabMenu from '../components/TabMenu.vue'
import { ref, reactive } from "vue";
import { useRouter} from "vue-router";
import axios from '../api'
import qs from "qs";
</script>
<style scoped>
/****************** 總?cè)萜?******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097ff;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 表單部分 ******************/
.wrapper .form-box {
width: 100%;
margin-top: 12vw;
}
.wrapper .form-box li {
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
display: flex;
align-items: center;
}
.wrapper .form-box li .title {
flex: 0 0 18vw;
font-size: 3vw;
font-weight: 700;
color: #666;
}
.wrapper .form-box li .content {
flex: 1;
}
.wrapper .form-box li .content input {
border: none;
outline: none;
width: 100%;
height: 4vw;
font-size: 3vw;
}
.wrapper .button-login {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-login button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
color: #fff;
background-color: #38ca73;
border-radius: 4px;
border: none;
outline: none;
}
.wrapper .button-register {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-register button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
color: #666;
background-color: #eee;
border-radius: 4px;
border: none;
outline: none;
border: solid 1px #ddd;
}
</style>
3.6.Order.vue組件 訂單確認(rèn)組件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>確認(rèn)訂單</p>
</header>
<!-- 訂單信息部分 -->
<div class="order-info">
<h5>訂單配送至:</h5>
<div class="order-info-address">
<p>沈陽市渾南區(qū)智慧四街1-121號</p>
<i class="fa fa-angle-right"></i>
</div>
<p>
苗苗先生 13050213330
</p>
</div>
<h3>萬家餃子(軟件園E18店)</h3>
<!-- 訂單明細(xì)部分 -->
<ul class="order-detailed">
<li>
<div class="order-detailed-left">
<img src="" />
<p>三鮮餃子 x 2</p>
</div>
<p>¥30</p>
</li>
</ul>
<div class="order-deliveryfee">
<p>配送費(fèi)</p>
<p>¥8</p>
</div>
<!-- 合計(jì)部分 -->
<div class="total">
<div class="total-left">¥38</div>
<div class="total-right">確認(rèn)下單</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from "vue"
import { useRouter, useRoute } from "vue-router"
import axios from "..//api"
import qs from "qs"
</script>
<style scoped>
/****************** 總?cè)萜?******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097ff;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 訂單信息部分 ******************/
.wrapper .order-info {
/*注意這里,不設(shè)置高,靠內(nèi)容撐開。因?yàn)榈刂酚锌赡苷坌?/
width: 100%;
margin-top: 12vw;
background-color: #0097ef;
box-sizing: border-box;
padding: 2vw;
color: #fff;
}
.wrapper .order-info h5 {
font-size: 3vw;
font-weight: 300;
}
.wrapper .order-info .order-info-address {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 700;
user-select: none;
cursor: pointer;
margin: 1vw 0;
}
.wrapper .order-info .order-info-address p {
width: 90%;
font-size: 5vw;
}
.wrapper .order-info .order-info-address i {
font-size: 6vw;
}
.wrapper .order-info p {
font-size: 3vw;
}
.wrapper h3 {
box-sizing: border-box;
padding: 3vw;
font-size: 4vw;
color: #666;
border-bottom: solid 1px #ddd;
}
/****************** 訂單明細(xì)部分 ******************/
.wrapper .order-detailed {
width: 100%;
}
.wrapper .order-detailed li {
width: 100%;
height: 16vw;
box-sizing: border-box;
padding: 3vw;
color: #666;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .order-detailed li .order-detailed-left {
display: flex;
align-items: center;
}
.wrapper .order-detailed li .order-detailed-left img {
width: 10vw;
height: 10vw;
}
.wrapper .order-detailed li .order-detailed-left p {
font-size: 3.5vw;
margin-left: 3vw;
}
.wrapper .order-detailed li p {
font-size: 3.5vw;
}
.wrapper .order-deliveryfee {
width: 100%;
height: 16vw;
box-sizing: border-box;
padding: 3vw;
color: #666;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 3.5vw;
}
/****************** 訂單合計(jì)部分 ******************/
.wrapper .total {
width: 100%;
height: 14vw;
position: fixed;
left: 0;
bottom: 0;
display: flex;
}
.wrapper .total .total-left {
flex: 2;
background-color: #505051;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .total .total-right {
flex: 1;
background-color: #38ca73;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
</style>
3.7.OrderList.vue 訂單列表組件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>我的訂單</p>
</header>
<h3>訂單信息:</h3>
<ul class="order">
<li>
<div class="order-info">
<p>
<img src="" >
<span>萬家餃子</span>
</p>
<div class="order-info-right">
<p style="margin-right: 2vw;">¥168</p>
<i v-show="!showDetail" @click="showDetail=!showDetail" class="fa fa-caret-down"></i>
<i v-show="showDetail" @click="showDetail=!showDetail" class="fa fa-caret-up"></i>
</div>
</div>
<ul class="order-detailet" v-show="showDetail">
<li>
<p>蝦仁水餃x 2</p>
<p>¥32</p>
</li>
<li>
<p>配送費(fèi)</p>
<p>¥5</p>
</li>
<li>
<p>下單時間</p>
<p>2025-08-20 15:33:20</p>
</li>
</ul>
</li>
</ul>
<!-- 底部菜單部分 -->
<TabMenu></TabMenu>
</div>
</template>
<script setup>
import { ref,onBeforeMount } from "vue";
import TabMenu from '../components/TabMenu.vue'
import axios from '../api'
import qs from "qs";
let showDetail = ref(false)
</script>
<style scoped>
/****************** 總?cè)萜?******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097ff;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 歷史訂單列表部分 ******************/
.wrapper h3 {
margin-top: 12vw;
box-sizing: border-box;
padding: 4vw;
font-size: 4vw;
font-weight: 300;
color: #999;
}
.wrapper .order {
width: 100%;
}
.wrapper .order li {
width: 95%;
background-color: rgb(209, 237, 196);
margin: 1vh auto;
box-sizing: border-box;
}
.wrapper .order li .order-info {
box-sizing: border-box;
padding: 2vw 4vw;
font-size: 4vw;
color: #666;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .order li .order-info p:first-of-type{
display: flex;
align-items: center;
}
.wrapper .order li .order-info img{
width: 10vw;
height: 10vw;
margin-right: 2vw;
}
.wrapper .order li .order-info .order-info-right {
display: flex;
}
.wrapper .order li .order-info .order-info-right .order-info-right-icon {
background-color: #f90;
color: #fff;
border-radius: 3px;
margin-left: 2vw;
user-select: none;
cursor: pointer;
}
.wrapper .order li .order-detailet {
width: 100%;
}
.wrapper .order li .order-detailet li {
width: 100%;
box-sizing: border-box;
padding: 1vw 4vw;
color: #666;
font-size: 3vw;
display: flex;
justify-content: space-between;
align-items: center;
}
</style>