0


【超详细】创建vue3+ts项目(引入ElementPlus、Axios)

目录


前言

本项目为简易的全栈项目,其中前端项目使用到了vue3、ts、Element Plus、axios等技术栈;后端项目使用到了springboot、jdbc、mysql、maven等技术


一、前端项目

1、使用vue脚手架创建项目

1.1检查vue版本

输入命令vue -V(V要大写),版本需要在4.5.1之后

1

1.2 使用vue脚手架创建项目

1、使用命令vue create vue3-element-demo 创建Vue项目。
2、通过上下键选择,选择 Manually select features,按回车,手动进行配置。
在这里插入图片描述
3、通过上下键选择,通过空格键选中(使用Babel,TypeScript,Router、Vuex、CSS Pre-processors、Linter / Formatter),按回车
在这里插入图片描述

4、选择vue3按回车
在这里插入图片描述
5、是否使用 Class 风格装饰器,此处输入【y】,然后回车确认;
在这里插入图片描述
6、Babel 和 TS 是否一起使用,用于现代模式、自动检测的 polyfills 和转译 JSX,此处输入【y】,然后回车确认;
在这里插入图片描述
7、是否使用history路由模式,此处输入【n】,即使用默认的 hash 模式,然后回车确认;
在这里插入图片描述
8、选择 CSS 预处理器,按上下方向键来选择,笔者习惯了 Less,然后回车确认;
在这里插入图片描述
9、选择第一个ESLint with error prevention only(仅具有错误预防功能的ESLint)
在这里插入图片描述
在这里插入图片描述
10、Babel、ESLint 等插件的配置是单独的文件进行配置,还是都在 package.json 文件里面?此处输选择 package.json 咯,并不想太多零散的配置文件,然后回车确认;
在这里插入图片描述
11、是否保存当前创建 Vue3 项目的特性配置,下次再创建 Vue 项目的时候,可以选择该特性,然后回车确认即可创建完成。这个可以不用保存,输入【n】,然后回车确认;
在这里插入图片描述12、项目创建中;
在这里插入图片描述
项目创建成功:
在这里插入图片描述
在这里插入图片描述
运行项目
在这里插入图片描述
在这里插入图片描述

2、删除项目多余文件,修改配置项目

2.1、删除以下文件

在这里插入图片描述

2.1、在views下创建index文件

在这里插入图片描述

<template><div>我的首页</div></template><script lang="ts">exportdefault{name:'Index'}</script><style scoped></style>

2.2、修改router/index.ts路由文件:

在这里插入图片描述
编译时会有报错:

vue eslint报错:Component name “index“ should always be multi-word.eslintvue/multi-word-component-names

在这里插入图片描述
原因:除了根组件(App.vue)外,自定义组件名称应该由多单词组成,防止和html标签冲突。
解决方法,关闭eslint校验,重新编译就正常了
lintOnSave: false

在这里插入图片描述

2.3、修改App.vue文件:

在这里插入图片描述

<template><div id="app"><router-view/></div></template><style lang="less">
html,
body,
#app {width:100%;height:100%;}</style>

运行效果:
在这里插入图片描述

2.4、初始化页面样式以及清除浮动

新建css/resset.css文件,并在index.html文件中引入,初始化样式
在这里插入图片描述

/**
 * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)
 * http://cssreset.com
 */
 
 html, body, div, span, applet, object, iframe,
 h1, h2, h3, h4, h5, h6, p, blockquote, pre,
 a, abbr, acronym, address, big, cite, code,
 del, dfn, em, img, ins, kbd, q, s, samp,
 small, strike, strong, sub, sup, tt,var,
 b, u, i, center,
 dl, dt, dd, ol, ul, li,
 fieldset, form, label, legend,
 table, caption, tbody, tfoot, thead, tr, th, td,
 article, aside, canvas, details, embed, 
 figure, figcaption, footer, header, hgroup, 
 menu, nav, output, ruby, section, summary,
 time, mark, audio, video{margin:0;padding:0;border:0;
   font-size:100%;font: inherit;
   font-weight: normal;
   vertical-align: baseline;}/* HTML5 display-role reset for older browsers */
 article, aside, details, figcaption, figure, 
 footer, header, hgroup, menu, nav, section{display: block;}
 ol, ul, li{
   list-style: none;}
 blockquote, q{quotes: none;}blockquote:before,blockquote:after,q:before,q:after{content:'';content: none;}
 table{
   border-collapse: collapse;
   border-spacing:0;}/* custom */
 a{color: #7e8c8d;
   text-decoration: none;-webkit-backface-visibility: hidden;}::-webkit-scrollbar{width: 5px;height: 5px;}::-webkit-scrollbar-track-piece{
   background-color:rgba(0,0,0,0.2);-webkit-border-radius: 6px;}::-webkit-scrollbar-thumb:vertical{height: 5px;
   background-color:rgba(125,125,125,0.7);-webkit-border-radius: 6px;}::-webkit-scrollbar-thumb:horizontal{width: 5px;
   background-color:rgba(125,125,125,0.7);-webkit-border-radius: 6px;}
 html, body{width:100%;
   font-family:"Arial","Microsoft YaHei","黑体","宋体","微软雅黑", sans-serif;}
 body{
   line-height:1;-webkit-text-size-adjust: none;-webkit-tap-highlight-color:rgba(0,0,0,0);}
 html{
   overflow-y: scroll;}/*清除浮动*/.clearfix:before,.clearfix:after{content:" ";display: inline-block;height:0;clear: both;visibility: hidden;}.clearfix{*zoom:1;}/*隐藏*/.dn{display: none;}

index.html中引用:
在这里插入图片描述

3、引入ElementPlus 组件库

3.1、导入依赖包

npm i element-plus -D
在这里插入图片描述

第一种:全局挂载ElementPlus,在main.js中添加

在这里插入图片描述

第一种:按需导入组件

vue.config.js中引入(按需导入方式),添加如下配置
在这里插入图片描述

const{ defineConfig }=require('@vue/cli-service');const AutoImport =require('unplugin-auto-import/webpack');const Components =require('unplugin-vue-components/webpack');const{ ElementPlusResolver }=require('unplugin-vue-components/resolvers');
module.exports =defineConfig({
  transpileDependencies: true,//关闭eslint校验
  lintOnSave: false,
  configureWebpack:{
    plugins:[AutoImport({
        resolvers:[ElementPlusResolver()],}),Components({
        resolvers:[ElementPlusResolver()],}),],}})

在页面中使用ElementPlus组件

在这里插入图片描述
效果:
在这里插入图片描述

3、创建登录页面

在view下新建Login.vue文件

在这里插入图片描述

<template><div class="container":class="{ 'sign-up-mode': signUpMode }"><!-- form表单容器 --><div class="form-container"><div class="signin-signup"><!-- 登录 --><el-form
            ref="ruleFormRef":model="loginUser":rules="rules"
            label-width="100px"
            class="login-form sign-in-form"><el-form-item label="邮箱" prop="email"><el-input v-model="loginUser.email" placeholder="Enter Email..."/></el-form-item><el-form-item label="密码" prop="password"><el-input
                v-model="loginUser.password"
                type="password"
                placeholder="Enter Password..."/></el-form-item><el-form-item><el-button type="primary" class="submit-btn" @click="submitForm(ruleFormRef)">提交</el-button></el-form-item><!-- 找回密码 --><el-form-item><p class="tiparea">忘记密码<a>立即找回</a></p></el-form-item></el-form></div></div><!-- 左右切换动画 --><div class="panels-container"><div class="panel left-panel"><div class="content"><h3>Row,row,row your boat</h3><p>Gentlely down the stream</p><button @click="signUpMode = !signUpMode" class="btn transparent">
              注册
            </button></div></div><div class="panel right-panel"><div class="content"><h3>Merrily,merrily,merrily,merrily,</h3><p>Life is but a dream</p><button @click="signUpMode = !signUpMode" class="btn transparent">
              登录
            </button></div></div></div></div></template><script lang="ts" setup>
  import { ref, reactive, toRefs, getCurrentInstance } from 'vue'
  import type { FormInstance, FormRules } from 'element-plus'// Vue3语法糖// 通过解构getCurrentInstance,获取this,这里的this就是ctx// const { ctx } = getCurrentInstance()const{ proxy }=getCurrentInstance()// 登录/注册模式const signUpMode =ref(false)const ruleFormRef = ref<FormInstance>()// 登录表单const loginUser =reactive({
    email:'',
    password:''})// 校验规则const rules =reactive({
    email:[{
            required: true,
            type:'email',
            message:'email格式错误',
            trigger:'blur'}],
        password:[{ required: true, message:'密码不得为空', trigger:'blur'},{ min:6, max:30, message:'密码长度必须在6到30之间', trigger:'blur'}]})// 触发登录方法const submitForm  =(formEl: FormInstance | undefined)=>{if(!formEl!)return
        formEl.validate((valid)=>{if(valid){
            console.log('submit!')const data = proxy.$http.getUserPassword(loginUser)
            console.log('data', data)}else{
            console.log('error submit!')return false
          }})}</script><style scoped>.container {
    position: relative;
    width:100%;
    min-height:100vh;
    background-color: #fff;
    overflow: hidden;}.form-container {
    position: absolute;
    left:0;
    top:0;
    width:100%;
    height:100%;}.signin-signup {
    position: relative;
    top:50%;
    left:75%;
    transform:translate(-50%,-50%);
    width:44%;
    transition:1s 0.7s ease-in-out;
    display: grid;
    grid-template-columns:1fr;
    z-index:5;}/* 左右切换动画 */.social-text {
    padding:0.7rem 0;
    font-size:1rem;}.social-media {
    display: flex;
    justify-content: center;}.social-icon {
    height:46px;
    width:46px;
    display: flex;
    justify-content: center;
    align-items: center;
    margin:00.45rem;
    color: #333;
    border-radius:50%;
    border:1px solid #333;
    text-decoration: none;
    font-size:1.1rem;
    transition:0.3s;}.social-icon:hover {
    color: #4481eb;
    border-color: #4481eb;}.btn {
    width:150px;
    background-color: #5995fd;
    border: none;
    outline: none;
    height:49px;
    border-radius:49px;
    color: #fff;
    text-transform: uppercase;
    font-weight:600;
    margin:10px 0;
    cursor: pointer;
    transition:0.5s;}.btn:hover {
    background-color: #4d84e2;}.panels-container {
    position: absolute;
    height:100%;
    width:100%;
    top:0;
    left:0;
    display: grid;
    grid-template-columns:repeat(2,1fr);}.container:before {
    content:'';
    position: absolute;
    height:2000px;
    width:2000px;
    top:-10%;
    right:48%;
    transform:translateY(-50%);
    background-image: linear-gradient(-45deg, #4481eb 0%, #04befe 100%);
    transition:1.8s ease-in-out;
    border-radius:50%;
    z-index:6;}.image {
    width:100%;
    transition: transform 1.1s ease-in-out;
    transition-delay:0.4s;}.panel {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: space-around;
    text-align: center;
    z-index:6;}.left-panel {
    pointer-events: all;
    padding:3rem 17%2rem 12%;}.right-panel {
    pointer-events: none;
    padding:3rem 12%2rem 17%;}.panel .content {
    color: #fff;
    transition: transform 0.9s ease-in-out;
    transition-delay:0.6s;}.panel h3 {
    font-weight:600;
    line-height:1;
    font-size:1.5rem;}.panel p {
    font-size:0.95rem;
    padding:0.7rem 0;}.btn.transparent {
    margin:0;
    background: none;
    border:2px solid #fff;
    width:130px;
    height:41px;
    font-weight:600;
    font-size:0.8rem;}.right-panel .image,.right-panel .content {
    transform:translateX(800px);}/* ANIMATION */.container.sign-up-mode:before {
    transform:translate(100%,-50%);
    right:52%;}.container.sign-up-mode .left-panel .image,.container.sign-up-mode .left-panel .content {
    transform:translateX(-800px);}.container.sign-up-mode .signin-signup {
    left:25%;}.container.sign-up-mode form.sign-up-form {
    opacity:1;
    z-index:2;}.container.sign-up-mode form.sign-in-form {
    opacity:0;
    z-index:1;}.container.sign-up-mode .right-panel .image,.container.sign-up-mode .right-panel .content {
    transform:translateX(0%);}.container.sign-up-mode .left-panel {
    pointer-events: none;}.container.sign-up-mode .right-panel {
    pointer-events: all;}

  @media(max-width:870px){.container {
      min-height:800px;
      height:100vh;}.signin-signup {
      width:100%;
      top:95%;
      transform:translate(-50%,-100%);
      transition:1s 0.8s ease-in-out;}.signin-signup,.container.sign-up-mode .signin-signup {
      left:50%;}.panels-container {
      grid-template-columns:1fr;
      grid-template-rows:1fr 2fr 1fr;}.panel {
      flex-direction: row;
      justify-content: space-around;
      align-items: center;
      padding:2.5rem 8%;
      grid-column:1/2;}.right-panel {
      grid-row:3/4;}.left-panel {
      grid-row:1/2;}.image {
      width:200px;
      transition: transform 0.9s ease-in-out;
      transition-delay:0.6s;}.panel .content {
      padding-right:15%;
      transition: transform 0.9s ease-in-out;
      transition-delay:0.8s;}.panel h3 {
      font-size:1.2rem;}.panel p {
      font-size:0.7rem;
      padding:0.5rem 0;}.btn.transparent {
      width:110px;
      height:35px;
      font-size:0.7rem;}.container:before {
      width:1500px;
      height:1500px;
      transform:translateX(-50%);
      left:30%;
      bottom:68%;
      right: initial;
      top: initial;
      transition:2s ease-in-out;}.container.sign-up-mode:before {
      transform:translate(-50%,100%);
      bottom:32%;
      right: initial;}.container.sign-up-mode .left-panel .image,.container.sign-up-mode .left-panel .content {
      transform:translateY(-300px);}.container.sign-up-mode .right-panel .image,.container.sign-up-mode .right-panel .content {
      transform:translateY(0px);}.right-panel .image,.right-panel .content {
      transform:translateY(300px);}.container.sign-up-mode .signin-signup {
      top:5%;
      transform:translate(-50%,0);}}

  @media(max-width:570px){
    form {
      padding:01.5rem;}.image {
      display: none;}.panel .content {
      padding:0.5rem 1rem;}.container {
      padding:1.5rem;}.container:before {
      bottom:72%;
      left:50%;}.container.sign-up-mode:before {
      bottom:28%;
      left:50%;}}/* 控制login & register显示 */
  form {
    padding:0rem 5rem;
    transition: all 0.2s 0.7s;
    overflow: hidden;}

  form.sign-in-form {
    z-index:2;}

  form.sign-up-form {
    opacity:0;
    z-index:1;}/* register */.loginForm,.registerForm {
    margin-top:20px;
    background-color: #fff;
    padding:20px 40px 20px 20px;
    border-radius:5px;
    box-shadow:0px 5px 10px #cccc;}.submit-btn {
    width:100%;}.tiparea {
    text-align: right;
    font-size:12px;
    color: #333;
    width:100%;}.tiparea a {
    color: #409eff;}</style>

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

4、封装并使用 Axios

4.1、安装Axios

npm i axios
在这里插入图片描述

4.2、安装NProgress顶部进度条

npm i --save-dev @types/nprogress
在这里插入图片描述

4.3、封装请求拦截

在 src 目录新建 utils 文件夹,再新建 requestUtil.ts 文件,写上以下代码
在这里插入图片描述

import axios from 'axios'
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'
import { ElMessage } from 'element-plus'const http = axios.create({
  baseURL:'http://localhost:9000',
  timeout:300*1000,// 请求超时时间设置为300秒})const NETWORK_ERROR ='网络错误,请联系开发人员'/**
 * 请求拦截器
 */
http.interceptors.request.use((req)=>{
  console.log('请求拦截器 =>', req)
  Nprogress.start()return req;},(error)=>{
  Nprogress.done()return Promise.reject(error);});/**
 * 响应拦截器
 */
http.interceptors.response.use(function(res){
  console.log('响应拦截器 =>', res)
  Nprogress.done()if(res.status ==200){return res.data
  }else{
    ElMessage.error((NETWORK_ERROR))return Promise.reject(NETWORK_ERROR)}});

export default http

4.4、前端设置跨域

在vue.config.js中配置如下代码:
在这里插入图片描述

const{ defineConfig }=require('@vue/cli-service');// const AutoImport = require('unplugin-auto-import/webpack');// const Components = require('unplugin-vue-components/webpack');// const { ElementPlusResolver } = require('unplugin-vue-components/resolvers');
module.exports =defineConfig({
  transpileDependencies: true,//关闭eslint校验
  lintOnSave: false,// ElementPlus按需导入方式// configureWebpack: {//   plugins: [//     AutoImport({//       resolvers: [ElementPlusResolver()],//     }),//     Components({//       resolvers: [ElementPlusResolver()],//     }),//   ],// }
  devServer:{
    open: true,
    host:'localhost',
    port:8080,
    https: false,// 设置跨域
    proxy:{'/api':{
        target:'http://localhost:9000',
        ws: true,
        changeOrigin: true,
        pathRewrite:{'^api':''}}}}})

4.5、配置接口api

在src目录下创建api文件夹,里面创建index.ts
在这里插入图片描述

import http from '@/utils/requestUtils'

 
export default{/**
   * 根据用户邮箱、密码查询用户信息
   */getUserPassword(data: any){return http.post('/api/getUserPassword',
      data,{
        headers:{'Content-Type':'application/json'},})},/**
   * 保存用户信息
   */saveUser(data: any){return http.post('/api/saveUser',
      data,{
        headers:{'Content-Type':'application/json'},})},}

4.6、将http请求全局封装

在 main.ts 文件引入HTTP请求工具并配置为全局方法
在这里插入图片描述

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import axios from 'axios'
import apiServe from '@/api'const app =createApp(App)

app.use(store)
app.use(router)
app.use(ElementPlus)
app.mount('#app')

app.config.globalProperties.$http = apiServe
app.config.globalProperties.$axios = axios

二、后端项目

1、检查JDK和maven的安装版本

在cmd输入 java -version
和mvn -v检查对应的安装情况
在这里插入图片描述

2、创建springboot项目

通过idea的spring initializr创建工程,不选择maven而是选择spring initializr快捷创建。然后去勾选相关依赖。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3、创建springboot项目成功

项目创建成功

在这里插入图片描述

4、配置maven和maven库

配置本地maven库
在这里插入图片描述

5、加载maven库

在这里插入图片描述

6、创建application.yml

在resources下面新建application.yml,并配置数据库名,密码,以及端口,端口尽量不要使用8080,避免和前端端口相同了

在这里插入图片描述
注释掉另外一个配置
在这里插入图片描述

#mysql
spring:
  datasource:#MySQL配置
    driverClassName:  com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/easyproject?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
    #数据库名和密码
    username: root
    password:920724

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.demo.model
server:
  port: 9000

7、运行项目

在这里插入图片描述
项目运行成功,端口9000
在这里插入图片描述
在这里插入图片描述

8、新建WebConfig文件处理跨域

创建utils文件夹,在utils文件夹下创建WebConfig,并添加以下配置
在这里插入图片描述

package com.springboot.userlogin.springbootdemo.utils;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;// 使用注解说明是全局配置类
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {// 继承跨域请求的类

    @Override
    public voidaddCorsMappings(CorsRegistry registry){// 跨域处理的方法
        registry.addMapping("/**")// 任意访问都允许跨域.allowedOrigins("http://localhost:8080","null")// 跨域来源.allowedMethods("POST","GET","PUT","OPTIONS","DELETE")// 跨域请求类型.maxAge(3600)// 超时时间.allowCredentials(true);// 允许携带信息}}

alt+insert快捷键可以弹出
在这里插入图片描述

9、使用idea连接mysql

mysql安装配置方法可以参照我写的另外一个文档:
https://blog.csdn.net/m0_47791238/article/details/134811414?spm=1001.2014.3001.5501

在这里插入图片描述
在这里插入图片描述
输入mysql用户名和密码:
在这里插入图片描述
在这里插入图片描述

10、在pom文件添加lombok依赖

目的:为了使用@Data注解
在这里插入图片描述

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency>

11、创建bean文件夹,用于放置实体对象

在项目中创建bean文件夹,新建user实体类,使用Data注解,创建构造方法和get\set方法
在这里插入图片描述

package com.springboot.userlogin.springbootdemo.bean;

import lombok.Data;

@Data
public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private String role;
    private boolean state;//    public User() {//    }//    public User(String username, String password, String email, String role, boolean state) {//        this.username = username;//        this.password = password;//        this.email = email;//        this.role = role;//        this.state = state;//    }////    public int getId() {//        return id;//    }////    public String getUsername() {//        return username;//    }////    public String getPassword() {//        return password;//    }////    public String getEmail() {//        return email;//    }////    public String getRole() {//        return role;//    }////    public boolean getState() {//        return state;//    }////    public void setId(int id) {//        this.id = id;//    }////    public void setUsername(String username) {//        this.username = username;//    }////    public void setPassword(String password) {//        this.password = password;//    }////    public void setEmail(String email) {//        this.email = email;//    }////    public void setRole(String role) {//        this.role = role;//    }////    public void setState(boolean state) {//        this.state = state;//    }}

12、查看构造成功成功的实体对象

快捷键 alt + 7
在这里插入图片描述

13、创建controller接口

在这里插入图片描述

import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RestController;

@RestController
publicclassLoginController{
    @Autowired
    UserDao userDao;

    @PostMapping("/api/getUserPassword")// @RequestMapping注解创建接口public String userLogin(@RequestBody User user){// @RequestBody注解方便找到user实体

        System.out.println("User : "+ user);
        String str ="error";
        int count = userDao.getUserByMassage(user.getEmail(), user.getPassword());if(count >0){
            str ="ok";}return str;}}

14、创建dao接口

在这里插入图片描述

package com.springboot.userlogin.springbootdemo.dao;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Repository;

@Repository
@Mapper
publicinterfaceUserDao{

    int getUserByMassage(@Param("email") String email, @Param("password") String password);}

15、创建mapper映射文件

在resources下面创建mapper文件夹,用于存放数据库的映射文件
在mapper文件夹下新建UserMapper.xml
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper  PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--对应dao层接口文件的目录--><mapper namespace="com.springboot.userlogin.springbootdemo.dao.UserDao"><!--  id值为UserDao接口方法名; --><select id="getUserByMassage" resultType="java.lang.Integer">SELECTcount(id)FROM easyUser
           WHERE email=#{email}AND password=#{password}</select></mapper>

三、测试前后端功能

1、前端页面接口请求

在这里插入图片描述

2、后端控制台日志打印

在这里插入图片描述


本文转载自: https://blog.csdn.net/m0_47791238/article/details/134972702
版权归原作者 smileAgain-lg 所有, 如有侵权,请联系我们删除。

“【超详细】创建vue3+ts项目(引入ElementPlus、Axios)”的评论:

还没有评论