vue3+ts+vite+element-plus从搭建环境到vite优化

今天使用vue3的命令创建了个新项目
代码请参考
https://gitee.com/hellow-world-lzc/lzc-vue-three

npm init vue@latest

命令行提示在create-vue,ok
提示是否,ts,jsx,router,pinia…可以按照个人需要选择
创建完成后,

cd your-app-name
npm i
npm run dev

运行这些命令即可完成项目本地编译启动
vue3+ts+vite+element-plus从搭建环境到vite优化_第1张图片
我这里继续安装了些可能会用到的框架,插件,库

npm install element-plus --save
npm install moment --save
npm i --save lodash-es  
npm install echarts --save
npm i axios vue-axios --save
npm install --save sass

vue3+ts+vite+element-plus从搭建环境到vite优化_第2张图片
将初始代码中的无用部分先清理掉
在views下新创建一个first-page页面,
简单修改路由

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: () => import('@/views/first-page/index.vue')
    }
  ]
})

export default router

给首页index.vue来点简单的布局





代码运行

vue3+ts+vite+element-plus从搭建环境到vite优化_第3张图片

先将axios简单封装下,方便在demo中调用
axios.ts

import axios from 'axios'

const initAxios = axios.create({
  withCredentials: true,
  timeout: 10000 //数据响应过期时间
})
//请求拦截器
initAxios.interceptors.request.use(
  (config) => {
    //在发送之前做点什么
    return config
  },
  (error) => {
    //对请求错误做点什么
    return error
  }
)

//响应拦截器
initAxios.interceptors.response.use((response) => {
  return response
})
//导出
export default () => initAxios

不同请求方式 method.ts

import Axios from './axios'

const instance = Axios()

export default {
  get(url: string, params: any, headers: any) {
    return instance.get(url, { params, headers })
  },
  post(url: string, params: any, headers: any) {
    return instance.post(url, params, { headers })
  },
  put(url: string, params: any, headers: any) {
    return instance.put(url, params, { headers })
  },
  delete(url: string, params: any, headers: any) {
    return instance.delete(url, { params, headers })
  }
}

注册接口api request.ts

import service from './method'
//声明一个基础接口变量
let baseURL: string

//配置开发环境
if (process.env.NODE_ENV === 'development') {
  baseURL = 'http://192.168.0.100:5050'
}

// 配置生产环境
if (process.env.NODE_ENV === 'production') {
  baseURL = 'http://192.168.0.100:5050'
}
//设置请求头(如果请求头统一的话可以在axios文件设置,则无须从这里传过去)
const headers = {
  // Accept: "application/json;charset=UTF-8",
  'Content-Type': 'application/json'
}

//根据自身需求
const _service = {
  getList(data: any) {
    const url = baseURL + '/api/list'
    return service.get(url, data, headers)
  },
  getDetail(data: any) {
    const url = baseURL + '/api/detail'
    return service.get(url, data, headers)
  },
  createItem(data: any) {
    const url = baseURL + '/api/add'
    return service.put(url, data, headers)
  },
  updateItem(data: any) {
    const url = baseURL + '/api/update'
    return service.post(url, data, headers)
  },
  deleteItem(data: any) {
    const url = baseURL + '/api/delete'
    return service.delete(url, data, headers)
  }
}

//导出
export default _service

在index.vue中简单引入使用下request

template:
内容主体
{{ msg }}
typescript import _service from '@/service/request' import { onMounted, ref } from 'vue' let msg = ref('') const getList = () => { msg.value = '请求中...' _service .getDetail({ userName: 'helloworld', password: 'helloworld' }) .then((res) => { msg.value = 'res: ' + res console.log(msg.value) }) .catch((err) => { msg.value = 'err: ' + err console.log(msg.value) }) } onMounted(() => { getList() })

vue3+ts+vite+element-plus从搭建环境到vite优化_第4张图片

这里为了方便使用,将element-plus 全局引入

// main.ts
import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)
app.use(ElementPlus)

app.mount('#app')

在index.vue添加个按钮组件,绑定事件,启动运行

vue3+ts+vite+element-plus从搭建环境到vite优化_第5张图片
简单尝试了下npm run build
打包成功了,
vue3+ts+vite+element-plus从搭建环境到vite优化_第6张图片

将打包成功的dist/index.html使用live server打开(vscode 扩展:live server)
vue3+ts+vite+element-plus从搭建环境到vite优化_第7张图片

vue3+ts+vite+element-plus从搭建环境到vite优化_第8张图片
页面空白,提示路径不对,404
在vite.config.js文件添加base:‘./’
vue3+ts+vite+element-plus从搭建环境到vite优化_第9张图片

重新build,将dist/index.html open by live server
vue3+ts+vite+element-plus从搭建环境到vite优化_第10张图片
文件路径是没问题了
不过页面依然是空白的,
稍微百度了下,这里是因为我们新建的项目里,路由模式默认了historry模式导致,

vue3+ts+vite+element-plus从搭建环境到vite优化_第11张图片
我们稍微修改下,使用hash

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: '/',
      name: 'home',
      component: () => import('@/views/first-page/index.vue')
    }
  ]
})

export default router

重新打包,打开dist/index.html
vue3+ts+vite+element-plus从搭建环境到vite优化_第12张图片

打包成功,页面展示内容和本地启动完全一致。
那么,在上面这一阶段:我们已经搭建好:vue3 + ts + vite + scss + element-plus + vouter + axios.并且在本地启动调试&打包构建启动验证完毕。

接下来,我们继续尝试vue组件化开发的内容:组件通信
在index.vue下创建两个子组件,方便一会儿尝试父子,子父,兄弟,祖孙通信

// 父组件 index.vue

        
从a组件来的信息:{{ msgFromA }}
import childA from './child-a.vue' import childB from './child-b.vue' let msgFromA = ref('') const handleA = (val: string) => { msgFromA.value = val } // child-a.vue porps,emit实现父子传值,子父通信

vue3+ts+vite+element-plus从搭建环境到vite优化_第13张图片
上面已经实现了父子组件的传值通信
接下来我们尝试下兄弟组件通信
在vue2版本中,我们是用事件总线来实现兄弟组件通信。
vue3版本中,已经移除了$on,$emit。我们可以使用官方推荐的mitt来实现
安装mitt

 npm install --save mitt

封装下eventBus

import mitt from 'mitt'
const eventBus = mitt()
export default eventBus

b组件发起事件

import eventBus from '@/utils/eventBus.ts'

let val = ref('')
const clickEvent = () => {
  eventBus.emit('bToA', val.value)
}

a组件注册事件

import eventBus from '@/utils/eventBus.ts'
let msgFromB = ref('')

onMounted(() => {
  eventBus.on('bToA', (val: string) => {
    msgFromB.value = val
  })
})

vue3+ts+vite+element-plus从搭建环境到vite优化_第14张图片
到这里,我们最基本的props,emit,eventBus都已经实现.

记录下ts的相关提示信息
vue3+ts+vite+element-plus从搭建环境到vite优化_第15张图片
根据提示,是因为两个参数的类型不明确。
这里调整下eventBus.ts的代码,带上类型

import mitt, { Emitter } from 'mitt'
type Events = {
  [propName: string]: any
}
const eventBus: Emitter = mitt()
export default eventBus

这样修改之后,可以看到eventBus.on不再有提示了
vue3+ts+vite+element-plus从搭建环境到vite优化_第16张图片

不过在eventBus.ts还有提示
vue3+ts+vite+element-plus从搭建环境到vite优化_第17张图片

改为定义type即可

import mitt, { type Emitter } from 'mitt'
type Events = {
  [propName: string]: any
}
const eventBus: Emitter = mitt()
export default eventBus

vue3+ts+vite+element-plus从搭建环境到vite优化_第18张图片

那么进入下一个环节,关于vue的computed和watch相关学习

import { computed, onMounted, ref } from 'vue'

let computedVal = computed(() => {
  return val.value.toUpperCase()
})

在这里插入图片描述
computed也可以支持get,set操作,
computed也支持传参,
这里就不演示了

关于数据监听,有watch,watchEffect两种
watch是指定监听的数据
watchEffect是自动跟踪回调的响应式依赖

import { computed, onMounted, ref, watch, watchEffect } from 'vue'
let val = ref('')
let modelVal = ref('')
watch(val, async () => {
  const a = await new Promise((resolve) => {
    resolve(Math.ceil(Math.random() * 100 + 100))
  })
  console.log(a + val.value)
})
watchEffect(() => {
  const b = val.value + modelVal.value
  console.log(b)
})

基本的组件开发内容,基本到这里结束。
下面可以尝试下其他内容,
比如:透传,依赖注入,插槽
比如:国际化
国际化实现还穿插了状态管理,本地缓存

接着昨天的内容继续,
今天研究了下关于国际化的内容
如果只是处理非UI组件的内容,昨天的代码已经足够了。
https://gitee.com/hellow-world-lzc/lzc-vue-three/commit/c383fb76c1a8d8821ca93331125c5d7dcb04932c

但是UI组件的内容并没有一起切换。

今天参考了element plus + vue-i18n的内容,重写了下国际化的内容。
首先安装vue-i18n

npm install --save @types/vue-i18n

这里说下为什么安装@types
当我们用 npm 等包管理工具安装第三方包的时候,有些包并不是 TypeScript 编写的,自然也不会导出 TypeScript 声明文件。这种情况下,如果我们在 TypeScript 项目中引入了这种包,则会编译报错(没有设置 allowJS)。举个例子,当我们通过npm install jquery --save 安装 jquery 包并引用的时候,TypeScript 会报错。
vue-i18n同理

安装好之后,创建下lang相关内容文件,引用vue-i18n

// src/lang/i18n.ts
import zh from './zh.json'
import en from './en.json'

import { createI18n } from 'vue-i18n'

const i18n = createI18n({
  legacy: false, // 没有该参数可能会报错
  globalInjection: true, // 全局注入$t函数
  locale: 'zh',
  messages: {
    zh: {
      ...zh
    },
    en: {
      ...en
    }
  }
})

export default i18n

// zh.json
{
  "firstPage": {
    "header": "页面头部",
    "menu": "页面左侧菜单",
    "main": "页面主体内容"
  },
  "greeting": {
    "hello": "你好"
  }
}

在main.ts中引入i18n

import i18n from './lang/vue-i18n'
const app = createApp(App)
app.use(i18n)

接下来是改造我们的路由入口文件app.vue

// 参考element plus说明,使用configProvider组件包裹好路由


// ts
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import en from 'element-plus/lib/locale/lang/en'
import { useLangStore } from '@/stores/index'
const lang = useLangStore()
interface localesType {
  [zh: string]: Object
}
const locales = reactive({
  zh: zhCn,
  en: en
})
const locale = computed(() => {
  // 不添加localesType这个接口,ts会报错
  return locales[lang.language]
})

考虑到本地保存和全局通信,使用pinia和localStorage
创建stores相关文件

import { defineStore } from 'pinia'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
export const useLangStore = defineStore(
  'lang',
  () => {
    const i18n = useI18n()
    let language = ref(localStorage.getItem('language') || 'zh')
    function setLanguage(lang: string) {
      language.value = lang
      localStorage.setItem('language', lang)
      i18n.locale.value = lang
    }
    return { language, setLanguage }
  },
  {
    persist: true
  }
)

看看效果
vue3+ts+vite+element-plus从搭建环境到vite优化_第19张图片
这是切换到英文状态下的结果。
接下来,我们刷新页面,看看是否缓存到了
vue3+ts+vite+element-plus从搭建环境到vite优化_第20张图片
ok,基本功能已经完成。
遗留问题一:ts报错,
vue3+ts+vite+element-plus从搭建环境到vite优化_第21张图片
这里vue-i18n安装的版本:
vue3+ts+vite+element-plus从搭建环境到vite优化_第22张图片
查看了下vue-i18n的官网
https://vue-i18n.intlify.dev/guide/advanced/typescript.html
vue3+ts+vite+element-plus从搭建环境到vite优化_第23张图片
ok,uninstall下@types/vue-i18n

npm uninstall @types/vue-i18n
npm i --save vue-i18n@latest 

vue3+ts+vite+element-plus从搭建环境到vite优化_第24张图片
当前版本为9.2.2,应该支持ts了
vue3+ts+vite+element-plus从搭建环境到vite优化_第25张图片
嗯,还是存在报错

遗留问题二:提示考虑到tree-shaking,需要做一些相应的配置
在这里插入图片描述
在vite.config.ts添加一行即可解决

'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js',

vue3+ts+vite+element-plus从搭建环境到vite优化_第26张图片
vue3+ts+vite+element-plus从搭建环境到vite优化_第27张图片
今天开始做一些优化方面的事情
第一步:对路由进行懒加载处理

routes: [
    {
      path: '/',
      redirect: '/index'
    },
    {
      path: '/index',
      name: 'home',
      component: () => import('@/views/first-page/first-index.vue'),
      children: [
        {
          path: 'content-management',
          name: 'content-management',
          component: () => import('@/views/content-management/content-index.vue')
        }
      ]
    },
    {
      path: '/login',
      name: 'login',
      component: () => import('@/views/login/login-index.vue')
    },
    {
      path: '/menu-management',
      name: 'menu-management',
      component: () => import('@/views/menu-management/menu-index.vue')
    }
  ]

vue3+ts+vite+element-plus从搭建环境到vite优化_第28张图片
第二步:分包策略
1)浏览器的缓存策略:
访问网站时向服务器获取静态资源并缓存起来,如css、js等
下次再访问时,如果之前保存的 “静态资源” 名字没有改变,则不会重新请求
2)vite打包文件生成策略:
打包时只要代码内容变了,就会生成hash字符完全不同的新文件
3)vite分包策略:
我们的业务代码时常改变,而依赖不会变化
所以把依赖分开打包,以避免多次重新请求资源
vue3+ts+vite+element-plus从搭建环境到vite优化_第29张图片

打包后效果:
vue3+ts+vite+element-plus从搭建环境到vite优化_第30张图片

可以看到content-index.js明显减小,新加了我们配置的四个分包js

第三步:gzip压缩

把打包后的静态资源压缩成 gzip格式
服务器响应资源文件时发送 gzip格式文件
浏览器拿到 gzip文件 后再解压使用
文件比较小不建议用 gzip ,因为浏览器解压时间可能大于请求原来资源的时间
通过配置 vite 插件 “vite-plugin-compression” 实现:
vue3+ts+vite+element-plus从搭建环境到vite优化_第31张图片

第四步:使用cdn加速
我们项目的所有依赖以及文件在我们进行打包以后会放到我们的服务器上面去
我们把第三方模块写成 cdn 的形式
保证我们自己代码的一个小体积,降低我们自己服务器的传输压力
第三方代码通过 cdn 向最近最优的服务器请求过来

// npm i --save vite-plugin-cdn-import
import { Plugin as importToCDN } from 'vite-plugin-cdn-import'

vue3+ts+vite+element-plus从搭建环境到vite优化_第32张图片
接着将上面配置的分包,去掉关于echarts部分的
vue3+ts+vite+element-plus从搭建环境到vite优化_第33张图片

再次打包
vue3+ts+vite+element-plus从搭建环境到vite优化_第34张图片

这次就没有关于echarts的包了,
用live server打开index.html

vue3+ts+vite+element-plus从搭建环境到vite优化_第35张图片

还可以做下去除console.log,debugger的操作
vue3+ts+vite+element-plus从搭建环境到vite优化_第36张图片

修改前:
vue3+ts+vite+element-plus从搭建环境到vite优化_第37张图片
修改后:
vue3+ts+vite+element-plus从搭建环境到vite优化_第38张图片

vue3+ts+vite+element-plus从搭建环境到vite优化_第39张图片

明天的任务是学习下vue3里面新增的几个组件

你可能感兴趣的:(vue)