话不多说,先给出完整代码~~
index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小米商城 By樱雨停后见</title>
<link rel="stylesheet" href="styles.css">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 1. 顶部导航栏 -->
<header class="header">
<!-- 汉堡菜单按钮在logo左侧 -->
<div class="category-toggle" @click="toggleSidebar">
<div class="hamburger"></div>
<div class="hamburger"></div>
<div class="hamburger"></div>
</div>
<div class="logo">
<img src="mi-logo.png" alt="小米Logo" class="logo-img">
<span>小米商城</span>
</div>
<nav class="nav">
<a href="index.html" class="nav-link">首页</a>
<template v-if="isLoggedIn">
<a href="cart.html" class="nav-link">
购物车 <span class="cart-count">({{ cartItems.length }})</span>
</a>
<a href="#" class="nav-link" @click.prevent="logout">退出</a>
</template>
<template v-else>
<a href="login.html" class="nav-link">登录</a>
<a href="register.html" class="nav-link">注册</a>
</template>
</nav>
<div class="mobile-menu" @click="toggleMenu">☰</div>
</header>
<!-- 侧边栏分类 -->
<div class="sidebar" :class="{ 'sidebar-active': sidebarActive }">
<div class="sidebar-header">
<h3>商品分类</h3>
<span class="close-btn" @click="toggleSidebar">×</span>
</div>
<ul class="category-list">
<li :class="{ 'active': selectedCategory === 'all' }" @click="selectCategory('all')">全部商品</li>
<li v-for="category in categories"
:key="category"
:class="{ 'active': selectedCategory === category }"
@click="selectCategory(category)">
{{ category }}
</li>
</ul>
</div>
<div class="sidebar-overlay" v-if="sidebarActive" @click="toggleSidebar"></div>
<!-- 2. 轮播图 -->
<div class="carousel-container">
<div class="carousel-slide" :style="{ transform: `translateX(-${currentSlide * 100}%)` }">
<div v-for="(slide, index) in slides" :key="index" class="slide"
:style="{ backgroundImage: 'url(' + slide.image + ')' }">
<div class="slide-content">
<h2>{{ slide.title }}</h2>
<p>{{ slide.description }}</p>
<button class="slide-button">敬请期待</button>
</div>
</div>
</div>
<button class="carousel-btn prev" @click="prevSlide">❮</button>
<button class="carousel-btn next" @click="nextSlide">❯</button>
<div class="carousel-dots">
<span v-for="(dot, index) in slides" :key="index" :class="{ active: currentSlide === index }"
@click="currentSlide = index">
</span>
</div>
</div>
<!-- 3. 商品展示网格 -->
<div class="product-grid">
<div v-for="product in filteredProducts" :key="product.id" class="product-card">
<img :src="product.image" :alt="product.name" class="product-image">
<div class="product-info">
<h3 class="product-name">{{ product.name }}</h3>
<p class="product-price">¥{{ product.price }}</p>
<button class="add-to-cart" @click="addToCart(product)">加入购物车</button>
</div>
</div>
</div>
<!-- 4. 页脚 -->
<footer class="footer">
<p>© 2025 小米商城 -- 樱雨停后见 | 版权所有</p>
</footer>
</div>
<!-- Vue逻辑 -->
<script>
new Vue({
el: '#app',
data: {
isLoggedIn: localStorage.getItem('isLoggedIn') === 'true',
currentSlide: 0,
slides: [
{ image: 'banner1.jpg', title: '新品上市', description: '小米13 Ultra 限时优惠' },
{ image: 'banner2.jpg', title: '超级促销', description: '智能家居套装直降500元' }
],
categories: ['手机', '家电'],
selectedCategory: 'all',
products: [
{ id: 1, name: '小米13 Pro', price: 4999, image: 'phone.jpg', category: '手机' },
{ id: 2, name: '空气净化器', price: 1299, image: 'air-purifier.jpg', category: '家电' }
],
cartItems: JSON.parse(localStorage.getItem('cart')) || [],
sidebarActive: false
},
computed: {
filteredProducts() {
if (this.selectedCategory === 'all') return this.products;
return this.products.filter(p => p.category === this.selectedCategory);
}
},
methods: {
nextSlide() {
this.currentSlide = (this.currentSlide + 1) % this.slides.length;
},
prevSlide() {
this.currentSlide = (this.currentSlide - 1 + this.slides.length) % this.slides.length;
},
addToCart(product) {
if (!this.isLoggedIn) {
alert('请先登录!');
window.location.href = `login.html?returnUrl=${encodeURIComponent(window.location.href)}`;
return;
}
const existing = this.cartItems.find(item => item.id === product.id);
if (existing) {
existing.quantity++;
} else {
this.cartItems.push({ ...product, quantity: 1 });
}
localStorage.setItem('cart', JSON.stringify(this.cartItems));
alert('已加入购物车!');
},
logout() {
localStorage.removeItem('isLoggedIn');
localStorage.removeItem('cart');
this.isLoggedIn = false;
this.cartItems = [];
alert('已退出登录!');
window.location.reload();
},
toggleMenu() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
},
toggleSidebar() {
this.sidebarActive = !this.sidebarActive;
},
selectCategory(category) {
this.selectedCategory = category;
this.sidebarActive = false;
}
},
mounted() {
setInterval(() => {
this.nextSlide();
}, 3000);
}
});
</script>
</body>
</html>styles.css
/* 基础样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: #f5f5f5;
}
/* 顶部导航栏 */
.header {
background: #ff6700;
padding: 1rem;
display: flex;
align-items: center;
position: fixed;
width: 100%;
top: 0;
z-index: 1000;
}
/* 左侧汉堡菜单 */
.category-toggle {
display: flex;
flex-direction: column;
justify-content: space-around;
width: 30px;
height: 24px;
cursor: pointer;
margin-right: 15px;
}
.hamburger {
width: 100%;
height: 3px;
background: white;
}
/* Logo部分 */
.logo {
display: flex;
align-items: center;
color: white;
flex-grow: 1;
}
.logo-img {
width: 40px;
height: 40px;
margin-right: 10px;
}
/* 右侧导航菜单 */
.nav {
display: flex;
gap: 20px;
}
.nav-link {
color: white;
text-decoration: none;
font-weight: 500;
}
.cart-count {
background: white;
color: #ff6700;
padding: 2px 8px;
border-radius: 12px;
margin-left: 5px;
}
.mobile-menu {
display: none;
color: white;
font-size: 24px;
cursor: pointer;
}
/* 侧边栏样式 */
.sidebar {
position: fixed;
top: 0;
left: -300px;
width: 300px;
height: 100%;
background: white;
box-shadow: 2px 0 10px rgba(0,0,0,0.1);
z-index: 1001;
transition: left 0.3s ease;
overflow-y: auto;
}
.sidebar-active {
left: 0;
}
.sidebar-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
}
.sidebar-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
background: #f5f5f5;
}
.sidebar-header h3 {
margin: 0;
color: #333;
}
.close-btn {
font-size: 24px;
cursor: pointer;
color: #666;
}
.close-btn:hover {
color: #ff6700;
}
.category-list {
list-style: none;
padding: 0;
}
.category-list li {
padding: 15px 20px;
border-bottom: 1px solid #eee;
cursor: pointer;
transition: all 0.2s;
}
.category-list li:hover {
background: #f9f9f9;
color: #ff6700;
}
.category-list li.active {
background: #ff6700;
color: white;
}
/* 轮播图容器 */
.carousel-container {
margin-top: 80px;
width: 100%;
height: 500px;
overflow: hidden;
position: relative;
}
.carousel-slide {
display: flex;
width: 100%;
height: 100%;
transition: transform 0.5s ease;
}
.slide {
flex: 0 0 100%;
height: 100%;
background-size: cover;
background-position: center;
position: relative;
}
.slide-content {
position: absolute;
bottom: 20%;
left: 10%;
color: white;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.slide-button {
padding: 10px 20px;
background: #ff6700;
border: none;
color: white;
cursor: pointer;
margin-top: 10px;
}
/* 商品网格 */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.product-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
transition: transform 0.3s;
}
.product-card:hover {
transform: translateY(-5px);
}
.product-image {
width: 100%;
height: 200px;
object-fit: cover;
}
.product-info {
padding: 15px;
text-align: center;
}
.product-price {
color: #ff6700;
font-size: 18px;
margin: 10px 0;
}
.add-to-cart {
background: #ff6700;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
width: 100%;
}
/* 页脚 */
.footer {
text-align: center;
padding: 20px;
background: #fff;
margin-top: 30px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.nav {
display: none;
}
.mobile-menu {
display: block;
}
.carousel-container {
height: 300px;
}
.product-grid {
grid-template-columns: 1fr;
}
}app.js
new Vue({
el: '#app',
data: {
isLoggedIn: localStorage.getItem('isLoggedIn') === 'true', // 读取登录状态
currentSlide: 0,
slides: [
{
image: 'banner1.jpg',
title: '新品上市',
description: '小米13 Ultra 限时优惠'
},
{
image: 'banner2.jpg',
title: '超级促销',
description: '智能家居套装直降500元'
}
],
categories: ['手机', '家电'],
selectedCategory: 'all',
products: [
{
id: 1,
name: '小米13 Pro',
price: 4999,
image: 'phone.jpg',
category: '手机'
},
{
id: 2,
name: '空气净化器',
price: 1299,
image: 'air-purifier.jpg',
category: '家电'
}
],
cartItems: JSON.parse(localStorage.getItem('cart')) || [],
sidebarActive: false // 新增侧边栏状态
},
computed: {
filteredProducts() {
if (this.selectedCategory === 'all') return this.products;
return this.products.filter(p => p.category === this.selectedCategory);
}
},
methods: {
// 加入购物车逻辑(登录检查)
addToCart(product) {
if (!this.isLoggedIn) {
alert('请先登录!');
window.location.href = 'login.html?returnUrl=' + encodeURIComponent(window.location.href);
return;
}
const existing = this.cartItems.find(item => item.id === product.id);
if (existing) {
existing.quantity++;
} else {
this.cartItems.push({ ...product, quantity: 1 });
}
localStorage.setItem('cart', JSON.stringify(this.cartItems));
alert('已加入购物车!');
},
// 退出登录
logout() {
localStorage.removeItem('isLoggedIn');
this.isLoggedIn = false;
this.cartItems = [];
localStorage.removeItem('cart');
alert('已退出登录!');
},
// 轮播图切换
nextSlide() {
this.currentSlide = (this.currentSlide + 1) % this.slides.length;
},
prevSlide() {
this.currentSlide = (this.currentSlide - 1 + this.slides.length) % this.slides.length;
},
// 移动端菜单切换
toggleMenu() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
},
// 新增侧边栏切换方法
toggleSidebar() {
this.sidebarActive = !this.sidebarActive;
},
// 新增选择分类方法
selectCategory(category) {
this.selectedCategory = category;
this.sidebarActive = false; // 选择后自动关闭侧边栏
}
},
mounted() {
// 轮播图自动播放
setInterval(() => {
this.nextSlide();
}, 3000);
}
});register.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户注册 - 小米商城 By樱雨停后见</title>
<link rel="stylesheet" href="styles.css">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<style>
/* 注册页专属样式 */
.register-container {
max-width: 400px;
margin: 80px auto 20px;
padding: 20px;
}
.register-form {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.form-title {
text-align: center;
color: #ff6700;
margin-bottom: 25px;
}
.form-group {
margin-bottom: 15px;
}
.form-group input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.error-message {
color: #ff4444;
font-size: 12px;
margin-top: 5px;
}
.submit-btn {
width: 100%;
padding: 12px;
background: #ff6700;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
.helper-links {
text-align: center;
margin-top: 15px;
}
.helper-links a {
color: #666;
text-decoration: none;
margin: 0 10px;
}
.helper-links a:hover {
color: #ff6700;
}
</style>
</head>
<body>
<div id="register-app">
<!-- 顶部导航 -->
<header class="header">
<div class="logo">
<img src="mi-logo.png" alt="小米Logo" class="logo-img">
<span>小米商城</span>
</div>
<nav class="nav">
<a href="index.html">首页</a>
<a href="login.html">登录</a>
</nav>
<div class="mobile-menu" @click="toggleMenu">☰</div>
</header>
<!-- 注册表单 -->
<div class="register-container">
<div class="register-form">
<h2 class="form-title">用户注册</h2>
<form @submit.prevent="handleSubmit">
<div class="form-group">
<input type="text"
v-model="username"
placeholder="用户名"
:class="{ 'error-border': errors.username }">
<div class="error-message">{{ errors.username }}</div>
</div>
<div class="form-group">
<input type="tel"
v-model="phone"
placeholder="手机号"
:class="{ 'error-border': errors.phone }">
<div class="error-message">{{ errors.phone }}</div>
</div>
<div class="form-group">
<input type="password"
v-model="password"
placeholder="密码"
:class="{ 'error-border': errors.password }">
<div class="error-message">{{ errors.password }}</div>
</div>
<div class="form-group">
<input type="password"
v-model="confirmPassword"
placeholder="确认密码"
:class="{ 'error-border': errors.confirmPassword }">
<div class="error-message">{{ errors.confirmPassword }}</div>
</div>
<button type="submit" class="submit-btn">立即注册</button>
<div class="helper-links">
<a href="login.html">已有账号?立即登录</a>
</div>
</form>
</div>
</div>
</div>
<script>
new Vue({
el: '#register-app',
data: {
username: '',
phone: '',
password: '',
confirmPassword: '',
errors: {
username: '',
phone: '',
password: '',
confirmPassword: ''
}
},
methods: {
validateForm() {
let isValid = true;
this.errors = {
username: '',
phone: '',
password: '',
confirmPassword: ''
};
// 用户名验证
if (!this.username.trim()) {
this.errors.username = '请输入用户名';
isValid = false;
} else if (this.username.length < 4) {
this.errors.username = '用户名至少4个字符';
isValid = false;
}
// 手机号验证
const phoneRegex = /^1[3-9]\d{9}$/;
if (!this.phone) {
this.errors.phone = '请输入手机号';
isValid = false;
} else if (!phoneRegex.test(this.phone)) {
this.errors.phone = '请输入正确的手机号';
isValid = false;
}
// 密码验证
if (!this.password) {
this.errors.password = '请输入密码';
isValid = false;
} else if (this.password.length < 6) {
this.errors.password = '密码至少需要6位';
isValid = false;
}
// 确认密码验证
if (!this.confirmPassword) {
this.errors.confirmPassword = '请确认密码';
isValid = false;
} else if (this.confirmPassword !== this.password) {
this.errors.confirmPassword = '两次输入的密码不一致';
isValid = false;
}
return isValid;
},
handleSubmit() {
if (!this.validateForm()) return;
// 检查用户名和手机号是否已注册
const users = JSON.parse(localStorage.getItem('registeredUsers')) || [];
if (users.some(user => user.username === this.username)) {
alert('用户名已存在!');
return;
}
if (users.some(user => user.phone === this.phone)) {
alert('手机号已注册!');
return;
}
// 添加新用户
users.push({
username: this.username,
phone: this.phone,
password: this.password
});
localStorage.setItem('registeredUsers', JSON.stringify(users));
alert('注册成功!');
window.location.href = 'login.html';
},
toggleMenu() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
}
}
});
</script>
</body>
</html>login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户登录 By樱雨停后见</title>
<link rel="stylesheet" href="styles.css">
<!-- 引入Font Awesome图标库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<style>
/* 登录页专属样式 */
.login-container {
max-width: 400px;
margin: 80px auto 20px;
padding: 20px;
}
.login-form {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.form-title {
text-align: center;
color: #ff6700;
margin-bottom: 25px;
}
.form-group {
margin-bottom: 15px;
position: relative;
}
.form-group input {
width: 100%;
padding: 10px 40px 10px 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.error-message {
color: #ff4444;
font-size: 12px;
margin-top: 5px;
}
.submit-btn {
width: 100%;
padding: 12px;
background: #ff6700;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
.submit-btn:hover {
background-color: #e55c00;
}
.helper-links {
text-align: center;
margin-top: 15px;
}
.helper-links a {
color: #666;
text-decoration: none;
margin: 0 10px;
transition: color 0.3s;
}
.helper-links a:hover {
color: #ff6700;
}
.password-toggle {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
color: #999;
font-size: 16px;
background: none;
border: none;
padding: 5px;
transition: color 0.3s;
}
.password-toggle:hover {
color: #666;
}
.password-toggle i {
display: block;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
}
/* 响应式设计 */
@media (max-width: 480px) {
.login-container {
margin: 60px 15px 20px;
padding: 15px;
}
.login-form {
padding: 20px;
}
.form-title {
font-size: 20px;
margin-bottom: 20px;
}
.helper-links a {
display: block;
margin: 10px 0;
}
}
</style>
</head>
<body>
<div id="login-app">
<!-- 顶部导航 -->
<header class="header">
<div class="logo">
<img src="mi-logo.png" alt="小米Logo" class="logo-img">
<span>小米商城</span>
</div>
<nav class="nav">
<a href="index.html">首页</a>
<a href="register.html">注册</a>
</nav>
<div class="mobile-menu" @click="toggleMenu">☰</div>
</header>
<!-- 登录表单 -->
<div class="login-container">
<div class="login-form">
<h2 class="form-title">用户登录</h2>
<form @submit.prevent="handleSubmit">
<div class="form-group">
<input type="text"
v-model="loginInput"
placeholder="用户名/手机号"
:class="{ 'error-border': errors.loginInput }">
<div class="error-message">{{ errors.loginInput }}</div>
</div>
<div class="form-group">
<input :type="showPassword ? 'text' : 'password'"
v-model="password"
placeholder="密码"
:class="{ 'error-border': errors.password }">
<button type="button"
class="password-toggle"
@click="showPassword = !showPassword">
<i :class="showPassword ? 'far fa-eye-slash' : 'far fa-eye'"></i>
</button>
<div class="error-message">{{ errors.password }}</div>
</div>
<button type="submit" class="submit-btn">
<i class="fas fa-sign-in-alt"></i> 立即登录
</button>
</form>
<div class="helper-links">
<a href="change-password.html"><i class="fas fa-key"></i> 重置密码</a>
<a href="register.html"><i class="fas fa-user-plus"></i> 注册新账号</a>
</div>
</div>
</div>
</div>
<script>
new Vue({
el: '#login-app',
data: {
loginInput: '',
password: '',
showPassword: false,
errors: {
loginInput: '',
password: ''
}
},
methods: {
validateForm() {
let isValid = true;
this.errors = { loginInput: '', password: '' };
// 登录账号验证
if (!this.loginInput.trim()) {
this.errors.loginInput = '请输入用户名或手机号';
isValid = false;
}
// 密码验证
if (!this.password) {
this.errors.password = '密码不能为空';
isValid = false;
} else if (this.password.length < 6) {
this.errors.password = '密码至少需要6位';
isValid = false;
}
return isValid;
},
handleSubmit() {
if (this.validateForm()) {
// 模拟登录验证:检查 localStorage 中的注册用户
const users = JSON.parse(localStorage.getItem('registeredUsers')) || [];
const matchedUser = users.find(user =>
(user.username === this.loginInput || user.phone === this.loginInput) &&
user.password === this.password
);
if (matchedUser) {
// 登录成功:设置登录状态并跳转
localStorage.setItem('isLoggedIn', 'true');
localStorage.setItem('currentUser', JSON.stringify({
username: matchedUser.username,
phone: matchedUser.phone
}));
const returnUrl = new URLSearchParams(window.location.search).get('returnUrl');
window.location.href = returnUrl || 'index.html';
} else {
alert('用户名/手机号或密码错误!');
}
}
},
toggleMenu() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
}
}
});
</script>
</body>
</html>change-password.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>修改密码 - 小米商城 By樱雨停后见</title>
<link rel="stylesheet" href="styles.css">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<style>
/* 修改密码页专属样式 */
.change-password-container {
max-width: 400px;
margin: 80px auto 20px;
padding: 20px;
}
.change-password-form {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.form-title {
text-align: center;
color: #ff6700;
margin-bottom: 25px;
}
.form-group {
margin-bottom: 15px;
position: relative;
}
.form-group input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.error-message {
color: #ff4444;
font-size: 12px;
margin-top: 5px;
}
.submit-btn {
width: 100%;
padding: 12px;
background: #ff6700;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-top: 10px;
}
.helper-links {
text-align: center;
margin-top: 15px;
}
.helper-links a {
color: #666;
text-decoration: none;
margin: 0 10px;
}
.helper-links a:hover {
color: #ff6700;
}
.password-toggle {
position: absolute;
right: 10px;
top: 10px;
cursor: pointer;
color: #999;
font-size: 14px;
}
.password-toggle:hover {
color: #666;
}
.password-strength {
height: 4px;
background: #eee;
margin-top: 8px;
border-radius: 2px;
overflow: hidden;
}
.strength-bar {
height: 100%;
width: 0;
transition: width 0.3s;
}
.strength-weak {
background: #ff4444;
}
.strength-medium {
background: #ff9500;
}
.strength-strong {
background: #4CAF50;
}
</style>
</head>
<body>
<div id="change-password-app">
<!-- 顶部导航 -->
<header class="header">
<div class="logo">
<img src="mi-logo.png" alt="小米Logo" class="logo-img">
<span>小米商城</span>
</div>
<nav class="nav">
<a href="index.html">首页</a>
<a href="login.html">登录</a>
<a href="register.html">注册</a>
</nav>
<div class="mobile-menu" @click="toggleMenu">☰</div>
</header>
<!-- 修改密码表单 -->
<div class="change-password-container">
<div class="change-password-form">
<h2 class="form-title">修改密码</h2>
<form @submit.prevent="handleSubmit">
<div class="form-group">
<input type="text"
v-model="username"
placeholder="用户名"
:class="{ 'error-border': errors.username }">
<div class="error-message">{{ errors.username }}</div>
</div>
<div class="form-group">
<input :type="showCurrentPassword ? 'text' : 'password'"
v-model="currentPassword"
placeholder="当前密码"
:class="{ 'error-border': errors.currentPassword }">
<div class="error-message">{{ errors.currentPassword }}</div>
</div>
<div class="form-group">
<input :type="showNewPassword ? 'text' : 'password'"
v-model="newPassword"
placeholder="新密码"
@input="checkPasswordStrength"
:class="{ 'error-border': errors.newPassword }">
<div class="password-strength">
<div class="strength-bar" :class="passwordStrengthClass"
:style="{ width: passwordStrength + '%' }"></div>
</div>
<div class="error-message">{{ errors.newPassword }}</div>
</div>
<div class="form-group">
<input :type="showConfirmPassword ? 'text' : 'password'"
v-model="confirmPassword"
placeholder="确认新密码"
:class="{ 'error-border': errors.confirmPassword }">
<div class="error-message">{{ errors.confirmPassword }}</div>
</div>
<button type="submit" class="submit-btn">确认修改</button>
<div class="helper-links">
<a href="login.html">返回登录</a>
</div>
</form>
</div>
</div>
</div>
<script>
new Vue({
el: '#change-password-app',
data: {
username: '',
currentPassword: '',
newPassword: '',
confirmPassword: '',
showCurrentPassword: false,
showNewPassword: false,
showConfirmPassword: false,
passwordStrength: 0,
errors: {
username: '',
currentPassword: '',
newPassword: '',
confirmPassword: ''
}
},
computed: {
passwordStrengthClass() {
if (this.passwordStrength < 30) return 'strength-weak';
if (this.passwordStrength < 70) return 'strength-medium';
return 'strength-strong';
}
},
methods: {
checkPasswordStrength() {
// 简单的密码强度计算
let strength = 0;
const password = this.newPassword;
if (password.length === 0) {
this.passwordStrength = 0;
return;
}
// 长度加分
strength += Math.min(password.length * 5, 30);
// 包含数字加分
if (/\d/.test(password)) strength += 10;
// 包含小写字母加分
if (/[a-z]/.test(password)) strength += 10;
// 包含大写字母加分
if (/[A-Z]/.test(password)) strength += 10;
// 包含特殊字符加分
if (/[^a-zA-Z0-9]/.test(password)) strength += 10;
// 确保不超过100
this.passwordStrength = Math.min(strength, 100);
},
validateForm() {
let isValid = true;
this.errors = {
username: '',
currentPassword: '',
newPassword: '',
confirmPassword: ''
};
// 用户名验证
if (!this.username) {
this.errors.username = '请输入用户名';
isValid = false;
}
// 当前密码验证
if (!this.currentPassword) {
this.errors.currentPassword = '请输入当前密码';
isValid = false;
}
// 新密码验证
if (!this.newPassword) {
this.errors.newPassword = '请输入新密码';
isValid = false;
} else if (this.newPassword.length < 6) {
this.errors.newPassword = '密码至少需要6位';
isValid = false;
} else if (this.newPassword === this.currentPassword) {
this.errors.newPassword = '新密码不能与当前密码相同';
isValid = false;
}
// 确认密码验证
if (!this.confirmPassword) {
this.errors.confirmPassword = '请确认新密码';
isValid = false;
} else if (this.confirmPassword !== this.newPassword) {
this.errors.confirmPassword = '两次输入的密码不一致';
isValid = false;
}
return isValid;
},
handleSubmit() {
if (!this.validateForm()) return;
// 获取用户数据
const users = JSON.parse(localStorage.getItem('registeredUsers')) || [];
const userIndex = users.findIndex(user => user.username === this.username);
if (userIndex === -1) {
alert('用户名不存在!');
return;
}
// 验证当前密码
if (users[userIndex].password !== this.currentPassword) {
alert('当前密码不正确!');
return;
}
// 更新密码
users[userIndex].password = this.newPassword;
localStorage.setItem('registeredUsers', JSON.stringify(users));
alert('密码修改成功!');
window.location.href = 'login.html';
},
toggleMenu() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
}
}
});
</script>
</body>
</html>cart.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>购物车 - 小米商城 By樱雨停后见</title>
<link rel="stylesheet" href="styles.css" />
<!-- Vue.js CDN -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- Lodash 用于节流 -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<style>
/* 购物车页专属样式 */
.cart-container {
max-width: 1200px;
margin: 80px auto 20px;
padding: 20px;
}
.cart-header {
text-align: center;
color: #ff6700;
margin-bottom: 30px;
}
.cart-item {
display: flex;
align-items: center;
padding: 20px;
background: white;
border-radius: 8px;
margin-bottom: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.item-image {
width: 120px;
height: 120px;
object-fit: cover;
margin-right: 20px;
}
.item-info {
flex: 1;
}
.item-name {
font-size: 18px;
margin-bottom: 10px;
}
.item-price {
color: #ff6700;
font-weight: bold;
}
.quantity-control {
display: flex;
align-items: center;
gap: 10px;
}
.quantity-btn {
width: 30px;
height: 30px;
border: 1px solid #ddd;
background: white;
cursor: pointer;
border-radius: 4px;
}
.quantity-btn:hover {
background: #f5f5f5;
}
.delete-btn {
background: #ff4444;
color: white;
border: none;
padding: 8px 15px;
border-radius: 4px;
cursor: pointer;
}
.total-section {
text-align: right;
padding: 20px;
background: white;
border-radius: 8px;
margin-top: 20px;
}
.checkout-btn {
background: #ff6700;
color: white;
border: none;
padding: 15px 40px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
.empty-cart {
text-align: center;
padding: 40px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.empty-cart img {
width: 100px;
margin-bottom: 15px;
}
/* 移动端适配 */
@media (max-width: 768px) {
.cart-item {
flex-direction: column;
align-items: flex-start;
}
.item-image {
width: 100%;
height: auto;
margin-bottom: 15px;
}
.quantity-control {
margin-top: 10px;
}
}
</style>
</head>
<body>
<div id="cart-app">
<!-- 顶部导航 -->
<header class="header">
<div class="logo">
<img src="mi-logo.png" alt="小米Logo" class="logo-img" />
<span>小米商城</span>
</div>
<nav class="nav">
<a href="index.html">首页</a>
<a href="cart.html">购物车 ({{ cartItems.length }})</a>
</nav>
<div class="mobile-menu" @click="toggleMenu">☰</div>
</header>
<!-- 登录状态判断 -->
<div v-if="isLoggedIn">
<div class="cart-container">
<h1 class="cart-header">我的购物车</h1>
<template v-if="cartItems.length === 0">
<div class="empty-cart">
<p>购物车空空如也,快去首页选购吧!</p>
</div>
</template>
<template v-else>
<!-- 商品列表 -->
<div v-for="(item, index) in cartItems" :key="item.id" class="cart-item">
<img :src="item.image" class="item-image" />
<div class="item-info">
<h3 class="item-name">{{ item.name }}</h3>
<p class="item-price">单价:¥{{ item.price }}</p>
<div class="quantity-control">
<button class="quantity-btn" @click="decreaseQuantity(index)">-</button>
<span>{{ item.quantity }}</span>
<button class="quantity-btn" @click="increaseQuantity(index)">+</button>
</div>
</div>
<button class="delete-btn" @click="removeItem(index)">删除</button>
</div>
<!-- 结算栏 -->
<div class="total-section">
<p>共 {{ totalItems }} 件商品</p>
<p>总价:<span class="item-price">¥{{ totalPrice }}</span></p>
<button class="checkout-btn" @click="goToCheckout()">去结算</button>
</div>
</template>
</div>
</div>
<div v-else class="empty-cart">
<img src="images/lock-icon.png" alt="请登录" />
<p>请先登录以查看购物车!</p>
<a href="login.html?returnUrl={{ encodeURIComponent(window.location.href) }}" class="confirm-btn">前往登录</a>
</div>
</div>
<script>
new Vue({
el: '#cart-app',
data: {
cartItems: JSON.parse(localStorage.getItem('cart')) || [],
isLoggedIn: localStorage.getItem('isLoggedIn') === 'true'
},
computed: {
totalPrice() {
return this.cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0);
},
totalItems() {
return this.cartItems.reduce((sum, item) => sum + item.quantity, 0);
}
},
methods: {
increaseQuantity(index) {
this.cartItems[index].quantity++;
this.updateStorage();
},
decreaseQuantity(index) {
if (this.cartItems[index].quantity > 1) {
this.cartItems[index].quantity--;
} else {
if (confirm('确定要从购物车中移除该商品吗?')) {
this.removeItem(index);
}
}
this.updateStorage();
},
removeItem(index) {
this.cartItems.splice(index, 1);
this.updateStorage();
},
updateStorage: _.throttle(function () {
localStorage.setItem('cart', JSON.stringify(this.cartItems));
}, 500),
toggleMenu() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
},
goToCheckout() {
if (this.cartItems.length === 0) {
alert('购物车为空,无法结算!');
return;
}
window.location.href = "checkout.html";
}
}
});
</script>
</body>
</html>checkout.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>订单确认 - 小米商城 By樱雨停后见</title>
<link rel="stylesheet" href="styles.css">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<style>
/* 订单确认页专属样式 */
.checkout-container {
max-width: 1200px;
margin: 100px auto 40px;
padding: 0 20px;
}
.checkout-header {
text-align: center;
color: #ff6700;
margin-bottom: 30px;
font-size: 28px;
}
.checkout-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 30px;
}
.address-form,
.payment-method,
.order-summary {
background: white;
padding: 25px;
border-radius: 8px;
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 20px;
margin-bottom: 20px;
color: #333;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #666;
}
.form-group input,
.form-group select {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
transition: border 0.3s;
}
.form-group input:focus,
.form-group select:focus {
border-color: #ff6700;
outline: none;
}
.order-item {
display: flex;
justify-content: space-between;
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px dashed #eee;
}
.total-price {
font-size: 20px;
color: #ff6700;
font-weight: bold;
text-align: right;
margin-top: 25px;
padding-top: 15px;
border-top: 2px solid #ff6700;
}
.confirm-btn {
width: 100%;
padding: 15px;
background: #ff6700;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
margin-top: 25px;
transition: background 0.3s;
}
.confirm-btn:hover {
background: #ff4500;
}
@media (max-width: 768px) {
.checkout-grid {
grid-template-columns: 1fr;
}
.checkout-container {
margin-top: 80px;
padding: 0 15px;
}
}
</style>
</head>
<body>
<div id="checkout-app">
<!-- 顶部导航 -->
<header class="header">
<div class="logo">
<img src="mi-logo.png" alt="小米Logo" class="logo-img">
<span>小米商城</span>
</div>
<nav class="nav">
<a href="index.html">首页</a>
<a href="cart.html">购物车</a>
<a href="#" @click.prevent="logout">退出</a>
</nav>
<div class="mobile-menu" @click="toggleMenu">☰</div>
</header>
<!-- 订单确认内容 -->
<div class="checkout-container">
<h1 class="checkout-header">订单确认</h1>
<div class="checkout-grid">
<!-- 左侧:收货地址和支付方式 -->
<div class="left-section">
<div class="address-form">
<h2 class="section-title">收货地址</h2>
<form @submit.prevent="submitOrder">
<div class="form-group">
<label>收货人姓名</label>
<input type="text" v-model="address.name" required placeholder="请输入收货人姓名">
</div>
<div class="form-group">
<label>联系电话</label>
<input type="tel" v-model="address.phone" required placeholder="请输入联系电话">
</div>
<div class="form-group">
<label>详细地址</label>
<input type="text" v-model="address.detail" required placeholder="请输入详细地址">
</div>
<div class="payment-method">
<h2 class="section-title">支付方式</h2>
<div class="form-group">
<select v-model="paymentMethod" required>
<option value="">请选择支付方式</option>
<option value="alipay">支付宝</option>
<option value="wechat">微信支付</option>
<option value="bank">银行卡</option>
</select>
</div>
</div>
<button type="submit" class="confirm-btn">提交订单</button>
</form>
</div>
</div>
<!-- 右侧:订单摘要 -->
<div class="right-section">
<div class="order-summary">
<h2 class="section-title">订单摘要</h2>
<div v-for="item in cartItems" :key="item.id" class="order-item">
<span>{{ item.name }} ×{{ item.quantity }}</span>
<span>¥{{ (item.price * item.quantity).toFixed(2) }}</span>
</div>
<div class="total-price">
总价:¥{{ totalPrice.toFixed(2) }}
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 登录和购物车检查
document.addEventListener('DOMContentLoaded', function() {
const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';
if (!isLoggedIn) {
alert('请先登录!');
window.location.href = 'login.html?returnUrl=' + encodeURIComponent('checkout.html');
return;
}
const cart = JSON.parse(localStorage.getItem('cart')) || [];
if (cart.length === 0) {
alert('购物车为空,无法结算!');
window.location.href = 'cart.html';
}
});
new Vue({
el: '#checkout-app',
data: {
isLoggedIn: localStorage.getItem('isLoggedIn') === 'true',
cartItems: JSON.parse(localStorage.getItem('cart')) || [],
address: {
name: localStorage.getItem('lastAddressName') || '',
phone: localStorage.getItem('lastAddressPhone') || '',
detail: localStorage.getItem('lastAddressDetail') || ''
},
paymentMethod: localStorage.getItem('lastPaymentMethod') || ''
},
computed: {
totalPrice() {
return this.cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
},
methods: {
submitOrder() {
// 表单验证
if (!this.address.name || !this.address.phone || !this.address.detail || !this.paymentMethod) {
alert('请填写完整的收货地址和支付方式!');
return;
}
// 保存地址信息以便下次使用
localStorage.setItem('lastAddressName', this.address.name);
localStorage.setItem('lastAddressPhone', this.address.phone);
localStorage.setItem('lastAddressDetail', this.address.detail);
localStorage.setItem('lastPaymentMethod', this.paymentMethod);
// 生成订单数据
const order = {
id: 'DD' + Date.now().toString(),
date: new Date().toLocaleString(),
items: this.cartItems,
address: {...this.address},
paymentMethod: this.paymentMethod,
totalPrice: this.totalPrice,
status: '待付款'
};
// 存储订单
const orders = JSON.parse(localStorage.getItem('orders')) || [];
orders.push(order);
localStorage.setItem('orders', JSON.stringify(orders));
// 清空购物车
localStorage.removeItem('cart');
this.cartItems = [];
// 跳转到订单完成页
window.location.href = `order-success.html?orderId=${order.id}`;
},
logout() {
localStorage.removeItem('isLoggedIn');
window.location.href = 'login.html';
},
toggleMenu() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
}
}
});
</script>
</body>
</html>order-success.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>订单提交成功 - 小米商城 By樱雨停后见</title>
<link rel="stylesheet" href="styles.css">
<style>
/* 订单成功页专属样式 */
.success-container {
max-width: 600px;
margin: 100px auto;
padding: 40px;
text-align: center;
background: white;
border-radius: 8px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
}
.success-icon {
font-size: 80px;
color: #4CAF50;
margin-bottom: 25px;
}
.success-message {
font-size: 24px;
color: #333;
margin-bottom: 20px;
font-weight: 500;
}
.order-info {
background: #f9f9f9;
padding: 20px;
border-radius: 6px;
margin: 25px 0;
text-align: left;
}
.order-info p {
margin: 10px 0;
color: #666;
}
.order-id {
color: #ff6700;
font-weight: bold;
font-size: 18px;
}
.action-buttons {
margin-top: 30px;
display: flex;
justify-content: center;
gap: 15px;
}
.back-to-home, .view-order {
display: inline-block;
padding: 12px 25px;
border-radius: 4px;
text-decoration: none;
font-size: 16px;
transition: all 0.3s;
}
.back-to-home {
background: #ff6700;
color: white;
}
.back-to-home:hover {
background: #ff4500;
}
.view-order {
background: white;
color: #ff6700;
border: 1px solid #ff6700;
}
.view-order:hover {
background: #fff8f5;
}
@media (max-width: 768px) {
.success-container {
margin: 80px 15px;
padding: 25px;
}
.action-buttons {
flex-direction: column;
gap: 10px;
}
.back-to-home, .view-order {
width: 100%;
}
}
</style>
</head>
<body>
<!-- 顶部导航 -->
<header class="header">
<div class="logo">
<img src="mi-logo.png" alt="小米Logo" class="logo-img">
<span>小米商城</span>
</div>
<nav class="nav">
<a href="index.html">首页</a>
<a href="cart.html">购物车</a>
</nav>
<div class="mobile-menu" id="mobile-menu-btn">☰</div>
</header>
<!-- 订单成功内容 -->
<div class="success-container">
<div class="success-icon">✓</div>
<h1 class="success-message">订单提交成功!</h1>
<div class="order-info">
<p>订单编号:<span class="order-id" id="order-id"></span></p>
<p>支付方式:<span id="payment-method"></span></p>
<p>订单金额:<span id="order-total"></span></p>
<p>收货地址:<span id="delivery-address"></span></p>
</div>
<div class="action-buttons">
<a href="index.html" class="back-to-home">返回首页</a>
</div>
</div>
<script>
// 登录状态检查
document.addEventListener('DOMContentLoaded', function() {
const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';
if (!isLoggedIn) {
alert('请先登录!');
window.location.href = 'login.html';
return;
}
// 获取订单ID
const urlParams = new URLSearchParams(window.location.search);
const orderId = urlParams.get('orderId');
if (!orderId) {
alert('订单参数无效!');
window.location.href = 'index.html';
return;
}
// 显示订单信息
const orders = JSON.parse(localStorage.getItem('orders')) || [];
const order = orders.find(o => o.id === orderId);
if (order) {
document.getElementById('order-id').textContent = order.id;
document.getElementById('payment-method').textContent =
order.paymentMethod === 'alipay' ? '支付宝' :
order.paymentMethod === 'wechat' ? '微信支付' : '银行卡';
document.getElementById('order-total').textContent = '¥' + order.totalPrice.toFixed(2);
document.getElementById('delivery-address').textContent =
`${order.address.name} ${order.address.phone} ${order.address.detail}`;
// 设置查看订单按钮链接
document.getElementById('view-order-btn').href = `order-detail.html?orderId=${order.id}`;
} else {
alert('订单不存在!');
window.location.href = 'index.html';
}
// 退出登录
document.getElementById('logout-btn').addEventListener('click', function(e) {
e.preventDefault();
localStorage.removeItem('isLoggedIn');
window.location.href = 'login.html';
});
// 移动端菜单
document.getElementById('mobile-menu-btn').addEventListener('click', function() {
const nav = document.querySelector('.nav');
nav.style.display = nav.style.display === 'flex' ? 'none' : 'flex';
});
});
</script>
</body>
</html>
附:以下是图片样例
phone.jpg
air.purifier.jpg
banner1.jpg
banner2.jpg
mi-logo.png 请自行查找
2025年10月
不错
好
好
好