搭建vue3+vite项目模板

237 阅读4分钟

一、通过vscode打开创建的vue3项目

该项目搭建时是按默认项目创建的,结构目录如下

image.png

在src目录下创建view目录来存储页面

image.png

安装CSS预处理器

npm install --save-dev sass

image.png

二、安装路由

1、安装 npm install vue-router -s

image.png 2、在src目录下创建router文件夹,并在router文件夹下创建index.js文件

image.png

3、在index.js配置基础路由

import { createRouter, createWebHistory } from 'vue-router'
// 路由配置
const routes = [
  {
    path: '/:pathMatch(.*)*', // 解决路由爆[Vue Router warn]: No match found for location with path
    meta: {
      title: '找不到此页面'
    },
    component: () => import('../view/404.vue')
  },
  {
    path: '/',
    name: 'rehome',
    redirect: '/home' // 重定向
  },
  {
    path: '/home',
    name: 'home',
    alias: ['/home1', '/home2'], // 可以定义多个别名
    component: () => import('../view/HomePage.vue'),
    children: []
  },
  {
    path: '/ai',
    name: 'ai',
    alias: ['/ai1', '/ai2'], // 可以定义多个别名
    component: () => import('../view/AiEvent.vue'),
    children: []
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

export default router

在main.js引入并注册

image.png 在App.vue上使用路由

image.png

三、样式初始化

主要用来解决游览器的初始兼容样式问题

npm install normalize.css

image.png

在main.js引入初始化文件

image.png

后面如果有项目上的初始化要调整,则修改该css文件就可以了

四、大屏适配

用来解决PC屏幕适配问题

npm install vue3-scale-box

image.png

在APP.vue上使用,用来起到全局适配的作用

image.png 属性说明

  • width 宽度 默认 1920
  • height 高度 默认 1080
  • bgc 背景颜色 默认 "transparent"
  • delay自适应缩放防抖延迟时间(ms) 默认 100
  • isFlat是否启用拉伸模式 默认 false
  • @scaleChange 缩放值发生改变的方法 可动态获取 scale 改变后的值 注意:拉伸模式下scale值为: [x缩放值, y缩放值];非拉伸模式下scale值为:等比缩放值

五、封装request请求

主要做到接口的统一管理

1、安装aaxios

npm install axios

image.png

2、在src目录下创建axios目录,在axios创建如下文件与目录

image.png

api目录用来存放各个接口

image.png

base.js文件用来做接口域名的管理

image.png http.js用来封装axios,目前的封装是基础的,后续如有项目需求可以进一步封装

import { base } from '@/axios/base'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/stores/counter.js'

/**
 *
 * @param opt.url (必填)请求地址
 * @param opt.method (必填)请求方式
 * @param opt.data query形式传参
 * @param opt.params param形式传参
 * @param opt.responseType 返回值类型(默认json)
 * @param opt.baseURL 请求前缀(默认/crmapi/crm)
 * @param opt.use_defaultCatch 请求失败默认处理方式
 */

function request(opt) {
  if (opt.method == 'jsonp') {
    return requestJSONP(opt)
  } else {
    const userStore = useUserStore()
    return new Promise((resolve, reject) => {
      const nullObj = Object.create(null)
      opt.use_defaultCatch = opt.use_defaultCatch !== false
      axios({
        baseURL: opt.baseURL !== undefined ? opt.baseURL : base.Api,
        url: opt.url,
        method: opt.method,
        params: opt.params || nullObj,
        data: opt.data || nullObj,
        responseType: opt.responseType || 'json',
        headers: {
          Authorization: 'Bearer ' + localStorage.getItem('token') // userStore.state.token
        }
      })
        .then((res) => {
          if (res.data.code >= 300 || res.data.code < 200) {
            ElMessage.error(res.data.msg)
            return userStore.actions.logOut(true)
          }
          if (opt.use_dataSource) resolve(res)
          else resolve(res.data)
        })
        .catch((err) => {
          if (opt.use_defaultCatch) {
            ElMessage.error(err)
          }
          reject(err)
        })
    })
  }
}

function requestJSONP(opt) {
  if (!opt.url) throw new Error('url is necessary')
  const callback = 'CALLBACK' + Math.random().toString().substr(9, 18)
  const JSONP = document.createElement('script')
  JSONP.setAttribute('type', 'application/javascript')

  const headEle = document.getElementsByTagName('head')[0]

  let ret = ''
  if (opt.data) {
    if (typeof opt.data === 'string') ret = '&' + opt.data
    else if (typeof opt.data === 'object') {
      for (let key in opt.data) ret += '&' + key + '=' + encodeURIComponent(opt.data[key])
    }
    ret += '&_time=' + Date.now()
  }
  JSONP.src = `${opt.url}?callback=${callback}${ret}`
  return new Promise((resolve /* reject */) => {
    window[callback] = (r) => {
      resolve(r)
      headEle.removeChild(JSONP)
      delete window[callback]
    }
    headEle.appendChild(JSONP)
  })
}
export default request

index.js文件是用来统一接口的出口的

/**
 * api接口的统一出口
 */
import device from './api/device.js'
// 导出接口
export default {
  device
}

api文件里放接口

import request from '../http.js'

const crmapi = {
  // 线索分页查询
  Cluelist(params) {
    return request({
      url: `/leads/list`,
      method: 'GET',
      params: params
    })
  }
}
export default crmapi

六、安装Pinia

1、安装

npm install pinia

image.png

2、挂载到main.js中

import { createPinia } from 'pinia'
const pinia = createPinia()
createApp(App).use(router).use(pinia).mount('#app')

3、在src目录下创建 store文件夹用来状态管理,结构如下

image.png index.js文件存放的数据如下

import { defineStore } from 'pinia'
const useStore = defineStore('dpStore', {
  state: () => {
    return {
      // 紧急求助
      emergencyHelp: null,
    }
  },
  actions: {
    setemergencyHelp(data) {
      this.informationReleaseScreen = data
    },
  },
  getters: {}
})
export { useStore }

和vuex的使用差不多,项目小的话直接引用该文件就可以了,不用做到全局挂载

7、vite.config.js的基础配置

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 { resolve } from 'path'
import { visualizer } from 'rollup-plugin-visualizer'
import legacyPlugin from '@vitejs/plugin-legacy'
// import viteCompression from 'vite-plugin-compression'
export default defineConfig({
  plugins: [
    vue(),
    // 配置插件
    AutoImport({
      resolvers: [ElementPlusResolver()],//引入elementPlus
      imports: ['vue', 'vue-router']
    }),
    Components({
      resolvers: [ElementPlusResolver()]
    }),
    // 开启查看打包情况
    visualizer({ open: true }),
    //低版本浏览器兼容,后续会被淘汰,看业务是否要求在老游览器跑
    legacyPlugin({
      targets: ['chrome 52', 'Android > 39', 'iOS >= 10.3', 'iOS >= 10.3'], // 需要兼容的目标列表,可以设置多个
      additionalLegacyPolyfills: ['regenerator-runtime/runtime'] // 面向IE11时需要此插件
    })
    // 打包压缩
    // viteCompression({
    //   verbose: true,
    //   disable: false,
    //   threshold: 10240,
    //   algorithm: 'gzip',
    //   ext: '.gz'
    // })
  ],
  server: {
  // 接口代理
    proxy: {
      '/msuu': {
        target: 'http://219.151.31.38',
        changeOrigin: true,
        ws: true,
        rewrite: (path) => path.replace(/^\/msuu/, '')
      }
    },
    host: '0.0.0.0'
  },
  resolve: {
    // 配置路劲别名
    alias: {
      '@': resolve(__dirname, './src')
    }
  },
  build: {
    outDir: 'BIGMAP3',
    assetsDir: 'public',
    // 打包时的每个模块的大小限制
    chunkSizeWarningLimit: 1500,
    // 分解每个模块
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            return id.toString().split('node_modules/')[1].split('/')[0].toString()
          }
        }
      }
    },
    //   关闭文件计算
    reportCompressedSize: false,
    //   关闭生成map文件 可以达到缩小打包体积
    sourcemap: false
  }
})