套用模板
vue-pure-admin
所用主要框架笔记
1. electron
app
const { app } = require('electron')
app.on('事件名', () => {} // 回调函数)
常用事件
- will-finish-launching 当应用程序完成基础的启动的时候触发
- ready:electron完成初始化时触发
- window-all-closed 所有窗口都被关闭时触发
- before-quit 在程序关闭窗口前触发 会返回event 调用event.preventDefault() 将阻止终止应用程序的默认行为
- will-quit 在所有窗口被关闭时触发
- quit 应用程序退出时触发
- open-file 当用户想要在应用中打开一个文件时触发 在windows中
process.argv
可以获取文件路径 - open-url 当用户想要在应用中打开一个url时触发
方法
- app.quit() 尝试关闭所有窗口 会触发before-quit事件
- app.exit([exitcode]) 如果使用exitcode默认退出 不会询问用户
- app.relaunch() 重启应用 此方法不会退出当前应用程序 需要在调用此方法后 在调用app.quit来重启应用
- app.hide() 隐藏所有的应用窗口
- app.show() 显示隐藏后的应用程序窗口
- app.getAppPath() app.getAppPath()
- app.getPath(name) 可以通过名称请求以下路径
- 可以通过名称请求以下路径 可以通过名称请求以下路径
- app.whenReady() 当electron初始化完成时触发
- app.getVersion() 加载应用程序的版本号
- app.getName() 当前应用程序的名称
BrowserView
// 在主进程中.
const { app, BrowserView, BrowserWindow } = require('electron')
app.whenReady().then(() => {
const win = new BrowserWindow({ width: 800, height: 600 })
const view = new BrowserView()
win.setBrowserView()
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadURL('https://electronjs.org')
})
- view.webContents 试图的webcontents对象
- view.setAutoResize([options]) 窗口自动缩放设置
- view.setBounds(bounds) 调整视图的大小,并将它移动到窗口边界
- view.setBackgroundColor(color)
BrowserWindow
- 优雅显示窗口两种方案
- ready-to-show事件
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
win.show() // 初始化完成后在显示
})
- 设置backgroundColor属性(建议使用这个方法 更接近原生 )
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ backgroundColor: '#2e2c29' })
win.loadURL('https://github.com')
- new BrowserWindow([options])
app.whenReady().then(() => {
win = new BrowserWindow({
width: 1024, // 窗口的宽度
height: 768, // 窗口的高度
x: 10, // 窗口相对于屏幕左侧的偏移量 如果有y 为必选 默认是窗口居中
y: 10, // 窗口相对于屏幕顶端的偏移量 默认是窗口居中
useContentSize: false, // 窗口的实际尺寸是否为web页面的尺寸,如果是true包括窗口边框的大小 稍微会大点 默认是false
center: true, // 窗口是否在屏幕居中
minWidth: 1024, // 窗口的最小宽度
minHeight: 768, // 窗口的最小高度
maxWidth: 1024, // 窗口的最大宽度
maxHeight: 790, // 窗口的最大高度
title: "Main window",
resizable: true, // 窗口大小是否可调整
movable: true, // 窗口是否可移动
minimizable: true, // 窗口是否可最小化
maximizable: true, // 窗口是否可以最大化
closable: true, // 窗口是否可关闭
focusable: true, // 窗口是否可聚焦,
alwaysOnTop: true, // 窗口是否永远在别的窗口之上
fullscreen: true, // 窗口是否全屏
skipTaskbar: true, // 是否在任务栏中显示窗口
backgroundColor: "#FFF", // 窗口背景色
hasShadow: true, // 窗口是否有阴影
opacity: 1, // 窗口的透明度
icon: join(process.env.PUBLIC, "favicon.ico"),
webPreferences: {
// 网页功能设置。
preload, // 在页面运行其他脚本之前预先加载指定的脚本 无论页面是否集成Node, 此脚本都可以访问所有Node API 脚本路径为文件的绝对路径
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
nodeIntegration: true, // 是否启用Node integration
contextIsolation: false // 是否在独立 JavaScript 环境中运行 Electron API和指定的preload 脚本.
// ...
}
// ...
});
})
Menu
创建原生应用菜单和上下文菜单
const menu = new Menu() // 创建新菜单
// 静态方法
// 返回应用程序菜单
getApplicationMenu.getApplicationMenu()
// 返回menu template是一个数组 用于构建menuItem
Menu.buildFromTemplate(template)
// 在macOS上将 menu设置成应用内菜单 在windows和Linux上,menu 将会被设置成窗口顶部菜单
Menu.setApplicaionMenu(menu)
MenuItem选项说明
详细文档
- click函数 click点击事件
- role 定义菜单项的操作 例如undo、redo等等
- type:类型
- label 文本
- tooltip菜单项的悬浮文本
- icon
clipboard
在系统剪贴板上执行复制和粘贴操作
const { clipboard } = require('electron')
- 方法
- clipboard.readText() 读取剪贴板内容
- clipboard.writeText(text. [type]) // 将txt写入剪贴板
session
管理浏览器回话、cookie、缓存、代理设置等
- 方法
- getCacheSize 当前session会话缓存大小
- clearCache 当缓存清除操作完成时可获取 清除session的HTTP缓存
cookies
通过Session的cookies属性来访问Cookies的实例
const { session } = require('electron')
const { session } = require('electron')
// 查询所有 cookies。
session.defaultSession.cookies.get({})
.then((cookies) => {
console.log(cookies)
}).catch((error) => {
console.log(error)
})
// 查询所有与设置的 URL 相关的所有 cookies.
session.defaultSession.cookies.get({ url: 'http://www.github.com' })
.then((cookies) => {
console.log(cookies)
}).catch((error) => {
console.log(error)
})
// 设置一个 cookie,使用设置的名称;
// 如果存在,则会覆盖原先 cookie.
const cookie = { url: 'http://www.github.com', name: 'dummy_name', value: 'dummy' }
session.defaultSession.cookies.set(cookie)
.then(() => {
// success
}, (error) => {
console.error(error)
})
2. vite4
文档
搭建vite项目
npm create vite@latest
| npm create vite@latest
| pnpm create vite
功能
通过原生ESM导入提供了许多主要用于打包场景的增强功能
vite天然支持引入.ts
文件 仅支持转椅 不执行任何类型检查 可以通过tsc --noEmit --watch
查看IDE提示 vite-plugin-checker
插件可以在浏览器直接看到上报的类型错误
模块热替换:内置HMR api可以及时准确更新 无需重新加载页面 自动配置了
WebWorkers
一个web worker 可以使用 new Worker()
和new SHareWorker()
导入
推荐使用的导入worker用法
const worker = new Worker(new URL('./worker.js', import.meta.url))
worker构造函数还有用来创建模块worker的选项
const worker = new Worker(new URL('./worker.js', import.meta.url), {
type: 'module',
})
通过?worker
或者?sharedworker
查询参数来直接导入一个web worker脚本
import Myworker from './worker?worker'
const worker = new Muworker()
// worker内联成base64字符串
import MyWorker from './worker?worker&inline'
环境变量
vite在一个特殊的import.meta.env
对象上暴露环境变量
import.meta.env.MODE
应用运行的模式 deveploment(开发) production(生产)import.meta.env.BASE_URL
: 部署应用时的基本urlimport.meta.env.PROD
: 是否在生产环境import.meta.env.DEV
: 是否在开发环境import.meta.env.SSR
: 是否在server上
插件配置
// vite.config.js
import vitePlugin from 'vite-plugin-feature'
import rollupPlugin from 'rollup-plugin-feature'
export default defineConfig({
plugins: [vitePlugin(), rollupPlugin()],
})
配置vite
当以命令行方式运行vite时,vite会自动解析vite.config.js文件
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({command, mode, ssrBuild}) => {
//环境变量可以从process.env获得但是默认vite是不加载.env的 所有可以通过loadEnv来加载
const env = loadEnv(mode, process.cwd(), '')
if (command === 'serve') {
return {
root: '', // 项目根目录 默认: process.cwd()
base: '/', // 开发或者生产环境的公共基础路径
mode: 'development', // 环境
server: { // 服务器选项
hmr: true, // 热重载
host: 'localhost', // 指定服务器应该监听哪个 IP 地址
port: '8080', // 指定开发服务器端口
strictPort: false, // 端口被占用是否退出
https: true, // 是否启用TLS+http/2
open: true, // 开发服务器启东市,自动在浏览器打开应用程序吗
proxy: { // 为开发服务器配置自定义代理规则 跨域代理
'/foo': 'http://localhost:4567',
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
cors: {}, // 为开发服务器配置 CORS
},
optimizeDeps: {}, // 依赖优化选项
ssr: {}, // ssr选项
build: {
target: "modules", // 设置最终构建的浏览器兼容目标
outDir: "dist", // 指定输出路径
cssCodeSplit: true, // css代码是否拆分
sourcemap: false, // 是否生成source map
ssr: false, // 是否服务端渲染
reportCompressedSize: true, // 启用/禁用 gzip 压缩大小报告
// 消除打包大小超过500kb警告
chunkSizeWarningLimit: 4000,
rollupOptions: {
input: {
index: pathResolve("index.html")
},
// 静态资源分类打包
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]"
}
}
},
// 定义全局常量替换方式
define: {
__APP_ENV__: env.APP_ENV
},
plugins: [], // 插件数组
publickDir: 'public', // 相对于项目根目录的相对路径
cacheDir, // 存储缓存文件的目录
resolve: {
alias: {}, // 配置别名
dedupe: [],
browserField: true, // 是否启用对 browser 字段的解析
},
rollupOptions: false, // 设为 false 可以避免 Vite 清屏而错过在终端中打印某些关键信息。命令行模式下可以通过 --clearScreen false 设置。
}
} else {
// command === 'build'
return {
// build 独有配置
}
}
})
3. pinia
官方推荐pinia的原因
特点
- vue2和vue3都支持
- devtools支持追踪actions、mutations的时间线 在组件中展示store
- 热更新
- 可通过插件扩展pinia功能
- 针对ts提供了更完善的类型推导
- 支持服务端渲染
使用
安装
yarn add pinia
vue3使用
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
核心概念
1. 定义store
通过defineStore()定义,他的第一个参数要求是一个独一无二的名字
这个名字 也被用作id,是必须传入的,pinia将用它来连接store和devtools
// 写法一
import { defineStore } from 'pinia'
export const noteStore = defineStore('note', { // 参数
state: () => ({ count: 0 }),
getters: {
double: () => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
// 写法二
export const useCounterStore = defineStore('counter', () => {
const count = ref(0) // 相当于定义state
function increment() { // actions
count.value++
}
return { count, increment }
})
2. 使用store
// 不是响应式的store
<script setup>
import { useCounterStore } from '@/stores/counter'
// 可以在组件中的任意位置访问 `store` 变量 ✨
const store = useCounterStore()
</script>
// 响应式的store storeToRefs
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>
3. state
import { defineStore, mapState, mapWritableState } from "pinia";
export const useTestStore = defineStore("test", {
state: () => {
return {
// 所有属性都会自动推断他们的类型
a: 1,
b: 2
};
}
});
// 获取state
const store = useTestStore();
console.log(store.a++);
// 重置state
store.$reset();
// vue文件中
computed: {
...mapState(useTestStore, ['a']) // 将state设置成只读的计算属性
...mapWritableState(useTestStore, ['a']) // 可以修改的state属性
}
// 变更state
store.$patch({
a: store.a++
})
4. getter
js
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
getters: {
// 自动推断出返回类型是一个 number
doubleCount(state) {
return state.count * 2
},
// 返回类型**必须**明确设置
doublePlusOne(): number {
// 整个 store 的 自动补全和类型标注 ✨
return this.doubleCount + 1
},
},
})
vue
<script setup>
import { useCounterStore } from './counterStore'
const store = useCounterStore()
</script>
<template>
<p>Double count is {{ store.doubleCount }}</p>
<p>User 2: {{ store.doubleCount(2) }}</p>
</template>
5. Action
import { mande } from 'mande'
const api = mande('/api/users')
export const useUsers = defineStore('users', {
state: () => ({
userData: null,
// ...
}),
actions: {
async registerUser(login, password) {
try {
this.userData = await api.post({ login, password })
showTooltip(`Welcome back ${this.userData.name}!`)
} catch (error) {
showTooltip(error)
// 让表单组件显示错误
return error
}
},
},
})
vue
<script setup>
const store = useCounterStore()
// 将 action 作为 store 的方法进行调用
store.randomizeCounter()
</script>
<template>
<!-- 即使在模板中也可以 -->
<button @click="store.randomizeCounter()">Randomize</button>
</template>
订阅action
可以通过store.$onAction
来监听action和他们的结果,$action参数如下
- name action名称
- store store实例
- args 传递给action的参数数组
- after 在action返回或者解决后的狗子
- onError 抛出错误的钩子
const unsubscribe = someStore.$onAction(
({
name, // action 名称
store, // store 实例,类似 `someStore`
args, // 传递给 action 的参数数组
after, // 在 action 返回或解决后的钩子
onError, // action 抛出或拒绝的钩子
}) => {
// 为这个特定的 action 调用提供一个共享变量
const startTime = Date.now()
// 这将在执行 "store "的 action 之前触发。
console.log(`Start "${name}" with params [${args.join(', ')}].`)
// 这将在 action 成功并完全运行后触发。
// 它等待着任何返回的 promise
after((result) => {
console.log(
`Finished "${name}" after ${
Date.now() - startTime
}ms.\nResult: ${result}.`
)
})
// 如果 action 抛出或返回一个拒绝的 promise,这将触发
onError((error) => {
console.warn(
`Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
)
})
}
)
// 手动删除监听器
unsubscribe()
默认情况下,action订阅器会绑定到使用他的组件上,如果组件被卸载 他会自动删除 如果想保留他们 可以穿第二个参数为true
<script setup>
const someStore = useSomeStore()
// 此订阅器即便在组件卸载之后仍会被保留
someStore.$onAction(callback, true)
</script>
4. vue3
reactive
使用注意:不能将一个对象或者数组直接赋值给由reactive创建的对象 这样会导致reactive创建的响应式对象被新赋值的直接代理,在vue3中操作的都是proxy代理对象,所以失去了响应式
解决办法
- 直接通过ref创建对象
- 通过对象[属性] 进行赋值
toRaw
toRow()
方法可以返回由reactive()
、readonly()
、shallowReactive()
或者shallowReadonly()
创建的代理对象的原始对象
使用场景: 想改变ref/reactive的数据 但是又不想更新ui界面的情况下 可以使用toRaw()方法拿到他的原始数据,减少性能的消耗,此方法慎用
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
defineComponent
定义vue组件
参数:
- name
- props
- setup
- render
import { defineComponent } from 'vue'
export default defineComponent({
// 启用了类型推导
props: {
message: String
},
setup(props) {
props.message // 类型:string | undefined
}
})
Vue 3结合element plus table数据更新而视图不更新解决方案
// 方案1:创建一个响应式对象,对象的属性是数组
const data = reactive({
arr: []
});
data.arr = [1, 2, 3]
// 方案2: 使用ref函数
const data = ref([])
data.value = [1, 2, 3]
// 方案3: 使用数组的push方法
const arr = reactive([])
arr.push(...[1, 2, 3])
vue 双向绑定-编辑弹框修改数据后页面数据跟着更改,利用 Object.assign解决对象
const showFormDialog = async (params: UserDetail, index?: any) => {
const obj = Object.assign({}, params);
userDetail.value = obj;
};
vue3监听不到父组件传给子组件的props变化
// vue3props数据复制给data中的key时 监听不到他的变化 要监听props值的变化 然后再赋值给data
watch(
() => props.addDialog,
newValue => (addDialog.value = newValue)
);
defineprops
https://cn.vuejs.org/api/sfc-script-setup.html#defineprops-defineemits
withDefaults
作用是给defineProps绑定默认值的api
export interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
vue3.sync
修饰符移除 只用v-model:属性名代替
v-model:value="activePath"
defineEmits定义emit
const emit = defineEmits(["SelectionChange", "update:page", "update:pagesize"]);
emit("SelectionChange", val);
nextTick用法
import { ref, watch, reactive, nextTick } from "vue";
nextTick(() => {
treeRef.value!.setCheckedKeys(props.checkedKey);
});
父组件调用子组件的方法
用到的知识点:defineExpose:
// 子组件
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
// 父组件
<script>
//注册ref
const areaRef = ref(null);
// 调用子组件方法
areaRef.value.clearValue();
<CascaderProvince ref="areaRef" @changeData="changeData" />
</script>
slot的使用
- 默认插槽
- buttonA组件
<template>
<slot></slot>
</template>
- 使用组件
<buttonA>插入的内容</buttonA>
- 具名插槽
- buttonA组件
<template>
<slot name="append"></slot>
</template>
- 使用组件
<buttonA>
<template v-slot:append> 插入的内容</template>
<template #append> 具名插槽简写-插入的内容</template>
</buttonA>
5. ts
6. element-plus
7. vue-router
Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。功能包括:
useRouter(): Router
返回一个路由器实例 在模板中相当于$router 通过createRouter创建的路由信息可以通过这个方法获取
属性
- currentRoute:当前页面路由信息
- listening
- 允许关闭历史事件的监听器。这是一个为微前端提供的底层 API
- options:创建路由器时的原始选项对象。与createRouter参数中的options对应
- end
- history
- linkActiveClass
- parseQuery
- routes: 应该添加到路由器的初始化路由列表
- scrollBehavior
- sensitive
- strict:是否禁用尾部斜线
- stringifyQuery
方法
- addRoute
- afterEach
- back
- beforeEach
- beforeResolve
- forward
- getRoutes
- go
- hasRoute
- isReady:返回一个promise 会在路由器初始化导航之后被解析,这在服务端渲染中确认服务端和客户端输出一致的时候非常有用
- onError: 捕获路由导航错误
- push
- removeRoute
- replace
- resolve
用到的插件
@pureadmin/descriptions、PureDescriptions、PureDescriptions
都是基于element-plus二次封装的组件
@vueuse/core
veuse是一个基于Composition API的实用函数集合
@vueuse/motion
可组合组件使组件处于运动状态 可以在nuxt中使用
- 全局安装
import { MotionPlugin } from '@vueuse/motion'
const app = createApp(App)
app.use(MotionPlugin)
app.mount('#app')
- 有些设定好的指令 链接
- 属性
initial:元素在被挂载之前将具备的属性。
enter:元素在挂载后将装备的属性。
visible:元素每次出现在视图中时都会装备的属性。一旦它离开了视图,初始属性将被应用。
visible-once:元素出现在视图中时就会显示的属性。
hovered:当指针进入该元素的区域时,该元素将拥有的属性。
focused:当该元素被聚焦时,该元素将装备的属性。
tapped: 点击(鼠标)或点击(t)时元素将装备的属性
varians:设置要 - example
<template>
<div
v-motion
:initial="{ opacity: 0, y: 100 }"
:enter="{ opacity: 1, y: 0,
scale: 1 }"
:hovered="{ scale: 1.2 }"
:delay="200"
/>
</template>
animate.css 动画样式库
dayjs 类似于moment 格式化时间
element-resize-detector 监听元素宽度变化
mitt
一个200字节的小型函数时事件发射器/发布订阅器,用于实现模块之间的通信、ui交互等等
NProgress 浏览器顶部的进度条
responsive-storage
响应式本地存储
完全兼容vue2和vue3
知识点总结
import.meta.glob
vite支持使用特殊的import.meta.glob函数从文件系统导入多个模块 为异步加载模块
const modules = import.meta.glob(
["./modules/**/*.ts", "!./modules/**/remaining.ts"] // 该文件下除了remaining.ts的所有ts文件
{ eager: true } // 这个参数可以同步引入所有的模块,如果没有的话 匹配的文件默认是懒加载的
)
获取MAC地址
/**获取mac地址信息 */
import { networkInterfaces } from "os";
export const getMacAddress = function (): string {
const interfaces = networkInterfaces();
let macAddress = "";
for (const interfaceName of Object.keys(interfaces)) {
const interfaceInfos = interfaces[interfaceName];
if (interfaceInfos) {
for (const interfaceInfo of interfaceInfos) {
if (interfaceInfo.mac && interfaceInfo.mac !== "00:00:00:00:00:00") {
macAddress = interfaceInfo.mac;
break;
}
}
}
if (macAddress.length > 0) break;
}
return macAddress;
};
js 计算浮点数精度问题
- 使用toFixed
parseFloat((数学表达式).toFixed(digits)); // toFixed() 精度参数须在 0 与20 之间
- Math.js
- decimal.js
- big.js