开始尝试从0写一个项目--前端(一)

基础项目构建

创建VUE初始工程

确保自己下载了node.js和npm

node -v     //查看node.js的版本
npm -v      //查看npm的版本
npm i @vue/cli -g    //安装VUE CLI

创建

以管理员身份运行

输入:vue ui

就会进入

点击创建

自定义项目名字,选择npm管理

结构

用vscode打开这个项目

运行

打开终端

快捷键:ctrl+j

输入npm run serve回车

然后进入给的网址

修改端口

vue.config.js

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 8181
  }
})

现在我们就是在这个界面开始编写我们的代码

2024.7.4


学生登录界面

参考这篇文章

Vue 实现登录注册功能(前后端分离完整案例) | 软件研会

参考文章中遇到的一些问题

问题:解决error: Component name "xxx" should always be multi-word.

解决:

解决error: Component name "xxx" should always be multi-word._error component name "about" should always be mult-CSDN博客

问题:import VueAxios from 'vue-axios'中vue-axios找不到报错

解决:

npm i vue-axios

问题:点击登录之后,一直网页报错

解决措施:(麻了,我各种翻阅资料,居然是这里出错了,气死了!!!!!!!花费了我2小时)

src\views\login\Login.vue

问题基本搞定,还有一些小细节:

我们不需要注册这个版本,所以我没有搞。

基本就ok了

所有的代码:

src\App.vue

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>


export default {
  name: 'App',
  components: {
  }
}
</script>


<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
</style>

src\main.js

import Vue from 'vue'
import App from './App.vue'
import store from './store'

import router from './router'      //路由 2
import VueRouter from 'vue-router' // 路由 1

import ElementUI from 'element-ui';	// Element 1
import 'element-ui/lib/theme-chalk/index.css'; // Element 2

import axios from 'axios'  
import VueAxios from 'vue-axios'



// 关闭 Vue 的生产提示
Vue.config.productionTip = false

// 使用插件
Vue.use(ElementUI); // Element 3
Vue.use(VueRouter) // 路由 3
Vue.use(VueAxios, axios) // 使用 axios 插件

// 创建 Vue 实例对象
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

vue.config.js

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave: false,
  devServer: {
    port: 8181,
    // 代理服务器可以将路由中的指定前缀转发到指定的后端服务器中
    proxy: {
      '/api': {
          target: 'http://localhost:8080',
          ws: true, // 是否启用websockets
          changeOrigin: true,  // 代理时是否更改host
          pathRewrite: {
              '^/api': '' //这里理解成用'/api'代替target里面的地址
          }
      }
  }
  }
})

src\views\login\Login.vue

<template>
  <div>
    <el-card class="box-card">
      <h2>登录</h2>
      <el-form
        :model="ruleForm"
        status-icon
        :rules="rules"
        ref="ruleForm"
        label-position="left"
        label-width="70px"
        class="login-from"
      >
        <el-form-item label="用户名" prop="username">
          <el-input v-model="ruleForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="ruleForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
      </el-form>
      <div class="btnGroup">
        <el-button
          type="primary"
          @click="submitForm('ruleForm')"
          v-loading="loading"
          >登录</el-button
        >
        <el-button @click="resetForm('ruleForm')">重置</el-button>
        <router-link to="/register">
          <el-button style="margin-left: 10px">注册</el-button>
        </router-link>
      </div>
    </el-card>
  </div>
</template>

<script>

export default {
  data() {
    return {
      ruleForm: {
        username: "",
        password: "",
      },
      rules: {
        username: [
          { required: true, message: "用户名不能为空!", trigger: "blur" },
        ],
        password: [
          { required: true, message: "密码不能为空!", trigger: "blur" },
        ],
      },
      loading: false, // 是否显示加载动画
    };
  },
  methods: {
    submitForm(formName) {
      // 验证表单中的账号密码是否有效,因为在上面rules中定义为了必填 required: true
      this.$refs[formName].validate((valid) => {
        // 点击登录后,让登录按钮开始转圈圈(展示加载动画)
        this.loading = true;
        // 如果经过校验,账号密码都不为空,则发送请求到后端登录接口
        if (valid) {
          let _this = this;
          // 使用 axios 将登录信息发送到后端
          this.axios({
            url: "/api/admin/student/login",               // 请求地址
            method: "post",                       // 请求方法
            headers: {                            // 请求头
              "Content-Type": "application/json",
            },
            data: {                             // 请求参数
              username: _this.ruleForm.username,
              password: _this.ruleForm.password,
            },
          }).then((res) => { // 当收到后端的响应时执行该括号内的代码,res 为响应信息,也就是后端返回的信息
            if (res.data.code === 1) {  // 当响应的编码为 1 时,说明登录成功
              // 将用户信息存储到sessionStorage中
              sessionStorage.setItem("userInfo", JSON.stringify(res.data.data));
              // 跳转页面到首页
              this.$router.push('/home');
              // 显示后端响应的成功信息
              this.$message({
                message: res.data.data,
                type: "success",
              });
            } else {  // 当响应的编码不为 1 时,说明登录失败
              // 显示后端响应的失败信息
              this.$message({
                message: res.data.msg,
                type: "warning",
              });
            }
            // 不管响应成功还是失败,收到后端响应的消息后就不再让登录按钮显示加载动画了
            _this.loading = false;
            console.log(res);
          });
        } else {  // 如果账号或密码有一个没填,就直接提示必填,不向后端请求
          console.log("error submit!!");
          this.loading = false;
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
  },
};
</script>

<style scoped>
/* 设置登录面板居中,宽度为400px */
.box-card {
  margin: auto auto;
  width: 400px;
}
/* 设置登录面板中的表单居中 */
.login-from {
  margin: auto auto;
}
</style>

src\views\home\Home.vue

<template>
  <div>
    <h2>欢迎{{ user.username }}!您的 uid 为{{ user.id }}</h2>
    <el-button @click="logout"> 登出 </el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        username: "",
        id: null,
      },
    };
  },
  methods: {
    logout(){
      // 移除本地用户登录信息
      sessionStorage.removeItem('userInfo');
      // 跳转页面到登录页
      this.$router.push('/login');
    }
  },
  mounted() {
    if (sessionStorage.getItem('userInfo')) {
      // 将用户信息存储到sessionStorage中
      this.user = JSON.parse(sessionStorage.getItem('userInfo'));
    }
  },
};
</script>

<style scoped>
</style>

src\router\index.js

// 此文件专门负责项目的路由

import VueRouter from "vue-router"

// 引入组件
import Login from '../views/login/Login'
import Register from '@/views/register/Register.vue'
import Home from '@/views/home/Home.vue'

// 创建并暴露一个路由器
export default new VueRouter({
    mode: 'history',    // 路由模式,该模式不会在地址中显示井号#
    routes: [
        {
            path: '/',          // 路径
            redirect: '/login'  // 重定向
        },
        {
            path: '/login',     // 路径
            component: Login    // 跳转到的组件
        },
        {
            path: '/register',     // 路径
            component: Register    // 跳转到的组件
        },
        {
            path: '/home',     // 路径
            component: Home    // 跳转到的组件
        }

    ]
})

修改一下登录界面

去掉注册功能

src\views\login\Login.vue

删除红色框部分

src\views\register

src\router\index.js

添加背景图片

src\views\login\Login.vue

测试

完整代码

src\views\login\Login.vue

<template>
  <div class="login-background">
    <el-card class="box-card">
      <h2>体育器材管理后台</h2>
      <el-form
        :model="ruleForm"
        status-icon
        :rules="rules"
        ref="ruleForm"
        label-position="left"
        label-width="70px"
        class="login-from"
      >
        <el-form-item label="用户名" prop="username">
          <el-input v-model="ruleForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input
            type="password"
            v-model="ruleForm.password"
            autocomplete="off"
          ></el-input>
        </el-form-item>
      </el-form>
      <div class="btnGroup">
        <el-button
          type="primary"
          @click="submitForm('ruleForm')"
          v-loading="loading"
          >登录</el-button
        >
        <el-button @click="resetForm('ruleForm')">重置</el-button>
      </div>
    </el-card>
  </div>
</template>

<script>

export default {
  data() {
    return {
      ruleForm: {
        username: "",
        password: "",
      },
      rules: {
        username: [
          { required: true, message: "用户名不能为空!", trigger: "blur" },
        ],
        password: [
          { required: true, message: "密码不能为空!", trigger: "blur" },
        ],
      },
      loading: false, // 是否显示加载动画
    };
  },
  methods: {
    submitForm(formName) {
      // 验证表单中的账号密码是否有效,因为在上面rules中定义为了必填 required: true
      this.$refs[formName].validate((valid) => {
        // 点击登录后,让登录按钮开始转圈圈(展示加载动画)
        this.loading = true;
        // 如果经过校验,账号密码都不为空,则发送请求到后端登录接口
        if (valid) {
          let _this = this;
          // 使用 axios 将登录信息发送到后端
          this.axios({
            url: "/api/admin/student/login",               // 请求地址
            method: "post",                       // 请求方法
            headers: {                            // 请求头
              "Content-Type": "application/json",
            },
            data: {                             // 请求参数
              username: _this.ruleForm.username,
              password: _this.ruleForm.password,
            },
          }).then((res) => { // 当收到后端的响应时执行该括号内的代码,res 为响应信息,也就是后端返回的信息
            if (res.data.code === 1) {  // 当响应的编码为 1 时,说明登录成功
              // 将用户信息存储到sessionStorage中
              sessionStorage.setItem("userInfo", JSON.stringify(res.data.data));
              // 跳转页面到首页
              this.$router.push('/home');
              // 显示后端响应的成功信息
              this.$message({
                message: res.data.data,
                type: "success",
              });
            } else {  // 当响应的编码不为 1 时,说明登录失败
              // 显示后端响应的失败信息
              this.$message({
                message: res.data.msg,
                type: "warning",
              });
            }
            // 不管响应成功还是失败,收到后端响应的消息后就不再让登录按钮显示加载动画了
            _this.loading = false;
            console.log(res);
          });
        } else {  // 如果账号或密码有一个没填,就直接提示必填,不向后端请求
          console.log("error submit!!");
          this.loading = false;
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
  },
};
</script>

<style scoped>
/* 设置登录面板居中,宽度为400px */
.box-card {
  margin: auto auto;
  width: 400px;
}
/* 设置登录面板中的表单居中 */
.login-from {
  margin: auto auto;
}

/* 背景图片 */
.login-background {  
  background-image: url('/src/assets/bg.jpeg');  
  background-size: cover;  
  background-position: center;  
  height: 100vh;  
  display: flex; /* 如果你想要使用Flexbox来居中el-card  */ 
  justify-content: center; /* 水平居中 */  
  align-items: center; /* 垂直居中 */  
}  
</style>
相关推荐
匹马夕阳8 分钟前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?10 分钟前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
桂月二二6 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062068 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb8 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角8 小时前
CSS 颜色
前端·css
九酒8 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔9 小时前
HTML5 新表单属性详解
前端·html·html5
lee5769 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579659 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter