在vite.config.js文件中
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
base: "./",//打包路径
resolve: {
alias: {
'@': path.resolve(__dirname, './src')//设置别名
}
},
server: {
open: true,//启动项目自动弹出浏览器
port: 4000,//启动端口
proxy: {
'/api': {
target: 'http://localhost:3001', //实际请求地址
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
}
}
// server: {
// port: 4000,//启动端口
// open: true,
// proxy: {
// // 跨域简单写法写法
// '/api': 'http://123.56.85.24:5000'//代理网址
// },
// cors: true
// },
})
import Axios from 'axios'
const axios = Axios.create({
headers: {
'Content-Type': 'application/json'
},
timeout: 60000, // 超时
baseURL: '' // 请求接口地址,这里使用本项目地址,因为我们是前后端分离,后面需要在vue.config.js里面配置代理,实际请求得地址不是这个。
})
// 请求拦截
axios.interceptors.request.use(req => {
if (req.method === 'get') {
const url = req.url
const t = new Date().getTime()
if (url.indexOf('?') >= 0) {
req.url = `${url}&t=${t}`
} else {
req.url = `${url}?t=${t}`
}
}
return req
})
// 响应拦截
axios.interceptors.response.use(
response => {
return response.data
},
error => {
// 响应失败统一处理
const { response } = error
if (response) {
switch (response.status) {
case 400:
window.$vm.$message.error('请求无效')
break
case 401:
window.$vm.$message.error({ message: '尚未登录请重新登录' })
break
case 403:
window.$vm.$message.error('您没有权限这样做,请联系管理员')
break
case 404:
window.$vm.$message.error('请求未找到')
break
case 500:
window.$vm.$message.error('系统异常')
break
case 504:
window.$vm.$message.error('请求超时,请稍后再试')
break
default:
window.$vm.$message.error('系统异常')
break
}
}
return Promise.reject(error)
}
)
export default axios
import request from '../utils/request' // 引入封装得axios
// 登录
export function cellphone (data) {
return request({
url: '/api/login/cellphone',
method: 'POST',
data:{
phone:'19829215473',
password:'lsh112233'
}
})
}
npm install element-plus --save
按需导入(自动导入):
npm install -D unplugin-vue-components unplugin-auto-import
在vite.config.js 或 vite.config.ts中写入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default {
plugins: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}
import {ref,isRef,shallowRef,triggerRef,customRef} from "vue";
/**
* ref() 响应式
* isRef() 判断是否为ref
* shallowRef() 浅层响应式 注意:与ref混用时,失效
* triggerRef() 强制收集依赖,shallowRef与ref混用时失效就是由于,ref底层代码中包含triggerRef
* customRef() 自定义一个ref
* 例:function MyRef(value: T) {
return customRef((track, trigger) => {
return {
get() {
track();
return value;
},
set(newValue) {
value = newValue;
trigger();
},
};
});
}
const obj = ref("大家好");
*/
直接使用ref
哈哈哈
const dom = ref();
console.log(dom.value?.innerHTML); // 注意:刚开始加载时间听不到的
- {{ item }}
{{ user }}
{{ name3 }}
{{ name3 }}
立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。
用法:
import { watchEffect } from ‘vue’
setup()
{
watchEffect(函数(){
依赖追踪:
同步调用:
追踪所有依赖
异步调用:
只有在第一个 await 正常工作前访问到的 property 才会被追踪。
如下:只会追踪url.value作为依赖
const response = await fetch(url.value)
data.value = await response.json()
})
(1)停止侦听
隐式停止:
当watchEffect在组件的setup()函数或生命周期钩子被调用时,侦听器会被链接到该组件的生命周期,并在组件卸载时自动停止。
显示停止:
const xx=watchEffect(...)
xx.stop();
(2)清除副作用
watchEffect传入参数
watchEffect((onInvalidate)=>{
onInvalidate(()=>{
执行时机:
在副作用即将重新执行时
如果在setup()或生命周期钩子函数中使用了 watchEffect, 则在卸载组件时
})
})
(3)异步副作用以及清楚
副作用函数是一个异步函数时,清理函数必须要在Promise被resolve之前被注册,同时Vue依赖这个返回的Promise来自动处理Promise链上的潜在错误
watchEffect(async () => {
onInvalidate(() => {
/* ... */
})
data.value = await fetchData(props.id)
})
(4)副作用需要同步或在组件更新之前
watchEffect(
() => {
...
},
{
flush: 'sync', 'pre'在DOM更新前运行,'post'在DOM更新后运行,'sync'强制效果始终同步触发,默认为'pre'
}
)
(5)调试侦听器的行为(只能在开发模式下工作)
watchEffect(
() => {
...
},
{
onTrack(e){
当一个 reactive对象属性或一个 ref 作为依赖被追踪时触发
e.target包含了值
debugger
},
onTrigger(e) {
依赖项变更导致副作用被触发时
e.target包含了值
debugger
}
}
)
(2)watchPostEffect
和flush:‘post’ 效果一致,作为别名使用
(3)watchSyncEffect
和flush:‘sync’ 效果一致,作为别名使用
(4)卸载watchEffect时机
异步回调创建一个侦听器,那么它不会绑定到当前组件上,必须手动停止它,以防内存泄漏,同步则不用
需要手动卸载:
setTimeout(() => {
watchEffect(() => {})
}, 100)
注:当作为组件引入时,大体与vue2一致,但不需要在computed中声明
我是子组件
{{ text }}
我是子组件
我是子组件
import { createApp } from 'vue'
import './style.css'
import HelloWorldVue from './components/HelloWorld.vue' // 在main.ts中引入
import App from './App.vue'
const app = createApp(App)
app.component('A', HelloWorldVue) // 声明
app.mount('#app')
例:
let a = {};
console.log(a.name); // underfind
console.log(a.name.length); // 报错
console.log(a.name?.length); // underfind 可选链操作符:如果后面的一层读不到的话会反一个underfind
{{ item.name }}
{{ item.name }}
匿名插槽
// 父组件
匿名插槽
// 子组件
具名插槽
// 父组件
具名插槽
// 子组件
作用域插槽
// 父组件
{{ date }}
// 子组件
顶层 await
在setup语法糖里面 使用方法
< script setup > 中可以使用顶层 await。结果代码会被编译成 async setup()
const { data } = await axios.get("./data.json");
父组件引用子组件 通过defineAsyncComponent加载异步配合import 函数模式便可以分包
-->
Teleport Vue 3.0新特性之一。
Teleport 是一种能够将我们的模板渲染至指定DOM节点,不受父级style、v-show等属性影响,但data、prop数据依旧能够共用的技术;类似于 React 的 Portal。
主要解决的问题 因为Teleport节点挂载在其他指定的DOM节点下,完全不受父级style样式影响
使用方法
通过to 属性 插入指定元素位置 to=“body” 便可以将Teleport 内容传送到指定位置
也可以自定义传送位置 支持 class id等 选择器
我是弹框
我是内容12321321321
多个使用场景
动态控制teleport
使用disabled 设置为 true则 to属性不生效 false 则生效
有时候我们不希望组件被重新渲染影响使用体验;或者处于性能考虑,避免多次重复渲染降低性能。而是希望组件可以缓存下来,维持当前的状态。这时候就需要用到keep-alive组件。
开启keep-alive 生命周期的变化
初次进入时: onMounted> onActivated
退出后触发 deactivated
再次进入:
只会触发 onActivated
事件挂载的方法等,只执行一次的放在 onMounted中;组件每次进去执行的方法放在 onActivated中
include 和 exclude
include 和 exclude 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
max
{{ item }
const list = reactive([1, 2, 4, 5, 6, 7, 8, 9])
const Push = () => {
list.push(123)
}
const Pop = () => {
list.pop()
}
< transition-group > 组件还有一个特殊之处。除了进入和离开,它还可以为定位的改变添加动画。只需了解新增的 v-move 类就可以使用这个新功能,它会应用在元素改变定位的过程中。像之前的类名一样,它的前缀可以通过 name attribute 来自定义,也可以通过 move-class attribute 手动设置
{{ item.number }}
{{ item.num }}
Vue 也同样可以给数字 Svg 背景颜色等添加过度动画 今天演示数字变化
{{ num.tweenedNumber.toFixed(0) }}
provide 可以在祖先组件中指定我们想要提供给后代组件的数据或方法,而在任何后代组件中,我们都可以使用 inject 来接收 provide 提供的数据或方法。
爸爸
孩子
可以添加readonly使后代组件无法修改祖先传的值:provide(“color”, readonly(color));
孩子
父组件
传参组件
接参组件
{{ qqq.Q2 }}
原码实现:
bus.ts
type BusClass = {
emit: (name: string) => void
on: (name: string, callback: Function) => void
}
type PramsKey = string | number | symbol
type List = {
[key: PramsKey]: Array
}
class Bus implements BusClass {
list: List
constructor() {
this.list = {}
}
emit(name: string, ...args: Array) {
let eventName: Array = this.list[name]
eventName.forEach(fn => {
fn.apply(this, args)
})
}
on(name: string, callback: Function) {
// 如果之前有就直接用,如果没有就创建一个空的数组
let fn: Array = this.list[name] || []
fn.push(callback)
this.list[name] = fn
}
}
export default new Bus()
父组件
兄弟组件
{{ bb }}
在vue3中 o n , on, on,off 和 $once 实例方法已被移除,组件实例不再实现事件触发接口,因此大家熟悉的EventBus便无法使用了。然而我们习惯了使用EventBus,对于这种情况我们可以使用Mitt库(其实就是我们视频中讲的发布订阅模式的设计)
1.安装
npm install mitt -S
2.main.ts 初始化
全局总线,vue 入口文件 main.js 中挂载全局属性
import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt'
const Mit = mitt()
//TypeScript注册
// 由于必须要拓展ComponentCustomProperties类型才能获得类型提示
declare module "vue" {
export interface ComponentCustomProperties {
$Bus: typeof Mit
}
}
const app = createApp(App)
//Vue3挂载全局API
app.config.globalProperties.$Bus = Mit
app.mount('#app')
3使用方法通过emit派发, on 方法添加事件,off 方法移除,clear 清空所有
A组件派发(emit)
我是A
B组件监听(on)
我是B
监听所有事件( on(“*”) )
instance?.proxy?.$Bus.on('*',(type,num)=>{
console.log(type,num,'===========>B')
})
移除监听事件(off)
const Fn = (num: any) => {
console.log(num, '===========>B')
}
instance?.proxy?.$Bus.on('on-num',Fn)//listen
instance?.proxy?.$Bus.off('on-num',Fn)//unListen
清空所有监听(clear)
instance?.proxy?.$Bus.all.clear()
npm install @vitejs/plugin-vue-jsx -D
npm i -D unplugin-auto-import
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import AutoImport from 'unplugin-auto-import/vite' // 引入
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(),
// 声明
AutoImport({
imports: ['vue'], // 语言
dts: 'src/auto-import.d.ts' // 配置信息位置
})],
resolve: {
alias: {
"@": resolve(__dirname, 'src'), // 路径别名
},
extensions: ['.js', '.json', '.ts'] // 使用路径别名时想要省略的后缀名,可以自己 增减
}
})
演示
{{ cs }}
其实是一个语法糖,由props与emit组合而成
1.默认值的改变
prop:value -> modelValue;
事件:input -> update:modelValue;
v-bind 的 .sync 修饰符和组件的 model 选项已移除
新增 支持多个v-model
新增 支持自定义 修饰符 Modifiers
父子组件传值
父组件
我是子组件
父组件
我是子组件
添加到组件 v-model 的修饰符将通过 modelModifiers prop 提供给组件。在下面的示例中,我们创建了一个组件,其中包含默认为空对象的 modelModifiers prop
只在 mounted 和 updated 时触发
思路:监听鼠标按下的事件,当鼠标按下后监听鼠标移动,并动态改变元素位置,最后鼠标松开关闭事件
父组件
Vue3 的 hook函数 相当于 vue2 的 mixin, 不同在与 hooks 是函数
Vue3 的 hook函数 可以帮助我们提高代码的复用性, 让我们能在不同的组件中都利用 hooks 函数
Vue3 hook 库Get Started | VueUse : https://vueuse.org/guide/
案例
import { onMounted } from 'vue'
type Options = {
el: string
}
type Return = {
Baseurl: string | null
}
export default function (option: Options): Promise {
return new Promise((resolve) => {
onMounted(() => {
const file: HTMLImageElement = document.querySelector(option.el) as HTMLImageElement;
file.onload = ():void => {
resolve({
Baseurl: toBase64(file)
})
}
})
const toBase64 = (el: HTMLImageElement): string => {
const canvas: HTMLCanvasElement = document.createElement('canvas')
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
canvas.width = el.width
canvas.height = el.height
ctx.drawImage(el, 0, 0, canvas.width,canvas.height)
console.log(el.width);
return canvas.toDataURL('image/png')
}
})
}
由于Vue3 没有Prototype 属性 使用 app.config.globalProperties 代替 然后去定义变量和函数
在 mine.ts下写入,如:
app.config.globalProperties.$env = '123'
app.config.globalProperties.$env2 = {
name(str: T) {
return '我叫' + str
}
}
type Filter = {
name(str: T): string
}
// 声明要扩充@vue/runtime-core包的声明.
// 这里扩充"ComponentCustomProperties"接口, 因为他是vue3中实例的属性的类型.
declare module 'vue' {
export interface ComponentCustomProperties {
$env: string
$env2: Filter
}
}
在setup中使用
方式一:
import { getCurrentInstance, ComponentInternalInstance } from 'vue';
const { appContext } = getCurrentInstance()
console.log(appContext.config.globalProperties.$env);
推荐 方式二:
import {ref,reactive,getCurrentInstance} from 'vue'
const app = getCurrentInstance()
console.log(app?.proxy?.$set2.name('李四'))
插件
插件是自包含的代码,通常向 Vue 添加全局级功能。你如果是一个对象需要有install方法Vue会帮你自动注入到install 方法 你如果是function 就直接当install 方法去使用
使用插件
在使用 createApp() 初始化 Vue 应用程序后,你可以通过调用 use() 方法将插件添加到你的应用程序中。
components/Loading.vue
loading
components/Loading.ts
import { createVNode, render, VNode, App } from 'vue';
import Loading from './index.vue'
export default {
install(app: App) {
//createVNode vue提供的底层方法 可以给我们组件创建一个虚拟DOM 也就是Vnode
const vnode: VNode = createVNode(Loading)
//render 把我们的Vnode 生成真实DOM 并且挂载到指定节点
render(vnode, document.body)
// Vue 提供的全局配置 可以自定义
app.config.globalProperties.$loading = {
show: () => vnode.component?.exposed?.show(),
hide: () => vnode.component?.exposed?.hide()
}
}
}
main.ts
import Loading from './components/loading'
let app = createApp(App)
app.use(Loading)
type Lod = {
show: () => void,
hide: () => void
}
//编写ts loading 声明文件放置报错 和 智能提示
declare module '@vue/runtime-core' {
export interface ComponentCustomProperties {
$loading: Lod
}
}
app.mount('#app')
vue3推荐:deep
A 组件定义一个插槽
我是插槽
在App.vue 引入
单文件组件的
小满是个弟弟
如果是对象 v-bind 请加引号
小满是个弟弟
4.css module
自定义注入名称(多个可以用数组)
你可以通过给 module attribute 一个值来自定义注入的类对象的 property 键
小满是个弟弟
与组合式 API 一同使用
注入的类可以通过 useCssModule API 在 setup() 和
小满是个弟弟
使用场景一般用于TSX 和 render 函数 居多
Tailwind CSS中文官网地址:https://www.tailwindcss.cn/
安装学习地址:http://t.csdn.cn/jrQvZ
JS 执行机制
在我们学js 的时候都知道js 是单线程的如果是多线程的话会引发一个问题在同一时间同时操作DOM 一个增加一个删除JS就不知道到底要干嘛了,所以这个语言是单线程的但是随着HTML5到来js也支持了多线程webWorker 但是也是不允许操作DOM
单线程就意味着所有的任务都需要排队,后面的任务需要等前面的任务执行完才能执行,如果前面的任务耗时过长,后面的任务就需要一直等,一些从用户角度上不需要等待的任务就会一直等待,这个从体验角度上来讲是不可接受的,所以JS中就出现了异步的概念。
同步任务
代码从上到下按顺序执行
异步任务
1.宏任务
script(整体代码)、setTimeout、setInterval、UI交互事件、postMessage、Ajax
2.微任务
Promise.then catch finally、MutaionObserver、process.nextTick(Node.js 环境)
运行机制
所有的同步任务都是在主进程执行的形成一个执行栈,主线程之外,还存在一个"任务队列",异步任务执行队列中先执行宏任务,然后清空当次宏任务中的所有微任务,然后进行下一个tick如此形成循环。
nextTick 就是创建一个异步任务,那么它自然要等到同步任务执行完成后才执行。
{{ text }}
参考:http://t.csdn.cn/AkrHY
参考:http://t.csdn.cn/tD9Nc
ps:打包后白屏,无法解决。爆炸…
开发桌面程序
创建一个vite 项目
npm init vite@latest
安装electron
npm install electron -D
npm install vite-plugin-electron -D
根目录新建 electron / index.ts
修改vite.config.ts 配置文件
引入electron插件配置main entry对应electron的文件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import electron from 'vite-plugin-electron'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), electron({
// 这里需要调整main对象,vite-plugin-electron 0.10.4中使用main会报错。
// main: {
// entry: "electron/index.ts"
// }
entry: "electron/index.ts"
})],
})
编写代码 electron / index.ts
import { app, BrowserWindow } from 'electron'
import path from 'path'
//app 控制应用程序的事件生命周期。
//BrowserWindow 创建并控制浏览器窗口。
let win: BrowserWindow | null;
//定义全局变量获取 窗口实例
const createWindow = () => {
win = new BrowserWindow({
//
webPreferences: {
devTools: true,
contextIsolation: false,
nodeIntegration: true
//允许html页面上的javascipt代码访问nodejs 环境api代码的能力(与node集成的意思)
}
})
if (app.isPackaged) {
win.loadFile(path.join(__dirname, "../index.html"));
} else {
//VITE_DEV_SERVER_HOST 如果是undefined 换成 VITE_DEV_SERVER_HOSTNAME
win.loadURL(`${process.env['VITE_DEV_SERVER_URL']}`);
}
}
//isPackage 不好使换下面的
// if(process.env.NODE_ENV != 'development'){
// win.loadFile(path.join(__dirname, "../index.html"));
// }else{
//win.loadURL(`${process.env['VITE_DEV_SERVER_URL']}`);}`)
// }
//在Electron完成初始化时被触发
app.whenReady().then(createWindow)
配置package json 增加main 字段 type 去掉
{
"name": "my_vite",
"private": true,
"version": "0.0.0",
"main": "dist-electron/index.js",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build && electron-builder",
"preview": "vite preview"
},
"dependencies": {
"cross-env": "^7.0.3",
"vue": "^3.2.45"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.0.0",
"electron": "^22.0.0",
"electron-builder": "^23.6.0",
"typescript": "^4.9.3",
"vite": "^4.0.0",
"vite-plugin-electron": "^0.10.4",
"vue-tsc": "^1.0.11"
},
"build": {
"appId": "com.electron.desktop",
"productName": "electron",
"asar": true,
"copyright": "Copyright © 2022 electron",
"directories": {
"output": "release/"
},
"files": [
"dist-electron"
],
"mac": {
"artifactName": "${productName}_${version}.${ext}",
"target": [
"dmg"
]
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
],
"artifactName": "${productName}_${version}.${ext}"
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": false
},
"publish": [
{
"provider": "generic",
"url": "http://127.0.0.1:8080"
}
],
"releaseInfo": {
"releaseNotes": "版本更新的具体内容"
}
}
}
npm run dev
需要安装electron-builder
npm install electron-builder -D
package json 配置 build 修改npm run build命令
"build": "vue-tsc --noEmit && vite build && electron-builder",
"build": {
"appId": "com.electron.desktop",
"productName": "electron",
"asar": true,
"copyright": "Copyright © 2022 electron",
"directories": {
"output": "release/"
},
"files": [
"dist"
],
"mac": {
"artifactName": "${productName}_${version}.${ext}",
"target": [
"dmg"
]
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
],
"artifactName": "${productName}_${version}.${ext}"
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": false
},
"publish": [
{
"provider": "generic",
"url": "http://127.0.0.1:8080"
}
],
"releaseInfo": {
"releaseNotes": "版本更新的具体内容"
}
}
npm run build
注:将来可能有用
参考:http://t.csdn.cn/EP0wW
// 查看环境变量
console.log(import.meta.env);
/**
* BASE_URL: "/" 路由应用前缀
*
* DEV: true // 是否开发环境
*
* MODE: "development" // 当前运行环境
*
* PROD: false // 生否生产环境
*
* SSR: false // 是否服务端渲染
*/
// 在.env.development里写入
VITE_HTTP=http://www.baidu.com
// 在package.json的dev里添加:
// --mode 配置开发环境的文件名
// 现在已经默认读取了
"scripts": {
"dev": "vite --mode development",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
// 在.env.development里写入
VITE_HTTP=http://www.jd.com
// package.json默认读取production。不需要配置
安装:npm i http-serve -g
输入:http-server -p 9002
// 引入
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default ({ mode }: any) => {
console.log(loadEnv(mode, process.cwd));
return defineConfig({
plugins: [vue()],
})
}
为什么要手写webpack 不用cli (脑子有病)并不是 其实是为了加深我们对webpack 的了解方便以后灵活运用webpack 的技术
参考:http://t.csdn.cn/Alf9Q
我们可以使用谷歌浏览器自带的DevTools 进行性能分析 LightHouse
选项代表意思:
FCP (First Contentful Paint):首次内容绘制的时间,浏览器第一次绘制DOM相关的内容,也是用户第一次看到页面内容的时间。
Speed Index: 页面各个可见部分的显示平均时间,当我们的页面上存在轮播图或者需要从后端获取内容加载时,这个数据会被影响到。
LCP (Largest Contentful Paint):最大内容绘制时间,页面最大的元素绘制完成的时间。
TTI(Time to Interactive):从页面开始渲染到用户可以与页面进行交互的时间,内容必须渲染完毕,交互元素绑定的事件已经注册完成。
TBT(Total Blocking Time):记录了首次内容绘制到用户可交互之间的时间,这段时间内,主进程被阻塞,会阻碍用户的交互,页面点击无反应。 CLS(Cumulative Layout Shift):计算布局偏移值得分,会比较两次渲染帧的内容偏移情况,可能导致用户想点击A按钮,但下一帧中,A按钮被挤到旁边,导致用户实际点击了B按钮。
由于我们使用的是vite vite打包是基于rollup 的我们可以使用 rollup 的插件
npm install rollup-plugin-visualizer
vite.config.ts 配置 记得设置open 不然无效
import { visualizer } from 'rollup-plugin-visualizer';
plugins: [vue(), vueJsx(),visualizer({
open:true
})],
然后进行npm run build打包
build:{
chunkSizeWarningLimit:2000,
cssCodeSplit:true, //css 拆分
sourcemap:false, //不生成sourcemap
minify:false, //是否禁用最小化混淆,esbuild打包速度最快,terser打包体积最小。
assetsInlineLimit:5000 //小于该值 图片将打包成Base64
},
npm install vite-plugin-pwa -D
修改vite.config.ts
import { VitePWA } from 'vite-plugin-pwa'
plugins: [vue(),VitePWA(
workbox:{
cacheId:"XIaoman",//缓存名称
runtimeCaching:[
{
urlPattern:/.*\.js.*/, //缓存文件
handler:"StaleWhileRevalidate", //重新验证时失效
options:{
cacheName:"XiaoMan-js", //缓存js,名称
expiration:{
maxEntries:30, //缓存文件数量 LRU算法
maxAgeSeconds:30 * 24 * 60 * 60 //缓存有效期
}
}
}
]
},
)],
PWA 技术的出现就是让web网页无限接近于Native 应用
可以添加到主屏幕,利用manifest实现
可以实现离线缓存,利用service worker实现
可以发送通知,利用service worker实现
进行 npm run build 打包会生成 sw.js
import lazyPlugin from 'vue3-lazy'
worker脚本与主进程的脚本必须遵守同源限制。他们所在的路径协议、域名、端口号三者需要相同
const myWorker1 = new Worker("./calcBox.js");
都使用postMessage发送消息
worker.postMessage(arrayBuffer, [arrayBuffer]);
都使用onmessage接收消息
self.onmessage = function (e) {
// xxx这里是worker脚本的内容
};
关闭
worker.terminate();
VueUse 库已经集成了 webWorker
同样VueUse 也是集成了
Web Components 提供了基于原生支持的、对视图层的封装能力,可以让单个组件相关的 javaScript、css、html模板运行在以html标签为界限的局部环境中,不会影响到全局,组件间也不会相互影响 。 再简单来说:就是提供了我们自定义标签的能力,并且提供了标签内完整的生命周期 。
参考:https://blog.csdn.net/qq1195566313/article/details/127328300