项目功能演示
1.项目创建目录初始化
vue-cli 建项目
2.安装脚手架 (已安装)
npm i @vue/cli -g
2.创建项目
vue create lch-shopping
- 选项
Vue CLI v5.0.8
? Please pick a preset:
Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
> Manually select features 选自定义
- 手动选择功能
- 选择vue的版本
3.x
> 2.x
- 等待安装,项目初始化完成
- 启动项目
npm run serve
3. 调整初始化目录结构
为了更好的实现后面的操作,我们把整体的目录结构做一些调整。
4. vant组件库及Vue周边的其他组件库
- 路由配置 - 一级路由
-
路由设计:
- 登录页
- 首页架子
- 首页 - 二级
- 分类页 - 二级
- 购物车 - 二级
- 我的 - 二级
- 搜索页
- 搜索列表页
- 商品详情页
- 结算支付页
- 我的订单页
import Vue from "vue";
import VueRouter from "vue-router";
import HomeView from "../views/HomeView.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
// name: "home",
//重定向到登录页
redirect:"/login"
// component: HomeView,
//元数据
// meta:{
// title:"首页",
// isShow:true
// }
},
{
path: "/home",
name: "home",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/HomeView.vue"),
meta:{
title:"首页",
isShow:true
}
},
{
path: "/about",
name: "about",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/AboutView.vue")
},
//路由
{
path: "/Login",
name: "Login",
component: () =>
import(/* webpackChunkName: "about" */ "../views/LoginView.vue"),
meta:{
title:"登录",
isShow:false
}
},
{
path: "/User",
name: "User",
component: () =>
import(/* webpackChunkName: "about" */ "../views/UserView.vue"),
meta:{
title:"用户",
isShow:true
}
},
{
path: "/User2",
name: "User2",
component: () =>
import(/* webpackChunkName: "about" */ "../views/UserView2.vue"),
meta:{
title:"用户列表",
isShow:true
}
},
{
path: "/Order",
name: "order",
component: () =>
import(/* webpackChunkName: "about" */ "../views/OrderView.vue"),
meta:{
title:"订单",
isShow:true
}
},
{
path: "/Shopping",
name: "shopping",
component: () =>
import(/* webpackChunkName: "about" */ "../views/ShoppingView.vue"),
meta:{
title:"商品",
isShow:true
}
}
,
{
path: "/datail",
name: "datail",
component: () =>
import(/* webpackChunkName: "about" */ "../views/DatailView.vue"),
meta:{
title:"详情",
isShow:true
}
}
];
// 初始化路由实例
const router = new VueRouter({
routes,
});
// 导出
export default router;
5. 路由配置-tabbar标签页
6登录页静态布局
.
<template>
<div class="home">
<el-divider></el-divider>
<el-row :gutter="50" class="order-info">
<el-col :span="8">
<div>
<i class="el-icon-date"></i> 今日订单总数<br />
{{orderInfo.today_orders}}
<div class="grid-content"></div>
</div>
</el-col>
<el-col :span="8">
<div>
<i class="el-icon-money"></i>今日销售总额 <br />{{orderInfo.today_total_amount}}
<div class="grid-content"></div>
</div>
</el-col>
<el-col :span="8">
<div>
<i class="el-icon-coin"></i>
昨日销售总额 <br />{{orderInfo.yester_total_amount}}
<div class="grid-content"></div>
</div>
</el-col>
</el-row>
<el-row :gutter="50" class="order-num">
<div><h1>待处理事务</h1></div>
<el-col :span="8">
<div>
<p>已取消订单</p>
<p class="c">{{orderInfo.canceled}}</p>
</div>
</el-col>
<el-col :span="8">
<div>
<p>待付款订单</p>
<p class="p">{{orderInfo.pending}}</p>
</div>
</el-col>
<el-col :span="8">
<div>
<p>待发货订单</p>
<p class="s">{{orderInfo.shipped}}</p>
</div>
</el-col>
<el-col :span="8">
<div>
<p>待确认收货订单</p>
<p class="r">{{orderInfo.received}}</p>
</div>
</el-col>
<el-col :span="8">
<div>
<p>待评价订单</p>
<p class="e">{{orderInfo.evaluated}}</p>
</div>
</el-col>
<el-col :span="8">
<div>
<p>已完成订单</p>
<p class="f">{{orderInfo.finished}}</p>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import axios from 'axios';
// @ is an alias to /src
export default {
name: "HomeView",
data(){
return{
value:5,
orderInfo:{}
};
},
created(){
this.getHomeData();
},
methods:{
//定义一个获取首页数据的方法
//get
getHomeData(){
axios.get("http://106.52.94.26:3001/home/home_data")
.then(res=>{
console.log(res);
//拿到数据后,先把存储在 data
this.orderInfo=res.data.orderInfo;
})
}
},
computed: {},
};
</script>
<style scoped lang="scss">
/* scoped 定义样式的作用域 局部作用域 只对当前页面生效*/
.order-info .el-col {
border: 5px #999;
}
.home {
padding: 0 350px;
.order-info {
margin: 30px;
.el-col > div {
height: 102px;
border: 1px solid #999;
display: flex;
justify-content: center;
align-items: center;
i {
font-size: 30px;
color: rgb(11, 189, 243);
margin-right: 10px;
}
}
}
.order-num {
h1 {
font-size: 20px;
background-color: rgb(204, 219, 219);
}
.el-col {
div {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #999;
padding: 20px;
p {
color: #999;
}
.c {
color: rgb(248, 5, 5);
}
}
}
}
}
</style>
- 登录静态布局
<template>
<div class="login">
<!-- 这是登录页 -->
<div id="big">
<div class="small">
<div class="bq">
<h3>mall-admin</h3>
</div>
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item prop="user">
<el-input placeholder="请输入账号" v-model="ruleForm.user" prefix-icon="el-icon-user-solid"></el-input>
</el-form-item>
<el-form-item prop="pass">
<el-input type="password" placeholder="请输入密码" v-model="ruleForm.pass" autocomplete="off" show-password
prefix-icon="el-icon-lock"></el-input>
</el-form-item>
<el-form-item>
<el-button id="bt" type="primary" @click="submitForm('ruleForm')">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<style>
#big {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.small {
width: 500px;
height: 250px;
box-sizing: border-box;
padding-right: 80px;
background-color: gainsboro;
}
.bq {
text-align: center;
color: blue;
width: 500px;
height: 5vh;
}
#bt {
width: 100%;
}
</style>
<script>
import axios from 'axios';
export default {
name: "LoginView",
data() {
var checkuser = (rule, value, callback) => {
if (value === "") {
return callback(new Error("用户不能为空"));
} else {
if (this.ruleForm.checkuser !== "") {
this.$refs.ruleForm.validateField("checkuser");
}
callback();
}
};
var validatePass = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入密码"));
} else {
if (this.ruleForm.checkPass !== "") {
this.$refs.ruleForm.validateField("checkPass");
}
callback();
}
};
return {
ruleForm: {
pass: "",
},
rules: {
pass: [{ validator: validatePass, trigger: "blur" }],
user: [{ validator: checkuser, trigger: "blur" }],
},
};
},
created() {
this.postuserInfo();
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
axios
.post("http://106.52.94.26:3001/user/login", {
username: this.ruleForm.user, //用户名
password: this.ruleForm.pass, //密码
})
//response
.then((res) => {
console.log(res);
//判断是否成功,跳转首页
if (res.data.msg == "登录成功") {
//登录成功之后,获取到用户信息,用户名、头像、电话…… 存储到本地 s
//如果存储是对象,需要先把对象转化为字符串
localStorage.setItem("userInfo",JSON.stringify(res.data.user))
this.$message({
type: 'success',
message: '登录成功!',
center:true,
showClose:true
});
this.$router.push("/home");
}
})
//接口请求不成功会进入这个catch捕获异常错误的函数里面
.catch(err => {
console.log(err)
if (err.response.data.msg== "用户不存在") {
this.$message({
type: 'error',
message: '用户不存在'
});
}
else {
if (err.response.data.msg== "密码错误") {
this.$message({
type: 'error',
message: '密码错误'
});
}
}
});
} else {
console.log("error submit!!");
return false;
}
});
},
},
};
</script>
封装调用接口获取数据
- 基本渲染
<template>
<table border="1">
<thead>
<th>班级</th>
<th>名字</th>
<th>数学</th>
<th>物理</th>
<th>语文</th>
<th>英语</th>
<th>计算机</th>
<th>化学</th>
<th>总分</th>
</thead>
<tbody id="tbody">
<tr v-for="(item,index) in grade" :key="index">
<td>{{item.class}}</td>
<td @click="toDetail(item.id,item.name)">{{item.name}}</td>
<td>{{item.single_subject[0].score}}</td>
<td>{{item.single_subject[1].score}}</td>
<td>{{item.single_subject[2].score}}</td>
<td>{{item.single_subject[3].score}}</td>
<td>{{item.single_subject[4].score}}</td>
<td>{{item.single_subject[5].score}}</td>
<td>{{item.totalScore}}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
name:"",
data() {
return{
grade: [
{
id: 1,
name: "苏春慧",
class: "外包1",
totalScore: 527,
single_subject: [
{
course: "数学",
score: 85,
},
{
course: "物理",
score: 90,
},
{
course: "语文",
score: 92,
},
{
course: "英语",
score: 93,
},
{
course: "计算机",
score: 87,
},
{
course: "化学",
score: 80,
},
],
},
{
id: 2,
name: "黄文静",
class: "外包1",
totalScore: 486,
single_subject: [
{
course: "数学",
score: 67,
},
{
course: "物理",
score: 77,
},
{
course: "语文",
score: 67,
},
{
course: "英语",
score: 87,
},
{
course: "计算机",
score: 89,
},
{
course: "化学",
score: 99,
},
],
},
{
id: 3,
name: "张蓉蓉",
class: "外包1",
totalScore: 518,
single_subject: [
{
course: "数学",
score: 77,
},
{
course: "物理",
score: 78,
},
{
course: "语文",
score: 89,
},
{
course: "英语",
score: 87,
},
{
course: "计算机",
score: 89,
},
{
course: "化学",
score: 98,
},
],
},
{
id: 4,
name: "卢朝航",
class: "外包2",
totalScore: 518,
single_subject: [
{
course: "数学",
score: 68,
},
{
course: "物理",
score: 87,
},
{
course: "语文",
score: 88,
},
{
course: "英语",
score: 89,
},
{
course: "计算机",
score: 90,
},
{
course: "化学",
score: 96,
},
],
},
{
id: 5,
name: "植玮昊",
class: "外包2",
totalScore: 503,
single_subject: [
{
course: "数学",
score: 76,
},
{
course: "物理",
score: 89,
},
{
course: "语文",
score: 90,
},
{
course: "英语",
score: 97,
},
{
course: "计算机",
score: 93,
},
{
course: "化学",
score: 58,
},
],
},
{
id: 6,
name: "胡广林",
class: "UI1",
totalScore: 506,
single_subject: [
{
course: "数学",
score: 68,
},
{
course: "物理",
score: 67,
},
{
course: "语文",
score: 87,
},
{
course: "英语",
score: 98,
},
{
course: "计算机",
score: 90,
},
{
course: "化学",
score: 96,
},
],
},
{
id: 7,
name: "廖继峰",
class: "UI1",
totalScore: 538,
single_subject: [
{
course: "数学",
score: 87,
},
{
course: "物理",
score: 89,
},
{
course: "语文",
score: 92,
},
{
course: "英语",
score: 97,
},
{
course: "计算机",
score: 85,
},
{
course: "化学",
score: 88,
},
],
},
{
id: 8,
name: "刘志源",
class: "外包1",
totalScore: 571,
single_subject: [
{
course: "数学",
score: 100,
},
{
course: "物理",
score: 99,
},
{
course: "语文",
score: 92,
},
{
course: "英语",
score: 97,
},
{
course: "计算机",
score: 85,
},
{
course: "化学",
score: 98,
},
],
},
],
};
},
methods:{
toDetail(id,name){
this.$router.push(`/datail?id=${id}&name=${name}`)
}
}
};
</script>
<style>
.user{
font-size: 25px;
}
</style>