前端项目学习Vue3项目实战商店后台管理系统

1.课程地址

https://www.bilibili.com/video/BV15v4y1b7Bw/?vd_source=240d9002f7c7e3da63cd9a975639409a#reply151314916928

2. 准备工作(mac)

ncpm 安装 sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
全局安装 vue sudo cnpm i -g vue@next
全局安装 vue/cli sudo cnpm install -g @vue/cli
全局安装yarn sudo cnpm i yarn -g

3.创建项目

vue create shop
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 创建仓库

在码云创建仓库
在这里插入图片描述

https://gitee.com/Blue_Pepsi_Cola/shop

5. reactive、toRefs

reactive 是 Vue3 中提供的实现响应式数据的方法。
链接:https://blog.csdn.net/weixin_44283432/article/details/111190176

toRefs函数的作用是将响应式对象中的所有属性转换为单独的响应式数据,对象成为普通对象,并且值是关联的。
链接:https://blog.csdn.net/lianghecai52171314/article/details/125706376

<template>
  <h1>hello world!</h1>
  <p v-text="name"></p>
  <!-- v-text简写 -->
  <p>{
   
   { age }}</p>
  <p>{
   
   { name}}</p>
</template>

<script>
import {
      
       reactive, toRefs } from "vue";
export default {
      
      
  name: "home",
  setup() {
      
      
    // beforeCreate和created 连接声明周期
    const data = reactive({
      
      
      name: "小红",
      age: 20,
    });

    return {
      
      
      ...toRefs(data)
    };
  },
};
</script>

6. v-if 等

<template>
  <h1>hello world!</h1>
  <p v-text="name"></p>
  <!-- v-text简写 -->
  <p>{
   
   { age }}</p>
  <p>{
   
   { name }}</p>
  <p v-html="info"></p>
  <p v-bind:data="dataVal">我有属性</p>
  <p :class="{ red: isRed }">我是红色的</p>
  <p v-if="isTrue">我是if存在</p>
</template>

<script>
import {
      
       reactive, toRefs } from "vue";
export default {
      
      
  name: "home",
  setup() {
      
      
    // beforeCreate和created 连接声明周期
    const data = reactive({
      
      
      name: "小红",
      age: 20,
      info: "<i>我是斜体字</i>",
      dataVal: 2,
      isRed: true,
      isTrue: true,
    });

    return {
      
      
      ...toRefs(data),
    };
  },
};
</script>
<style>
.red {
      
      
  color: red;
}
</style>

7.生命周期

<template>
  <div>
    <h2>vue3的生命周期</h2>
    <div id="dom">{
   
   { msg }}</div>
  </div>
</template>

<script>
import {
      
      
  reactive,
  toRefs,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
} from "vue";
export default {
      
      
  name: "about",
  setup() {
      
      
    const data = reactive({
      
      
      msg: "你好!",
    });
    // 数据渲染前
    onBeforeMount(() => {
      
      
      console.log("onBeforeMount", document.querySelector("#dom"));
    });
    // 数据渲染后
    onMounted(() => {
      
      
      console.log("onMounted", document.querySelector("#dom"));
      setTimeout(() => {
      
      
        data.msg = "hello";
      }, 8000);
    });
    // dom更新前
    onBeforeUpdate(() => {
      
      
      console.log("onBeforeUpdate");
    });
    //dom更新后
    onUpdated(() => {
      
      
      console.log("onUpdated");
    });
    return {
      
      
      ...toRefs(data),
    };
  },
};
</script>

在这里插入图片描述

8. 事件绑定

8.1 点击事件

<template>
  <div>
    <h2>vue3的生命周期</h2>
    <div id="dom">{
   
   { msg }} -- {
   
   { num }}</div>
    <!-- v-on:事件名="事件方法" 绑定事件 -->
    <!-- 事件及方法直接声明在 setup 内 -->
    <button v-on:click="handleClick">click me</button>
  </div>
</template>

<script>
import {
      
      
  reactive,
  toRefs,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
} from "vue";
export default {
      
      
  name: "about",
  setup() {
      
      
    const data = reactive({
      
      
      msg: "你好!",
    });
    // 数据渲染前
    onBeforeMount(() => {
      
      
      console.log("onBeforeMount", document.querySelector("#dom"));
    });
    // 数据渲染后
    onMounted(() => {
      
      
      console.log("onMounted", document.querySelector("#dom"));
      setTimeout(() => {
      
      
        data.msg = "hello";
      }, 8000);
    });
    // dom更新前
    onBeforeUpdate(() => {
      
      
      console.log("onBeforeUpdate");
    });
    //dom更新后
    onUpdated(() => {
      
      
      console.log("onUpdated");
    });
    // 事件及方法
    const handleClick = () => {
      
      
      alert("Nihao");
    };
    return {
      
      
      ...toRefs(data),
      handleClick,
    };
  },
};
</script>

8.2 input事件

<template>
  <div>
    <h2>vue3的生命周期</h2>
    <div id="dom">{
   
   { msg }} -- {
   
   { num }}</div>
    <!-- v-on:事件名="事件方法" 绑定事件   简写 @:事件名="时间方法"-->
    <!-- 事件及方法直接声明在 setup 内 -->
    <button v-on:click="handleClick">click me</button>
    <hr />
    <!-- v-model 双向绑定 -->
    <!-- input: 输入时间
      blur:失去焦点
      focus:获取焦点
      change: 内容更改-->
    <input type="text" placeholder="请输入姓名" v-model="userName" />
    <input type="text" placeholder="请输入电话号" v-model="userPhone" @:focus="handleFocus" @blur="handleBlur" />
    <textarea
      placeholder="请输入您的建议"
      cols="30"
      rows="10"
      v-model="userInput"
    ></textarea>
    <p>{
   
   { userName }} ---- {
   
   { userInput }}</p>
    <button @click="submit">提交</button>
  </div>
</template>

<script>
import {
      
      
  reactive,
  toRefs,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
} from "vue";
export default {
      
      
  name: "about",
  setup() {
      
      
    const data = reactive({
      
      
      msg: "你好!",
      mesg2: "hello world",
      num: 0,
      userName: "",
      userInput: "",
      userPhone: "",
    });
    // 数据渲染前
    onBeforeMount(() => {
      
      
      console.log("onBeforeMount", document.querySelector("#dom"));
    });
    // 数据渲染后
    onMounted(() => {
      
      
      console.log("onMounted", document.querySelector("#dom"));
      setTimeout(() => {
      
      
        data.msg = "hello";
      }, 8000);
    });
    // dom更新前
    onBeforeUpdate(() => {
      
      
      console.log("onBeforeUpdate");
    });
    //dom更新后
    onUpdated(() => {
      
      
      console.log("onUpdated");
    });
    // 事件及方法
    const handleClick = () => {
      
      
      alert("Nihao");
    };

    const submit = () => {
      
      
      alert(
        `${ 
        data.userName}${ 
        data.userInput}她的电话号码是${ 
        data.userPhone}`
      );
    };
    const handleFocus = () => {
      
      
      console.log("获取焦点");
    };
    const handleBlur = () => {
      
      
      console.log("失去焦点");
    };
    return {
      
      
      ...toRefs(data),
      handleClick,
      submit,
      handleFocus,
      handleBlur
    };
  },
};
</script>

9.路由及路由配置

路由的位置在router下的index.js

  {
    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: "/abc",
    // 页面的名字
    name: "abc",
    // 组件名 通过头部引用
    component: Abc,
  },

其中import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),是懒加载组件,path: "/about"是路由。
在这里插入图片描述
在src下的App.vue引入

<template>
  <nav>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
    <router-link to="/abc">Abc</router-link>
  </nav>
  <router-view/>
</template>

在这里插入图片描述

10. element-plus

1.官网 https://element-plus.gitee.io/zh-CN/
2. 安装

# 选择一个你喜欢的包管理器

# NPM
$ npm install element-plus --save

# Yarn
$ yarn add element-plus

# pnpm
$ pnpm install element-plus

在这里插入图片描述
3.项目引入
在这里插入图片描述
4.布局

<template>
  <div class="common-layout">
    <el-container>
      <el-header>Header</el-header>
      <el-container>
        <el-aside width="200px">Aside</el-aside>
        <el-main>Main</el-main>
      </el-container>
    </el-container>
  </div>
</template>

11. 新的布局及按钮添加

LayOut.vue

<template>
  <div class="common-layout">
    <el-container>
      <el-header class="common-header flex-float">
        <div class="flex">
          <img class="logo" src="../../assets/logo.png" alt="" />
          <h1 class="title">商铺后台管理系统</h1>
        </div>

        <el-button type="danger">退出</el-button>
      </el-header>
      <el-container>
        <el-aside class="common-aside" width="200px"></el-aside>
        <el-main>
          <!-- router-view -->
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
export default {
      
      
  name: "layout",
};
</script>

<style>
    .el-container {
      
      
        height: 100vh;
        overflow: hidden;
    }
    .common-header {
      
      
        background: rgb(48, 55, 65);
    }
    .common-aside {
      
      
        background: rgb(48, 55, 65);
    }
    .logo {
      
      
        width: 80px;
    }
    .title {
      
      
        color: white;
    }
</style>

并在APP.vue中添加

<style>
/* flex布局类名 */
.flex-float {
      
      
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.flex {
      
      
  display: flex;
  align-items: center;
}
</style>

12. icon

安装icon

# 选择一个你喜欢的包管理器

# NPM
$ npm install @element-plus/icons-vue
# Yarn
$ yarn add @element-plus/icons-vue
# pnpm
$ pnpm install @element-plus/icons-vue

安装后需要全局注册图标
在这里插入图片描述

// main.ts

// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

在这里插入图片描述

13. menu

地址: https://element-plus.gitee.io/zh-CN/component/menu.html#%E4%BE%A7%E6%A0%8F

 <!-- el-menu 整个导航 background-color背景颜色-->
          <el-menu background-color="none"
           text-color="#fff" 
           :router="true">
            <!-- 一级导航 -->
            <el-sub-menu index="1">
              <template #title>
                <!-- icon  -->
                <el-icon><Avatar /></el-icon>
                <span>账号管理</span>
              </template>
              <el-menu-item-group>
                <el-menu-item index="/user">账号列表</el-menu-item>
              </el-menu-item-group>
            </el-sub-menu>
            <el-sub-menu index="2">
              <template #title>
                <el-icon><Management /></el-icon>
                <span>角色管理</span>
              </template>
              <el-menu-item-group>
                <el-menu-item index="/roles">账号列表</el-menu-item>
              </el-menu-item-group>
            </el-sub-menu>
          </el-menu>

效果
在这里插入图片描述

14. 登录页面

1.form表单 https://element-plus.gitee.io/zh-CN/component/form.html
2.button

<template>
  <div class="login_wrap"></div>
  <div class="form_wrap">

  <el-form
    ref="formRef"
    :model="loginData"
    label-width="100px"
    class="demo-dynamic"
  >
    <el-form-item
      prop="username"
      label="用户名"
      :rules="[
        {
          required: true,
          message: '此项目为必填项',
          trigger: 'blur',
        },
      ]"
    >
      <el-input v-model="loginData.username" />
    </el-form-item>
  </el-form>

  <el-form
    ref="formRef"
    :model="loginData"
    label-width="100px"
    class="demo-dynamic"
  >
    <el-form-item
      prop="password"
      label="密码"
      :rules="[
        {
          required: true,
          message: '此项目为必填项',
          trigger: 'blur',
        },
      ]"
    >
      <el-input v-model="loginData.password" type="password"/>
    </el-form-item>
  </el-form>
  <el-button type="primary" class="login_bt" >登录</el-button>
</div>
</template>

<script>
import {
      
       reactive, toRefs } from "vue";
export default {
      
      
  name: "login",
  setup() {
      
      
    const data = reactive({
      
      
      loginData: {
      
      
        username: "",
        password: "",
      },
    });
    return {
      
      
      ...toRefs(data),
    };
  },
};
</script>

<style scoped>
.login_wrap {
      
      
  width: 100%;
  height: 100vh;
  background: rgb(28, 76, 166);
  position: relative;
}
.form_wrap {
      
      
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding:30px 50px;
  border-radius: 5px;
}
.login_bt{
      
      
  display: block;
  margin: 10px auto;
}
</style>

15. Vuex

// 后续补充

16. 路由守卫

在router的index.js中
在这里插入图片描述
store/stateuserinfo.state.js
在这里插入图片描述
在store的index.js
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实现输入用户名密码即可登录
在这里插入图片描述
在这里插入图片描述

17. 路由守卫登录状态存储

由于原来用户的登录是通过路由守卫判断uInfo是否存在username属性,即不为空。
但是每次刷新后uInfo为空,就又会跳转回login页面。

在这里插入图片描述在这里插入图片描述


这里在login.vue中通过localStorage.setItem("loginData", JSON.stringify(data.loginData));存储,刷新后不会再清空。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

18.退出功能

在这里插入图片描述
在这里插入图片描述

19.封装axios

19.1 查询axios的所有版本

npm view axios versions --json
安装
在这里插入图片描述
在这里插入图片描述

import axios from "axios";
import { ElLoading } from "element-plus";
import { ElMessage } from "element-plus";
// 使用create创建axios实例
let loadingObj = null;
const Service = axios.create({
  timeOut: 8000,
  baseURL: "http://XXX",
  headers: {
    "content-type": "application/json;charset=utf-8",
  },
});

// 请求拦截 增加loading,对请求做统一处理
Service.interceptors.request.use((config) => {
  loadingObj = ElLoading.service({
    lock: true,
    text: "Loading",
    background: "rgba(0, 0, 0, 0.7)",
  });
  return config;
});

// 响应拦截 对返回值做统一处理
Service.interceptors.response.use(
  (response) => {
    loadingObj.close();
    return response.data;
  },
  (error) => {
    loadingObj.close();
    ElMessage({
      message: "服务器错误",
      type: "error",
      duration: 2000,
    });
  }
);

element-plus加载

message消息提示

20.

// TODO

附录

1.git https://gitee.com/all-about-git
2.完整项目代码 https://github.com/act27/Store-backstage

猜你喜欢

转载自blog.csdn.net/Blue_Pepsi_Cola/article/details/129052128