首页 前端知识 创建新的vite vue3 Element-plus unocss vue-router axios pinia

创建新的vite vue3 Element-plus unocss vue-router axios pinia

2024-05-20 14:05:03 前端知识 前端哥 370 631 我要收藏

缘由:由于不经常创建新项目导致每次都忘,在这做个记录,再用的时候就直接翻翻,不用再查了

这里插一句,vite.config.ts 会被多次编辑,不用每次复制,结尾会贴一份完整的代码

路由守卫待续......

可能还有其他也待续......

写了一天写不动了......

1.先初始化项目

1.1 选择用vite构建,输入下面命令

npm create vite@latest

1.2 会问你是否继续,直接回车,默认为yes

1.3 输入项目名字

1.4 输入package.json中的名字,不能有大写

1.5 选择你所用的框架,用上下方向键选择,然后回车,我这里用了vue

1.6 选择用什么类型来开发,也是用上下方向键选择,然后回车,我这里用了TypeScript

1.7 然后就创建好了

1.8 然后跟着命令跑起来就行了,这是完整的截图

2.配置UI element-plus(点击这里查看文档)

2.1 先下载UI

npm install element-plus --save

2.2  然后配置按需导入

npm install -D unplugin-vue-components unplugin-auto-import
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
+import AutoImport from 'unplugin-auto-import/vite'
+import Components from 'unplugin-vue-components/vite'
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  // ...
  plugins: [
    vue(),
+    AutoImport({
+      resolvers: [ElementPlusResolver()],
+    }),
+    Components({
+      resolvers: [ElementPlusResolver()],
+    }),
  ],
})

2.3 自定义一个主题

2.3.1 先下载所需要的依赖
npm i @types/node scss -D
2.3.2 创建一个scss文件,路径为 src/assets/css/element.scss
// styles/element/index.scss
/* 只需要重写你需要的即可 */
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
  $colors: (
    'primary': (
      'base': #ff7e00,
    ),
  ),
);

// 如果只是按需导入,则可以忽略以下内容。
// 如果你想导入所有样式:
// @use "element-plus/theme-chalk/src/index.scss" as *;
 2.3.3 配置 vite.config.ts ,顺便把@也一起配置了
+ import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver(
+        {importStyle: 'sass'}
      )],
    }),
  ],
+  resolve: {
+    alias: {
+      '@': fileURLToPath(new URL('./src', import.meta.url))
+    }
+  },
+  css: {
+    preprocessorOptions: {
+      scss: {
+        additionalData: `@use "@/assets/css/element.scss" as *;`,
+      }
+    }
+  }
})

3.配置unocss(点击这里查看文档)

3.1 下载依赖

npm i unocss @unocss/preset-rem-to-px -D

 3.2 创建unocss.config.ts

import { defineConfig, presetUno, presetAttributify } from 'unocss';
// presetAttributify 属性化模式,属性冲突时,可以通过默认un-前缀来解决:<div m-2 rounded text-teal-400 >代替class</div>
import presetRemToPx from '@unocss/preset-rem-to-px';
// 此处我用了rem to px的预设,所以后面不加单位的数字的话会直接被转化为px(如果不用这个预设,就需要用m-100px之类的)

export default defineConfig({
  presets: [presetUno(), presetAttributify(), presetRemToPx({ baseFontSize: 4 })],
  rules: [
    [/^fs-(\d+)$/, ([, num]) => ({ 'font-size': `${num}px` })],
    [/^lh-(\d+)$/, ([, num]) => ({ 'line-height': `${num}px` })]
  ],
  variants: [
    matcher => {
      if (!matcher.startsWith('hover:')) {
        return matcher;
      }
      return {
        matcher: matcher.slice(6),
        selector: s => `${s}:hover`
      };
    }
  ],
  shortcuts: {
    'center': 'flex items-center justify-center'
  }
});

3.3 配置 vite.config.ts 

import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
+ import Unocss from 'unocss/vite'

export default defineConfig({
  plugins: [
    vue(),
+    Unocss({
+      configFile: '@/unocss.config.ts'
+    }),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver({
        importStyle: 'sass'
      })],
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/assets/css/element.scss" as *;`,
      }
    }
  }
})

3.4 配置main.ts 

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
+ import 'uno.css'

createApp(App).mount('#app')

4.配置vue-router

4.1 先下载依赖

npm install vue-router@4 -D

4.2 在src下创建 router/index.ts

import { createRouter,createWebHashHistory } from "vue-router";
import login from '@/views/login/login.vue'
import home from '@/views/home/home.vue'


let routes = [
  {
    path:'/',
    redirect:'/login'
  },
  {
    path: '/login',
    name: 'login',
    component: login
  },
  {
    path: '/home',
    name: 'home',
    component: home
  }
]

const router = createRouter({
  history:createWebHashHistory(),
  routes
})

export default router

4.3 在 main.ts 中配置

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import 'uno.css'
+ import router from '@/router/index.ts'


- createApp(App).mount('#app')
+ createApp(App).use(router).mount('#app')

4.4 如果用了ts报错找不到类型啥的,在根目录下的 vite-env.d.ts 添加下面这个

/// <reference types="vite/client" />


+ declare module "*ts"
+ declare module "*vue"

4.5 路由守卫 路由守卫先待续......

const WhiteList = ['/login']; // 配置白名单
router.beforeEach((to, from, next)=> {
  if (WhiteList.indexOf(to.fullPath) !== -1) { // 判断前往页面是都存在于白名单
    next()
  } else {
    if (localStorage.getItem('userInfo')) {// 判断用户是否d登录
      if (to.name) { // 判断是否存在路由的name名字,如果有则代表有路由表已经存在,name继续前往,反之,则不存在
        next()
      }
      else {// 当路由不存在,录取路由,动态添加路由表,
        let localRoutes: any = localStorage.getItem('routes');
        let recursionList = recursionParam(JSON.parse(localRoutes));
        for (let item of recursionList) {
          router.addRoute(item)
        }
        next({ ...to, replace: true })
      }
    } else {
      next('/login')
    }
  }
});

5.配置交互axios

5.1先设置环境变量+代理

5.1.1 根目录下创建.env.production和.env.development
# .env.development
VITE_APP_MODE = "development"
#base api
VITE_APP_BASE_API = "/aaa/"


# .env.production
VITE_APP_MODE = "production"
#base api
VITE_APP_BASE_API = "https://xxx.xxx.com/"
5.1.2 vite.config.ts 中配置代理
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Unocss from 'unocss/vite'

export default defineConfig({
  plugins: [
    vue(),
    Unocss({
      configFile: '@/unocss.config.ts'
    }),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver({
        importStyle: 'sass'
      })],
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/assets/css/element.scss" as *;`,
      }
    }
  },
+  server: {
+    proxy: {
+      // 字符串代理
+      '/xxx': {
+        target: 'https://xxx.xxx.com/',
+        changeOrigin: true,
+        rewrite: (path) => path.replace(/^\/xxx/, '')
+      }
+    }
+  }
})

5.2 配置axios

5.2.1 先下载axios
npm i axios qs -D
5.2.2 在src/utils下创建 api.js 编写 axios 的统一方法
import axios from "axios"
import qs from "qs"
import { ElMessage } from 'element-plus'
let key = "loading";

const _LOGIN_URL = import.meta.env.VITE_APP_LOGIN_URL;

const instance = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 6000,
});

axios.interceptors.response.use((res) => {
  // return
  if (res.status != 200) {
    ElMessage.error("暂无网络,请稍后重试");
    ElMessage.destroy(key);
    return;
  }
  if (!res.data.code || res.config.headers.status == 3) {
    ElMessage.destroy(key);
    return res.data;
  }
  if (res.data.code == 301) {
    ElMessage.error("身份已过期,请重新登录");
    ElMessage.destroy(key);
    let expireTime = setTimeout(() => {
      window.location.href = _LOGIN_URL;
      clearTimeout(expireTime);
    }, 3000);
    return;
  }
  if (res.data.code == 313) {
    ElMessage.error("未登录,请登录");
    ElMessage.destroy(key);
    let notLoginTime = setTimeout(() => {
      window.location.href = _LOGIN_URL;
      clearTimeout(notLoginTime);
    }, 3000);
    return;
  }
  ElMessage.destroy(key);
  return res.data;
},
  (error) => {
    return error;
  }
);

instance.interceptors.request.use((config) => {
  console.log(config);
  return config;
}, (error) => {
  // 对请求错误做些什么
  return Promise.reject(error);
}
);

const requestApi = (method, url, params, status, headers) => {
  // status 0: 都显示 1: 不显示loading 2: 不显示报错 3: 都不显示
  if (status != 1 || status != 3) {
    message.loading({ content: "加载中", key: key, duration: 0 });
  }
  headers.status = status;
  return new Promise((resolve, reject) => {
    instance({
      method: method,
      headers: headers,
      url,
      params: method == "GET" && params,
      data: method == "POST" && qs.stringify(params)
    }).then(res => {
      resolve(res.data);
    }).catch(err => {
      reject(err);
    });
  })
}

const login = (params) => requestApi("POST", "/login", params, 0, { "Content-Type": "application/x-www-form-urlencoded" });

export {
  login
}

6. 配置pinia

6.1 先下载所需的依赖

  pinia-plugin-persistedstate是为了将store存在本地存储中,这样刷新页面关键信息也不会丢失

npm install pinia pinia-plugin-persistedstate -D

6.2 然后在 main.ts 中配置 

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import 'uno.css'
import router from '@/router/index.ts'
+ import { createPinia } from "pinia";
+ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'


- createApp(App).use(router).mount('#app')



+ const app = createApp(App);
+ const store = createPinia();
+ store.use(piniaPluginPersistedstate);

+ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+   app.component(key, component)
+ }
+ app.use(router).use(store).mount("#app");

6.3 如何配置 

  简单举个例子,创建文件,路径为 src/store/user.ts 

import { defineStore } from "pinia"

let _LOGIN_URL = import.meta.env.VITE_APP_LOGIN_URL; // 从环境变量中拿到当前应该跳转到哪个地址

export const useUserStore = defineStore('user', {
  state: () => {
    return {
      token: '', // 用户token
      userInfo: {}, // 用户信息
    }
  },
  persist: {
    storage: sessionStorage, // 这里设置存储方式,也可以是 localStorage
    paths: ['userInfo', 'token'], // 要存储的哪个字段
  },
  actions: {
    setToken(token: string) {
      this.token = token; // 修改
    },
    setUserInfo(userInfo: any) {
      this.userInfo = userInfo;
    },
    logout() {
      window.sessionStorage.clear();
      window.location.href = _LOGIN_URL;
      // 调用方法,这里只能把存储里的删掉,pinia本身还需要多加一步$reset()来清除,这个后面有体现
    }
  }
})

6.4 如何调用操作 

在vue文件中,举个例子,可以结合自己需求去完成

<script setup lang="ts">
  import { useUserStore } from "@/store/user";
  const userStore: any = useUserStore();


  onMounted(() => {
    if (!userStore.token) { // 这里直接就能使用
      // 没有登录信息
      router.push({
        name: "login",
      });
      return;
    }

    // 这里举个例子怎么使用

    // 1. 调用事件去修改
    let token = "xajxbnajsbxjasbxhsbxhsabxjhbsajhbxa";
    userStore.setToken(token); 

    // 2. 本身自带的方法去修改
    userStore.$patch((state) => {
      state.token = token;
    })

    // 3.直接修改不推荐,能不用就不用吧
    userStore.token = token;
  })

  const logout = () => {
    // 退出登录
    userStore.$reset(); // 清空本身store中所有数据
    userStore.logout(); // 调用方法
  };
</script>

7. 结尾

7.1 vite.config.ts

import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Unocss from 'unocss/vite'

export default defineConfig({
  plugins: [
    vue(),
    Unocss({
      configFile: '@/unocss.config.ts'
    }),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver({
        importStyle: 'sass'
      })],
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/assets/css/element.scss" as *;`,
      }
    }
  },
  server: {
    proxy: {
      // 字符串代理
      '/huipaia': {
        target: 'https://ai.huipaia.com/',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/huipaia/, '')
      },
    }
  }
})

7.2 main.ts

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import 'uno.css'
import router from '@/router/index.ts'
import { createPinia } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

createApp(App).use(router).mount('#app')

const app = createApp(App);
const store = createPinia();
store.use(piniaPluginPersistedstate);

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

app.use(router).use(store).mount("#app");

转载请注明出处或者链接地址:https://www.qianduange.cn//article/8922.html
标签
评论
会员中心 联系我 留言建议 回顶部
复制成功!