相关推荐recommended
Vue3实战教程(快速入门)
作者:mmseoamin日期:2023-12-02

Vue3实战教程(快速入门)

  • 前言
  • 1.搭建脚手架
    • 1.1 创建项目
    • 1.2 清除多余文件,创建干净项目
    • 1.3 创建登录页面
    • 2.创建404页面(引入sass)
      • 2.1 引入sass
      • 2.2 创建404页面
      • 3.构建登录注册页面(引入element-plus)
        • 3.1 实现布局左右切换动画
        • 3.2 引入element-plus
        • 3.3 使用element-plus表单组件
        • 3.4 表单验证
        • 4.类型匹配和代码抽离
          • 4.1 代码抽离
          • 4.2 类型匹配
            • 4.2.1 ts文件类型匹配
            • 4.2.2 vue文件中的ts类型匹配
            • 5.抽离登录组件
            • 6. 实现注册表单
              • 6.1 创建注册表单ts——存放注册表单及其验证规则
              • 6.2 创建注册表单组件
              • 6.3 在LoginRegister.vue中引入使用
              • 7. 封装axios
                • 7.1 下载axios
                • 7.2 封装axios
                • 7.3 解决跨域问题(配置vue.config.js,设置代理)
                • 7.4 使用axios发起请求
                  • 7.4.1 创建api文件夹,规范使用api(推荐)
                  • 7.4.2 全局注册axios(不推荐,也没必要)
                  • 8.总结

                    前言

                    本教程通过搭建一个简单项目,帮助读者快速入门Vue3项目实战,掌握Vue3、TS、Element Plus、axios等技术栈。

                    1.搭建脚手架

                    vue -V查看vue版本,需要在4.5.1版本之后,即可进行以下操作。

                    1.1 创建项目

                    (1)使用命令 vue create vue3-elementplus-demo 创建Vue项目。

                    (2)进入选项配置,选择 Manually select features,进行手动配置

                    Vue3实战教程(快速入门),在这里插入图片描述,第1张

                    (3)配置项如下

                    Vue3实战教程(快速入门),在这里插入图片描述,第2张

                    都选择完毕后,回车,项目即可创建完毕,使用VsCode或者按照提示进入和启动项目

                    Vue3实战教程(快速入门),在这里插入图片描述,第3张

                    Vue3实战教程(快速入门),在这里插入图片描述,第4张

                    Vue3实战教程(快速入门),在这里插入图片描述,第5张

                    1.2 清除多余文件,创建干净项目

                    (1)删除以下文件

                    Vue3实战教程(快速入门),在这里插入图片描述,第6张

                    (2)在views目录下创建Index.vue文件(后面处于方便,又将Index.vue修改成了Home.vue),内容如下:

                    Vue3实战教程(快速入门),在这里插入图片描述,第7张

                    
                    
                    

                    (3)修改router/index.ts路由文件:

                    Vue3实战教程(快速入门),在这里插入图片描述,第8张

                    import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
                    import Home from '../views/Home.vue'
                    const routes: Array = [
                      {
                        path: '/',
                        name: 'Index',
                        component: () => import('../views/Index.vue')
                      },
                    ]
                    const router = createRouter({
                      history: createWebHistory(process.env.BASE_URL),
                      routes
                    })
                    export default router
                    

                    (4)修改App文件:

                    Vue3实战教程(快速入门),在这里插入图片描述,第9张

                    
                    
                    

                    修改完毕后,查看效果

                    Vue3实战教程(快速入门),在这里插入图片描述,第10张

                    (5)新建css/resset.css文件(上网搜关键词reset.css就有),并在index.html文件中引入,初始化样式

                    Vue3实战教程(快速入门),在这里插入图片描述,第11张

                    /**
                     * 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;
                     }
                    

                    Vue3实战教程(快速入门),在这里插入图片描述,第12张

                    Vue3实战教程(快速入门),在这里插入图片描述,第13张

                    1.3 创建登录页面

                    创建LoginRegister.vue文件:

                    Vue3实战教程(快速入门),在这里插入图片描述,第14张

                    
                    
                    

                    在路由中引入

                    Vue3实战教程(快速入门),在这里插入图片描述,第15张

                    查看效果:

                    Vue3实战教程(快速入门),在这里插入图片描述,第16张

                    2.创建404页面(引入sass)

                    2.1 引入sass

                    (1)查看当前node版本

                    Vue3实战教程(快速入门),在这里插入图片描述,第17张

                    (2)引入对应版本的node-sass和sass-load

                    Vue3实战教程(快速入门),在这里插入图片描述,第18张

                    当前已知 node-sass 与 node 版本对应如下:https://github.com/sass/node-sass

                    Vue3实战教程(快速入门),在这里插入图片描述,第19张

                    node-sass 和 sass-loader 的常见版本对应关系如下:

                    node-sasssass-loader4.3.04.1.14.7.2.0.3/7.3.16.0.110.0.1

                    (3)如果引入出现了问题,基本上就是node版本和sass版本不一致导致。此时需要创建一个新项目,将新项目中的package.json和package-lock.json复制到当前项目中,然后重新 npm i 即可。

                    2.2 创建404页面

                    (1)assets下创建img文件夹,加入404.gif

                    Vue3实战教程(快速入门),在这里插入图片描述,第20张

                    (2)创建404.vue

                    Vue3实战教程(快速入门),在这里插入图片描述,第21张

                    
                    
                    

                    (3)router/index.ts中通过正则表达式匹配匹配失败的路由为404页面

                    Vue3实战教程(快速入门),在这里插入图片描述,第23张

                    Vue3实战教程(快速入门),在这里插入图片描述,第24张

                    3.构建登录注册页面(引入element-plus)

                    3.1 实现布局左右切换动画

                    因为本篇文章主要讲解的是Vue3和element-plus的用法,css部分就省略说明,有兴趣的同学可以自行研究。

                    Vue3实战教程(快速入门),在这里插入图片描述,第25张

                    Vue3实战教程(快速入门),在这里插入图片描述,第26张

                    
                    
                    

                    3.2 引入element-plus

                    (1)下载element-plus包:

                    npm i element-plus
                    

                    Vue3实战教程(快速入门),在这里插入图片描述,第29张

                    (2)在main.ts中引入

                    Vue3实战教程(快速入门),在这里插入图片描述,第30张

                    3.3 使用element-plus表单组件

                    (1)setup中加入登录表单loginUser

                    setup() {
                        // 登录/注册模式
                        const signUpMode = ref(false)
                        // 登录表单
                        const loginUser = reactive({
                          email: '',
                          password: ''
                        })
                        return { signUpMode, loginUser }
                      }
                    

                    (2)使用表单组件

                    Vue3实战教程(快速入门),在这里插入图片描述,第31张

                    
                    
                      
                        
                      
                      
                        
                      
                      
                        提交
                      
                      
                      
                        

                    忘记密码立即找回

                    Vue3实战教程(快速入门),在这里插入图片描述,第32张

                    3.4 表单验证

                    (1)表单验证

                    Vue3实战教程(快速入门),在这里插入图片描述,第33张

                    关键代码:

                    // 校验规则
                    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' }
                      ]
                    })
                    

                    Vue3实战教程(快速入门),在这里插入图片描述,第34张

                    (2)点击提交触发表单验证

                    Vue3实战教程(快速入门),在这里插入图片描述,第35张

                    关键代码:

                    
                    

                    点击提交,完成验证:

                    Vue3实战教程(快速入门),在这里插入图片描述,第38张

                    4.类型匹配和代码抽离

                    4.1 代码抽离

                    创建utils文件夹和loginValidators.ts文件,将LoginRegister.vue中的loginUser和rules剪切抽离到该文件中,LoginRegister.vue再通过import导入。测试正常运行。

                    Vue3实战教程(快速入门),在这里插入图片描述,第39张

                    loginValidators.ts:

                    import { ref, reactive  } from 'vue'
                    // 登录表单
                    export const loginUser = reactive({
                      email: '',
                      password: ''
                    })
                    // 校验规则
                    export 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' }
                      ]
                    })
                    

                    4.2 类型匹配

                    4.2.1 ts文件类型匹配

                    将鼠标悬浮在 loginUser 的 reactive 上,可以看到对应的类型提示,写入interface User 并复制提示。rules重复操作。

                    Vue3实战教程(快速入门),在这里插入图片描述,第40张

                    import { ref, reactive  } from 'vue'
                    interface User{
                      email: string;
                      password: string;
                    }
                    // 登录表单
                    export const loginUser = reactive({
                      email: '',
                      password: ''
                    })
                    interface Rules{
                      email: {
                          required: boolean;
                          type: string;
                          message: string;
                          trigger: string;
                      }[];
                      password: ({
                          required: boolean;
                          message: string;
                          trigger: string;
                          min?: undefined;
                          max?: undefined;
                      } | {
                          min: number;
                          max: number;
                          message: string;
                          trigger: string;
                          required?: undefined;
                      })[];
                    }
                    // 校验规则
                    export 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' }
                      ]
                    })
                    

                    此时如果将字段修改为不符合规范的类型,则会有报错提示

                    Vue3实战教程(快速入门),在这里插入图片描述,第41张

                    这对于初次使用ts的同学可能不太适应,认为完全没有必要。但是这其实对于大型项目的维护来说,相对比js友好许多。

                    4.2.2 vue文件中的ts类型匹配

                    (1)在script标签中加入lang="ts"标识,发现参数都没有类型匹配。

                    Vue3实战教程(快速入门),在这里插入图片描述,第42张

                    (2)类型匹配

                    1、对于any类型的变量——ctx,使用// @ts-ignore进行类型忽略

                    2、对于其他类型的变量,在变量后加入:类型即可,比如formName:string和valid:boolean

                    Vue3实战教程(快速入门),在这里插入图片描述,第43张

                    5.抽离登录组件

                    (1)创建组件LoginForm.vue,将LoginRegister.vue中的表单内容(包括组件、数据、方法和样式,顺便对样式做了点优化)复制到该文件中。

                    Vue3实战教程(快速入门),在这里插入图片描述,第44张

                    LoginForm:

                    
                    
                    

                    Vue3实战教程(快速入门),在这里插入图片描述,第45张

                    6. 实现注册表单

                    其实完全可以仿照登录组件的写法,先在LoginRegister.vue中写出form组件,填充form数据,实现表单验证,最后再抽离出来。但是如果已经熟练的话,建议可以直接分为3个部分写完(ts——对应的数据和验证规则,component——组件,vue——引入到父组件中)

                    6.1 创建注册表单ts——存放注册表单及其验证规则

                    创建registerValidator.ts文件,用于存放注册表单及其验证规则。

                    可以先复制之前的loginValidator.ts文件的内容,然后进行修改(注意确认密码password2的验证规则写法)。

                    Vue3实战教程(快速入门),在这里插入图片描述,第46张

                    registerValidator.ts:

                    import { reactive  } from 'vue'
                    interface RegisterUser{
                      name:string;
                      email: string;
                      password: string;
                      password2: string;
                      role:string
                    }
                    // 登录表单
                    export const registerUser = reactive({
                      name:'',
                      email: '',
                      password: '',
                      password2: '',
                      role:''
                    })
                    interface RegisterRules{
                      name: {
                        required: boolean;
                        message: string;
                        trigger: string;
                    }[];
                      email: {
                          required: boolean;
                          type: string;
                          message: string;
                          trigger: string;
                      }[];
                      password: ({
                          required: boolean;
                          message: string;
                          trigger: string;
                      } | {
                          min: number;
                          max: number;
                          message: string;
                          trigger: string;
                      })[];
                      password2: ({
                          required: boolean;
                          message: string;
                          trigger: string;
                      } | {
                          min: number;
                          max: number;
                          message: string;
                          trigger: string;
                      } | {
                        validator:(rule: RegisterRules, value: string, callback: any)=>any;
                        trigger:string
                      })[];
                      role: {
                        required: boolean;
                        message: string;
                        trigger: string;
                    }[];
                    }
                    const validatePass2 = (rule: RegisterRules, value: string, callback: any) => {
                      if (value === '') {
                        callback(new Error('请再次输入密码'))
                      } else if (value !== registerUser.password) {
                        callback(new Error("两次输入的密码不一致!"))
                      } else {
                        callback()
                      }
                    }
                    // 校验规则
                    export const registerRules = reactive({
                      name: [
                        {
                          required: true,
                          message: '用户名不得为空',
                          trigger: 'blur'
                        }
                      ],
                      email: [
                        {
                          required: true,
                          type: 'email',
                          message: 'email格式错误',
                          trigger: 'blur'
                        }
                      ],
                      password: [
                        { required: true, message: '密码不得为空', trigger: 'blur' },
                        { min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' }
                      ],
                      password2: [
                        { required: true, message: '确认密码不得为空', trigger: 'blur' },
                        { min: 6, max: 30, message: '密码长度必须在6到30之间', trigger: 'blur' },
                        { validator: validatePass2, trigger: 'blur' }
                      ],
                      role: [
                        {
                          required: true,
                          message: '角色不得为空',
                          trigger: 'blur'
                        }
                      ],
                    })
                    

                    完成后将 registerUser 和 registerRules 引入到LoginRegister.vue中备用。

                    Vue3实战教程(快速入门),在这里插入图片描述,第47张

                    6.2 创建注册表单组件

                    创建注册表单组件RegisterForm.vue,模仿或者直接复制LoginForm.vue组件,稍作修改(包括样式、数据和方法)

                    Vue3实战教程(快速入门),在这里插入图片描述,第48张

                    
                    
                    

                    6.3 在LoginRegister.vue中引入使用

                    最后在LoginRegister.vue中引入使用即可

                    Vue3实战教程(快速入门),在这里插入图片描述,第49张

                    Vue3实战教程(快速入门),在这里插入图片描述,第50张

                    Vue3实战教程(快速入门),在这里插入图片描述,第51张

                    7. 封装axios

                    7.1 下载axios

                    (1)使用命令npm i axios下载axios

                    Vue3实战教程(快速入门),在这里插入图片描述,第52张

                    7.2 封装axios

                    创建utils/http.ts文件,用于封装axios请求(为了避免混乱,所以取名http.ts,不过叫做axios也无不可)。

                    Vue3实战教程(快速入门),在这里插入图片描述,第53张

                    http.ts:

                    import axios,{AxiosRequestConfig,AxiosResponse} from 'axios'
                    import { ElLoading } from 'element-plus'
                    import { ElMessage } from 'element-plus'
                    let loading:any;
                    const startLoading = () =>{
                      interface Options{
                        lock: boolean;
                        text: string;
                        background: string;
                    }
                      const options:Options = {
                        lock: true,
                        text: 'Loading',
                        background: 'rgba(0, 0, 0, 0.7)'
                      }
                      loading = ElLoading.service(options)
                    }
                    const endLoading = ()=>{
                      loading.close()
                    }
                    // 请求拦截
                    axios.interceptors.request.use((config:AxiosRequestConfig)=>{
                      // 开始Loading
                      startLoading()
                      return config
                    })
                    // 响应拦截
                    axios.interceptors.response.use((res:AxiosResponse)=>{
                      // 结束Loading
                      endLoading()
                      // console.log('成功响应拦截',res)
                      // 如果请求成功直接返回响应数据
                      if(res.status === 200){
                        return res.data
                      }
                    },error=>{
                      // 结束Loading
                      endLoading()
                      // console.log('失败响应拦截',error)
                      const { response: res } = error
                      const msg = typeof res.data === 'string' ? res.data: res.data.error || '请求失败,请稍后重试'
                      ElMessage.error(msg)
                      // 错误提醒
                      return Promise.reject(error)
                    })
                    export default axios
                    

                    7.3 解决跨域问题(配置vue.config.js,设置代理)

                    创建vue.config.js文件,配置如下:

                    Vue3实战教程(快速入门),在这里插入图片描述,第54张

                    module.exports = {
                      devServer: {
                        open: true,
                        host: 'localhost',
                        port: 8080,
                        https: false,
                        hotOnly: false,
                        // 设置跨域
                        proxy: {
                          '/api': {
                            target: 'http://imissu.herokuapp.com',
                            ws: true,
                            changeOrigin: true,
                            pathRewrite: {
                              '^api': ''
                            }
                          }
                        },
                        before: (app) => {}
                      }
                    }
                    

                    7.4 使用axios发起请求

                    API地址:http://imissu.herokuapp.com/

                    7.4.1 创建api文件夹,规范使用api(推荐)

                    (1)创建api/loginRegister.ts,引入axios,规范export注册接口

                    Vue3实战教程(快速入门),在这里插入图片描述,第55张

                    import axios from '@/utils/http'
                    // 注册接口
                    export function register(params: any) {
                      return axios({
                        url: '/api/v1/auth/register',
                        method: 'post',
                        headers: {
                          'Content-Type': 'application/json;charset=UTF-8'
                        },
                        data: params
                      })
                    }
                    

                    (2)在注册组件中使用

                    Vue3实战教程(快速入门),在这里插入图片描述,第56张

                    
                    
                    

                    登录功能模仿注册功能即可。

                    7.4.2 全局注册axios(不推荐,也没必要)

                    (1)在main.ts中全局挂载axios

                    import axios from '@/utils/http'
                    app.config.globalProperties.$http = axios
                    

                    (2)在注册组件中使用,关键代码:

                    // @ts-ignore
                    const { ctx, proxy } = getCurrentInstance()
                    const res = await proxy.$http({
                      url: '/api/v1/auth/register',
                      method: 'post',
                      headers: {
                        'Content-Type': 'application/json;charset=UTF-8'
                      },
                      data: props.registerUser
                    })
                    

                    (3)不推荐的原因是,随着版本的更替,貌似axios全局挂载的位置也发生了变化,之前是在ctx,之后的版本又换成了proxy;另外一个原因是,这种方式不便于一个接口多处使用,复用性较差。

                    8.总结

                    Vue3 和 Vue2 的几个明显的区别:

                    (1)Vue2使用的选项式API,Vue3使用的是组合式API。前者随着项目页面体积的增大,对于代码的管理会给使用者带来更大的心智负担;后者组合式的写法,将data和methods等组合在一起,更容易理解和使用。不过对于初学者而言,可能会有些不太适应。

                    (2)Vue2使用的js构建的源码和使用方式,Vue3使用ts构建的源码,使用方式也支持ts,对于大型项目而言,更加友好,不过对于小型项目而言,往往使用者无法一下子看出ts对于强类型支持带来的好处,相反会觉得麻烦和没有必要。

                    (3)由于该项目是为了简要说明Vue3和Vue2在页面中的区别,方便急于使用Vue3的同学构建项目和页面,所以没有将Vue3更多的特性展示出来。在下一篇文章中,将会通过一个更加完整的项目,对Vue3的更多其他特性以及和Vue2的区别进行深入的解析和说明,敬请期待。