vue3+vite+ts 浅显易懂语法整理
由于学习vue3到现在一直没有用到项目上,时间久了不写就容易忘记,整理一篇vue3+vite最新项目构建以及语法糖笔记
上手教程
npm install vite@lastext
推荐使用vscode volar(快捷分割真香)
基础语法
生命周期钩子
setup是围绕beforeCreate和created这两个钩子函数运行的,所以不需要定义它们
| vue2.0 | setup |
|---|
| beforeCreate | setup |
| created | setup |
| beforeMount | onBefooreMount 挂载之前 |
| mountd | onMountd 页面加载完成 |
| beforeUpadte | onBeforeUpadte 更新前 |
| upadte | onUpadte 更新后 |
| beforeUnmount | onBeforeUnmount 组件卸载前 |
| unmounted | onUnmounted 组件卸载后 |
| activated | onActivated 活跃前 |
| deactivated | onDeactivated 活跃后 |
| errorCaptured | onErrorCaptured 子孙组件异常钩子 |
setup语法糖
—优势
|——组件引入无需注册
|——写法上不用写setup函数以及export(优化了一下繁杂的写法)
|——没有this
<script setup lang="ts">
......
</script>
声明响应式变量
ref 建议基本数据类型
reactive 建议复杂数据类型(推荐)
二者区别:ref获取值需要通过.value
import {ref,reactive} from "vue"
const count = ref(0)
const data = reactive({
obj:{
name:'mool'
},
arr:[1,2,3]
})
const data = reactive({
count:1,
obj:{
name:'mool'
},
arr:[1,2,3]
})
typescript
const count = ref<number>(0)
props
defineProps无需引入,defineProps相较与props写法上没有太大出入
defineProps({
msg:String,
age:{
type:Number,
default:() => 10
}
})
<child msg="props"/>
typescript
defineProps<{
msg:string|number,
age?:number
}>()
emit
defineEmits无需引入,需先声明后通过emit调用
const emit = defineEmits(['childEmit'])
emit('childEmit',参数)
<child msg="props" @childEmit="emit"/>
const emit = () => {}
typescript
const emit = defineEmits<{
(event:'childEmit',data:string):void
...
}>()
emit('childEmit',参数)
<child msg="props" @childEmit="emit"/>
const emit = () => {}
useAttrs
获取除了响应式props之外的属性
import {useAttrs} from "vue"
const attr = useAttrs()
useSlots
获取除了响应式props之外的属性
import {useSlots} from "vue"
const slot = = useSlots().default()
expose/ref
2.0通过组件上ref去获取对应组件的实例
3.0有别于需预先通过defineExpose暴露方法以及属性,后声明ref去获取
defineExpose({
child: '子组件',
fn:(value:string)=>{
return value
}
})
<child ref="getRef" msg="props" @childEmit="emit"/>
<script setup lang="ts">
import {ref, onMounted} from "vue"
const refs= ref()
onMounted(()=> {
console.log('ref:', refs)
console.log('fn:', refs.value.fn('111'))
})
</script>
watch和watchEffect
watch (建议使用,代码更具有可观性)
-惰性监听(可通过配置immediate)
-可以监听多个数据的变化
-参数可以拿到变化前后的值
watchEffect
-每次加载都会执行
-不需要传递监听的参数
-只能获取变化后的值
-可以手动停止监听
-自动收集依赖
import {watchEffect,watch} from "vue"
const name = ref('mool')
const data = reactive({name:'yaa'})
watch([name,()=>data.name],(newVal,oldVal)=>{
console.log('newVal:', newVal)
console.log('oldVal:', oldVal)
},immediate:true)
watchEffect(()=>{
console.log('count1111:',data.name)
})
methods
setup中声明函数类似于js声明函数
function fn (params) {
console.log(params)
}
const fn = params => {
console.log(params)
}
typescript
function fn (params:(string|number)) {
console.log(params)
}
const fn = (params: (string | number)): (string | number) => {
console.log(params)
return params
}
withDefaults
给props设置默认值
interface Props {
mag: string,
age?: number
}
withDefaults(defineProps<Props>(), {
msg: 'mool',
age: 10
})
组件通信汇总
- props/emit
- expose/ref
- useAttrs
- v-model
- provide/inject
- vuex
props
跳转props
emit
跳转emit
expose/ref
跳转expose/ref
useAttrs
跳转useAttrs
v-model
<child v-model:msg="msg" v-model:value="value"></child>
const emit = defineEmits(["msg","value"])
const handlerClick = () => { emit("update:msg", "新的msg") emit("update:value", "新的value") }
provide/inject
import { provide } from "vue"
provide("name", "mool")
import { inject } from "vue"
const name = inject("name")
vuex
跳转vuex
vuex
安装4.+:npm install vuex@next
├── store
└── index.ts
└── typeing.ts
└── getters.ts
└── mutations.ts
└── actions.ts
index.ts
import {InjectionKey} from "vue"
import {useStore as baseUseStore, createStore, Store} from "vuex"
import * as type from "./typeing"
import {getters} from "./getters"
import {mutations} from "./mutations"
import {actions} from "./actions"
export const key: InjectionKey<Store<type.State>> = Symbol()
export const store: Store<type.State> = createStore({
state: {
username: 'mool',
role: [],
menu: [{}]
},
getters,
mutations,
actions
})
export const useStore = () => {
return baseUseStore(key)
}
typeing.ts
统一分模块声明state接口,采用接口继承整合接口
interface User {
username: string
}
interface Role {
role: object
}
interface Item {
[index: number]: object
}
export interface State extends User, Role {
menu: Array<Item>
}
getters.ts
import * as type from "./typeing";
export const getters = {
GET_NAME: (state: type.State): string => {
return state.username
}
}
mutations.ts
import * as type from "./typeing";
export const mutations = {
SET_NAME(state: type.State, params: string) {
state.username = params
}
}
actions.ts
import {State} from "./typeing";
export const actions = {
DIS_NAME( context: { commit: any, state: State }, params: string) {
context.commit('SET_NAME', params)
}
}
用法
import {store, key} from "./store"
app.use(store, key)
import {useStore} from "../store"
const store = useStore()
store.commit('SET_NAME', 'yaa')
store.dispatch('DIS_NAME', 'MOOL')
store.getters.GET_NAME
router
安装4.+:npm install vue-router@next
相比于2.0没太大的区别
index.ts
import {createRouter, createMemoryHistory} from "vue-router";
import Home from "../pages/index.vue"
const routes = [
{
path: '/',
component: Home,
}
]
const router = createRouter({
history: createMemoryHistory(),
routes
})
export default router
import router from "./router"
app.use(router)
用法
import { useRouter } from "vue-router"
const router = useRouter()
router.push
...
vite
vite.config.ts
相关配置查看(https://vitejs.dev/config/)
全面些的查看(https://gitee.com/dlhf/admin-ui/blob/main/vite.config.ts)
import {ConfigEnv, defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import {loadEnv} from "vite"
import {resolve} from "path"
export default ({command, mode}: ConfigEnv) => {
return defineConfig({
base: './',
plugins: [vue()],
server: {
host: '0.0.0.0',
port: Number(loadEnv(mode, process.cwd()).VITE_APP_PORT),
strictPort: true,
https: false,
open: false,
proxy: {
"/api": {
target: loadEnv(mode, process.cwd()).VITE_APP_BASE_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, '')
}
},
hmr: {
overlay: false
}
},
resolve: {
alias: {
'@': resolve(__dirname, './src')
}
},
build: {
outDir: 'dist',
assetsDir: "assets",
sourcemap: false,
chunkSizeWarningLimit: 1500,
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
}
}
}
}
})
}