完整创建一个vite前端项目

目录

1.先创建一个vite项目

2.下载第三方依赖 

 ① 安装路由vue-router

 ② 安装vuex全局数据管理

③ 安装element-plus  

④ 安装element-plus图标

 ⑤ 安装axios发送请求

⑥ 完整main.js代码模板

3.开发组件

 4.登陆页面开发用例

 5. 完整项目代码


废话少说,直接上步骤!

1.先创建一个vite项目

2.下载第三方依赖 

 ① 安装路由vue-router

       -- 用于页面跳转切换

 npm install vue-router

--安装完之后,在src创建router目录, 在router目录创建index.js文件

--创建完后,在index.js文件中导入以下模板

//vue-router配置文件
//1.从vue-router导入createRouter() 创建路由器对象
import { createRouter, createWebHistory, createWebHashHistory} from 'vue-router'
 
//2.配置路由规则: 给组件绑定url
const routes = [
    //默认路由
    {
        path:'/',
        //重定向
        redirect:'/index'
    },

    // 这是一个配置路由的示例
    {
        path: "/index",
        component: ()=>import('../views/index.vue'),
        name:'indexPage',
        children:[  //配置子级路径
            {
                // 这是resful风格的url写法
                path:'/infor/:id' , 
                component:  ()=>import('../views/information.vue'),
                name:'infor',
            },
        ]
    },
    
    //配置404的组件
    {
        path:'/:pathMatch(.*)*', 
        component:  ()=>import('../views/NotFound.vue'),
        name:'notFound',
    }
];
 
//3.创建路由器对象
const router = createRouter({
        routes,  //路由规则
        history:  createWebHashHistory(),
        linkActiveClass:'active'
    });
//4. 把路由器对象暴露出去  其他组件文件,导入
export default router;

--最后找到main.js文件,并在里面配置router

 ② 安装vuex全局数据管理

       --通过命令安装vuex

npm install vuex

--安装完成后,在src目录下创建store目录, 在store目录创建一个index.js

--然后再index.js文件中导入以下模板,用于配置全局数据

// 导入函数
import { createStore } from "vuex";

// 定义一个状态
const state = {
    count:0,
    user:{
        id:0,
        username:'张三',
        age:13
    }
}

// 修改状态的函数集合 , 不能异步调用
const mutations = {
    addCount(state,payload){
        // 修改state里面的count状态
        state.count+=payload.num ; 
    }
}

// actons : 操作集合(定义事件,让组件触发事件)
const actions = {
    increment(context,payload){
        // 发送ajax请求,异步通信
        // 它只能调用mutations里面的方法才能修改数据,三个核心对象各司其职(主要是因为mutation不能异步调用,而actions可以,所以我们用actions去调用mutations)
        context.commit('addCount' , payload)
    }
}

// 调用createStore创建Store对象
const store = createStore({
    state , 
    mutations,
    actions
})

// 暴露store对象
export default store  //把它挂在到mian.js中去,就可以全局使用它

--最后在main.js文件里面配置store

③ 安装element-plus  

      --使用命令安装element-plus

npm install element-plus

-- 然后在main.js文件中配置

④ 安装element-plus图标

     --命令行安装

npm install @element-plus/icons-vue

 

--在main.js配置

import * as ElementPlusIconsVue from '@element-plus/icons-vue'

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

 ⑤ 安装axios发送请求

       --使用命令安装axios和qs

npm install axios

npm install qs

-- 在src目录创建一个http目录, 创建两个文件

--一个是 axios实例配置文件: config.js

   并且在里面配置如下模板:

//axios的配置文件
export default {
    method: 'get',
    // 基础url前缀
    baseUrl: 'http://localhost:8080',
    // 请求头信息
    headers: {
      //默认的请求context-type: application/json
      'Content-Type': 'application/json;charset=UTF-8'
    },
    // 参数
    data: {},
    // 设置超时时间
    timeout: 10000,
    // 携带凭证  是否携带cookie
    withCredentials: true,
    // 返回数据类型
    responseType: 'json'
  }

--另外一个封装axios 工具库的文件 request.js

并且在里面配置如下模板:

import { ElLoading,ElMessage } from 'element-plus'
import axios from 'axios'
import qs from 'qs'  //把json进行序列化成key/value
import config from './config'
import  $router from '../router'

const instance = axios.create({
    baseURL: config.baseUrl,
    headers: config.headers,
    timeout: config.timeout,
    withCredentials: config.withCredentials
  })
// request 拦截器
instance.interceptors.request.use(
    config => {
      let token = sessionStorage.getItem("token");
      // 带上token
      if (token) {
        config.headers.token = token
      }
      return config
    });

const request = async function (loadtip, query) {
    let loading
    if (loadtip) {
        loading = ElLoading.service({
            lock: true,
            text: '正在加载...',
            background: 'rgba(0, 0, 0, 0.7)',
        })
    }
    const res = await instance.request(query)
    if (loadtip) {
        loading.close()
    }
    if (res.data.meta.status === 401) {
        //ElMessage.error();
        $router.push({ path: '/login' })
        return Promise.reject(res.data) //reject()  catch捕获
    } else if (res.data.meta.status === 500) {
        return Promise.reject(res.data)
    } else if (res.data.meta.status === 501) {
        return Promise.reject(res.data)
    } else if (res.data.meta.status === 502) {
        $router.push({ path: '/login' })
        return Promise.reject(res.data)
    } else {
        return Promise.resolve(res.data)  // then()
    }
        /*
        .catch(e => {
            if (loadtip) {
                loading.close()
            }
            return Promise.reject(e.msg)
        })
        */
}
const get = function (url, params) {
    const query = {
        url: url,
        method: 'get',
        withCredentials: true,
        timeout: 30000,
        params: params,  //params: queryString
        headers: { 'request-ajax': true }
    }
    return request(false, query)
}
const post = function (url, params) {
    const query = {
        url: url,
        method: 'post',
        withCredentials: true,
        timeout: 30000,
        data: params,  //请求体
        headers: { 'Content-Type': 'application/json', 'request-ajax': true }
    }
    return request(false, query)
}
const postWithLoadTip = function (url, params) {
    const query = {
        url: url,
        method: 'post',
        withCredentials: true,
        timeout: 30000,
        data: params,
        headers: { 'Content-Type': 'application/json', 'request-ajax': true }
    }
    return request(true, query)
}
const postWithOutLoadTip = function (url, params) {
    const query = {
        url: url,
        method: 'post',
        withCredentials: true,
        timeout: 30000,
        data: params,
        headers: { 'Content-Type': 'application/json', 'request-ajax': true }
    }
    return request(false, query)
}
const postWithUrlEncoded = function (url, params) {
    const query = {
        url: url,
        method: 'post',
        withCredentials: true,
        timeout: 30000,
        data: qs.stringify(params), //params:json  qs.stringify(json) --> 转换key/value
        headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'request-ajax': true }
    }
    return request(false, query)
}

const del = function (url, params) {
    const query = {
        url: url,
        method: 'DELETE',
        withCredentials: true,
        timeout: 30000,
        data: params,
        headers: { 'Content-Type': 'application/json', 'request-ajax': true }
    }
    return request(true, query)
}
const put = function (url, params) {
    const query = {
        url: url,
        method: 'PUT',
        withCredentials: true,
        timeout: 30000,
        data: params,
        headers: { 'Content-Type': 'application/json', 'request-ajax': true }
    }
    return request(true, query)
}



const form = function (url, params) {
    const query = {
        url: url,
        method: 'post',
        withCredentials: true,
        timeout: 30000,
        data: params,
        headers: { 'Content-Type': 'multipart/form-data', 'request-ajax': true }
    }
    return request(false, query)
}


export default {
    post,
    postWithLoadTip,
    postWithOutLoadTip,
	postWithUrlEncoded,
    get,
    form,
    del,
    put
}

--最后在在main.js配置request.js文件

⑥ 完整main.js代码模板
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
const app = createApp(App)
// 配置路由
import router from './router'
app.use(router)
// 配置vuex
import store from './store'
app.use(store)
// 配置element-plus
import ElementPlus from 'element-plus'
import '../node_modules/element-plus/dist/index.css'
app.use(ElementPlus)
// 配置element-plus图标
import * as ElementPlusIconsVue from '../node_modules/@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    createApp(App).component(key, component)
}
// 配置axios
import $http from './http/request.js'
app.config.globalProperties.$http =  $http
// 注册一个全局路由守卫
router.beforeEach((to, from) => {
    console.log("to:"+to)
    return true
});

app.mount('#app')

3.开发组件

组件分类:

局部功能组件: 放在src/components目录下面

页面/视图组件: 放在src/views(pages)目录下面

组合式api获取相关对象:

--组合式不能用this得到当前对象,只能导入。

// router  route   
//第一步 从vue-router导入 useRoute()  useRouter()
import { useRoute, useRouter } from 'vue-router'
//第二步: 调用函数useRouter() 得到router
//得到路由对象
const router = useRouter();

//store对象
//第一步 从vuex导入 useStore()
import {useStore} from 'vuex'
//第二步:调用useStore得到store对象
const store = useStore();

 4.登陆页面开发用例

① 登录页面开发: Login.vue

<template>
    <div class="login">
        <div class="login-context">
            <!--头部图片-->
            <div class="login-logo">
                <img src="../assets/vue.svg" alt="">
            </div>
            <!--form表单-->
            <el-form :model="loginForm" :rules="loginFormRul" ref="loginFormRef" label-width="100px" class="login-box">
                <el-form-item label="用户名:" prop="username">
                    <el-input v-model="loginForm.username"></el-input>
                </el-form-item>
                <el-form-item label="密码:" prop="password">
                    <el-input type="password" v-model="loginForm.password"></el-input>
                </el-form-item>
                <el-form-item>
                    <el-col :span="12">
                        <el-form-item prop="captcha">
                            <el-input type="test" v-model="loginForm.captcha" auto-complete="off"
                                      placeholder="验证码, 单击图片刷新" style="width: 100%;">
                            </el-input>
                        </el-form-item>
                    </el-col>
                    <el-col class="line" :span="1">&nbsp;</el-col>
                    <el-col :span="11">
                        <el-form-item>
                            <img style="width: 100%;" class="pointer" :src="src" @click="refreshCaptcha">
                        </el-form-item>
                    </el-col>
                </el-form-item>


                <el-form-item class="login-btn">
                    <el-button type="primary" @click="login(loginFormRef)">登录</el-button>
                    <el-button @click="reset(loginFormRef)">重置</el-button>
                </el-form-item>
            </el-form>
        </div>
    </div>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import { ref, reactive ,getCurrentInstance } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {useStore} from 'vuex'
const store = useStore();
const loginForm = reactive({
    username: '',
    password: '',
    captcha: '',
});
const src = ref('');
//得到form对象
const loginFormRef = ref();

//验证规则
const loginFormRul = reactive({
    username: [
        { required: true, message: '请输入用户名', trigger: 'blur' },
        { min: 2, max: 8, message: '长度在 2 到 8 个字符', trigger: 'blur' }
    ],
    password: [
        { required: true, message: '请输入密码', trigger: 'blur' },
        { min: 3, max: 8, message: '长度在 3 到 8 个字符', trigger: 'blur' }
    ]
    ,
    captcha: [
        { required: true, message: '请输入验证码', trigger: 'blur' }
    ]
});

//得到路由对象
const router = useRouter();

//获取当前组件实例对象
const app = getCurrentInstance();
//获取app上的globalProperties属性
const $http = reactive(app.appContext.config.globalProperties.$http); 

//登录功能
function login(form) {
    if(!form) return;
    //提交表单之前进行表单验证
    form.validate((valid) => {
        //校验失败
        if (!valid) return;
        //校验成功
        $http.post('login', loginForm).then((response) => {
            ElMessage({
                showClose: true,
                message: '登录成功',
                type: 'success',
            })
            //状态保存下来
            window.sessionStorage.setItem("token", response.data);
            //跳转
            router.push('/users');
        }).catch((error) => {
            ElMessage({
                showClose: true,
                message: error.meta.msg,
                type: 'error',
            });
            //清空表单
            form.resetFields();
        });
    });

}


//重置功能
function reset(form) {
    if (!form) return
    form.resetFields();
}


//刷新验证码
function refreshCaptcha() {
    //防止浏览器缓存
    src.value =  "http://localhost:8080/captcha.jpg?t=" + new Date().getTime();
}
//调用这个函数显示验证码
refreshCaptcha();
</script>


<style scoped>
.login {
    height: 100%;
    background: rgb(43 75 107);
}

.login-context {
    width: 450px;
    height: 300px;
    background: #fff;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 3px 2px #DDD;
    border-radius: 10px;
}

.login-logo {
    width: 150px;
    height: 150px;
    position: absolute;
    top: -80px;
    left: 50%;
    margin-left: -75px;
    border: 1px solid #eee;
    border-radius: 50%;
    background-color: #fff;
    padding: 10px;
    box-shadow: 0 0 3px 2px #fff;
}

.login-logo img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: rgb(238, 238, 238);
}

.login-box {
    width: 100%;
    position: absolute;
    bottom: 0;
    padding: 0 20px;
    box-sizing: border-box;
}

.login-btn {
    display: flex;
    justify-content: flex-end;
}
</style>

② 在router/index.js文件中配置这个路由

const routes = [
    {
        path:'/login',
        component:()=>import('../views/Login.vue'),
        name:'Login'
    },
    {
        path:'/',
        redirect:'/login'
    }
];

③ 修改APP.vue页面

<script setup>

</script>

<template>
   <router-view/>
</template>

<style scoped>

</style>

④ 运行项目

npm run dev

⑤ 运行页面效果展示

 5. 完整项目代码

        完整的项目代码我放在的我的资源《创建一个完整vite前端项目》打包成jar包。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/842816.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DDei在线设计器-HTML渲染

Html渲染 HtmlViewer插件通过将一个外部DIV附着在图形控件上&#xff0c;从而改变原有图形的显示方式。允许使用者自己定义HTML通过HTML元素。本示例演示了通过Html来扩展渲染图形&#xff0c;从而获得更加丰富的图形展现。 通常情况下&#xff0c;我们创建的图形控件&#xff…

IDEA的工程与模块管理

《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试&#xff08;Debug&#xff09; 第七章 …

STM32项目分享:智能宠物喂食系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.com/video/BV1zy411z7…

【STL专题】模拟实现std::string,深入解析内部实现机制:从大小到运算符重载的探索之旅【万字详解】

欢迎来到 CILMY23的博客 &#x1f3c6;本篇主题为&#xff1a;模拟实现std::string&#xff0c;深入解析内部实现机制&#xff1a;从大小到运算符重载的探索之旅【万字详解】 &#x1f3c6;个人主页&#xff1a;CILMY23-CSDN博客 &#x1f3c6;系列专栏&#xff1a;Python |…

使用 PVE 自签 CA 证书签发新证书

前言 PVE 安装时会自动创建一个有效期 10 年的 CA 证书, 我们可以利用这个 CA 证书给虚拟机中的 Web 应用签发新的 TLS 证书用于提供 HTTPS 服务. 下面以 PVE 虚拟机中通过 Docker 跑的一个 雷池 应用为例进行演示. PVE 证书位置 官方文档: https://pve.proxmox.com/wiki/Pr…

python-多任务编程

2. 多任务编程 2.1 多任务概述 多任务 即操作系统中可以同时运行多个任务。比如我们可以同时挂着qq&#xff0c;听音乐&#xff0c;同时上网浏览网页。这是我们看得到的任务&#xff0c;在系统中还有很多系统任务在执行,现在的操作系统基本都是多任务操作系统&#xff0c;具备…

国产麒麟、UOS在线打开pdf加盖印章

PageOffice支持两种电子印章方案&#xff0c;可实现对Word、Excel、PDF文档加盖PageOffice自带印章或ZoomSeal电子印章&#xff08;全方位保护、防篡改、防伪造&#xff09;。Word和Excel的盖章功能请参考&#xff1a;Word和Excel加盖印章和签字功能 &#xff08;目前只支持win…

【Django+Vue3 线上教育平台项目实战】Celery赋能:优化订单超时处理与自动化定时任务调度

文章目录 前言⭐✨&#x1f4ab;&#x1f525;&#x1f4d6;一、Celery⭐1.基本概念及介绍:✨2.使用步骤&#x1f4ab; 二、订单超时 取消订单&#xff08;Celery&#xff09;&#x1f525;具体实现流程&#x1f4d6; 前言⭐✨&#x1f4ab;&#x1f525;&#x1f4d6; 在构建复…

Mac Electron 应用如何进行签名(signature)和公证(notarization)?

最近很多客户反映&#xff0c;从官网下载的Mac Electron应用打不开&#xff0c;直接报病毒&#xff0c;类似于这种&#xff1a; 这是因为在MacOS 10.14.5之后&#xff0c;如果应用没有在苹果官方平台进行公证notarization(我们可以理解为安装包需要审核&#xff0c;来判断是否存…

Typora 1.5.8 版本安装下载教程 (轻量级 Markdown 编辑器),图文步骤详解,免费领取(软件可激活使用)

文章目录 软件介绍软件下载安装步骤激活步骤 软件介绍 Typora是一款基于Markdown语法的轻量级文本编辑器&#xff0c;它的主要目标是为用户提供一个简洁、高效的写作环境。以下是Typora的一些主要特点和功能&#xff1a; 实时预览&#xff1a;Typora支持实时预览功能&#xff0…

【每日一练】python编写一个简易计算器

程序代码: #循环语句&#xff0c;条件为真所以循环执行 while True: #定义两个数的变量和运算符号 num1 float(input("第一个数:")) num2 float(input("第一个数:")) syminput("选择运算符 - * /&#xff1a;") #判断运算符号 …

知名在线市场 Etsy 允许在其平台上销售 AI 艺术品,但有条件限制|TodayAI

近日&#xff0c;以手工和复古商品著称的在线市场 Etsy 宣布&#xff0c;将允许在其平台上销售 AI 生成的艺术品。这一举措引发了广泛关注和争议。尽管 Etsy 正在接受 AI 艺术的潮流&#xff0c;但平台对这一类商品的销售设置了一些限制。 根据 Etsy 新发布的政策&#xff0c;…

小程序图片下载保存方法,图片源文件保存!

引言 现在很多时候我们在观看到小程序中的图片的时候&#xff0c;想保存图片的原文件格式的话&#xff0c;很多小程序是禁止保存的&#xff0c;即使是让保存的话&#xff0c;很多小程序也会限制不让保存原文件&#xff0c;只让保存一些分辨率很低的&#xff0c;非常模糊的图片…

【iOS】类对象的结构分析

目录 对象的分类object_getClass和class方法isa流程和继承链分析isa流程实例验证类的继承链实例验证 类的结构cache_t结构bits分析实例验证属性properties方法methods协议protocolsro类方法 类结构流程图解 对象的分类 OC中的对象主要可以分为3种&#xff1a;实例对象&#xf…

tinymce富文本支持word内容同时粘贴文字图片上传 vue2

效果图 先放文件 文件自取tinymce: tinymce富文本简单配置及word内容粘贴图片上传 封装tinymce 文件自取&#xff1a;tinymce: tinymce富文本简单配置及word内容粘贴图片上传 页面引用组件 <TinymceSimplify refTinymceSimplify v-model"knowledgeBlockItem.content…

exo 大模型算力共享;Llama3-70B是什么

目录 exo 大模型算力共享 exo框架的特点 如何使用exo框架 注意事项 结论 Llama3-70B是什么 一、基本信息 二、技术特点 三、性能与应用 四、未来发展 exo 大模型算力共享 exo框架的特点 异构支持:支持多种不同类型的设备,包括智能手机、平板电脑、笔记本电脑以及高…

仅两家!云原生向量数据库 PieCloudVector 全项通过信通院「可信数据库」评测

7月16日&#xff0c;2024 可信数据库发展大会在北京隆重举行。大会以“自主、创新、引领”为主题&#xff0c;近百位数据库领域的专家、学者齐聚一堂&#xff0c;带来高质量的数据库技术洞察与实战经验。 本次可信数据库发展大会中&#xff0c;中国信通院正式公布 2024 年上半年…

SpringMVC源码深度解析(中)

接上一遍博客《SpringMVC源码深度解析(上)》继续聊。最后聊到了SpringMVC的九大组建的初始化&#xff0c;以 HandlerMapping为例&#xff0c;SpringMVC提供了三个实现了&#xff0c;分别是&#xff1a;BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、RouterFunctio…

公司技术栈用到了RocketMQ,我对此块知识进行了回顾(初始RocketMQ)

前言 作为24届的校招生&#xff0c;不知道大伙儿们是否都已经到了工作岗位上。为了以后更方便的接触到公司的业务&#xff0c;我司为我们安排了将近一个月的实操。虽然不用敲代码&#xff0c;但是… 了解到我司使用到的技术栈&#xff0c;在空闲时间正好对RocketMQ这块技术做个…

[PM]产品运营

生命周期 运营阶段 主要工作 拉新 新用户的定义 冷启动 拉新方式 促活 用户活跃的原因 量化活跃度 运营社区化/内容化 留存 用户流失 培养用户习惯 用户挽回 变现 变现方式 付费模式 广告模式 数据变现 变现指标 传播 营销 认识营销 电商营销中心 拼团活动 1.需求整理 2.…