项目初始化
npm init @vitejs/app
1 2 3 4 5
| { Project name 'vue3_demo', framework: 'vue', variant: 'TypeScript' }
|
cd vue3_demo
-> npm i
-> npm run dev
vue3知识
ref和reactive的区别
ref 的作用就是将一个原始数据类型(primitive data type)转换成一个带有响应式特性的数据类型
reactive是用来定义更加复杂的数据类型,但是定义后里面的变量取出来就不在是响应式Ref对象数据了,所以需要用toRefs函数转化为响应式数据对象
reactive 和 ref 都是用来定义响应式数据的 reactive更推荐去定义复杂的数据类型 ref 更推荐定义基本类型
setup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { toRefs } from 'vue' setup(props, context) {
props.title ? (const { title } = toRefs(props)) : ( const title = toRef(props, 'title'))
const {attr,slot, emit} = context
return obj || () => VNode }
|
hook
hook方法需要定义在 setup 顶层
vue动态组件
1
| <component :is="currentTabComponent"></component>
|
JSX使用插槽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| render() { console.log('sidemenu', this.route) console.log('sidemenu', this.menu) const slots = { title: () => <div> {this.itemMenu?.meta?.icon && <i class={this.itemMenu.meta.icon}></i> || null} <span>{this.itemMenu.meta?.title || '默认菜单'}</span> </div> } return ( <el-submenu v-slots={slots} index={this.itemMenu.path}> { this.itemMenu.children?.map((item) => { if (item.children && item.children.length) { return <SideMenuItem itemMenu={item} /> } else { return <el-menu-item index={item.path}>{item.meta?.title || '默认菜单'}</el-menu-item> } }) } </el-submenu> ) },
|
Vue3响应式
Proxy
- 代理,顾名思义,就是在要访问的对象之前增加一个中间层,这样就不直接访问对象,而是通过中间层做一个中转,通过操作代理对象,来实现修改目标对象
reactive
创建响应式代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| function createReactiveObject( target: unknown, toProxy: WeakMap<any, any>, toRaw: WeakMap<any, any>, baseHandlers: ProxyHandler<any>, collectionHandlers: ProxyHandler<any> ) { if (!isObject(target)) { if (__DEV__) { console.warn(`value cannot be made reactive: ${String(target)}`) } return target } let observed = toProxy.get(target) if (observed !== void 0) { return observed } if (toRaw.has(target)) { return target } if (!canObserve(target)) { return target } const handlers = collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers observed = new Proxy(target, handlers) toProxy.set(target, observed) toRaw.set(observed, target) if (!targetMap.has(target)) { targetMap.set(target, new Map()) } return observed } export function reactive(target: object) { if (readonlyToRaw.has(target)) { return target } if (readonlyValues.has(target)) { return readonly(target) }
return createReactiveObject( target, rawToReactive, reactiveToRaw, mutableHandlers, mutableCollectionHandlers ) }
|
vetur 无法识别模块 (强迫症解决)
- 在vscode中添加插件:
Path Intellisense
- vscode设置
1 2 3
| "path-intellisense.mappings": { "@": "${workspaceRoot}/src" },
|
- 项目设置
1 2 3 4
| "paths": { "@/*": ["./src/*"] }
|
搭建项目框架
vue3 + vite + typescript + elementplus
- 第一个页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
<template> <el-form :model="ruleForm" status-icon :rules="rules" ref="refRuleForm" label-width="100px" > <el-form-item label="账号" prop="loginAccount"> <el-input type="text" v-model="ruleForm.loginAccount" autocomplete="off" ></el-input> </el-form-item> <el-form-item label="密码" prop="loginPassword"> <el-input type="password" autocomplete="off" v-model="ruleForm.loginPassword" ></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submit(ruleForm)" >登录</el-button > </el-form-item> </el-form> </template>
<script lang="ts"> import { defineComponent, onMounted, reactive, toRef, toRefs } from 'vue' import {useRouter} from 'vue-router' import {loginService} from '../api/login' import {enCodeMd5, saveLoginInfo} from '@/utils/utils' import {CommonTypeProps} from '../types/common' import { AxiosResponse } from 'axios'
interface RuleFormProps { loginAccount: string loginPassword: string
} export default defineComponent({ setup () { const router = useRouter() const rules: any = { loginAccount: [{ required: true, message: '请输入手机号' }], loginPassword: [{ required: true, message: '请输入手机号' }] } const ruleForm: RuleFormProps = reactive({ loginAccount: '', loginPassword: '' }) const refRuleForm = toRefs(ruleForm) const submit = async (obj: any) => { console.log(obj) try { const res:AxiosResponse<CommonTypeProps.ResponseProps> = await loginService({ ...obj, loginPassword: enCodeMd5(obj.loginPassword) }) console.log('res', res) if (res?.data?.bizCode === 'SUCCESS') { console.log(res.data.respData) saveLoginInfo(res.data.respData) router.push('/') } } catch (error) { } } return { ...refRuleForm, ruleForm, rules, submit } } }) </script>
|
- 路由配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import {RouteRecordRaw} from 'vue-router'
const routes: RouteRecordRaw[] = [ { path: '/login', component: () => import('@/views/login.vue') }, { path: '/', component: () => import('@/views/layout.vue'), redirect: '/index', meta: { name: '首页' }, children: [ { path: 'index', component: () => import('@/views/index/index.vue'), meta: { name: '首页' } }, { path: 'order', component: () => import('@/views/index/index.vue'), meta: { name: '订单' } }, { path: 'goods', component: () => import('@/views/index/index.vue'), meta: { name: '商品' } } ] } ] export default routes
import {createRouter, createWebHashHistory} from 'vue-router' import routes from './route'
const router = createRouter({ history: createWebHashHistory(), routes: routes })
export default router
|
- 动态路由配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const modules = import.meta.glob('../views/**/**.vue') 获取页面文件信息与后台返回的菜单数组匹配,获取路由数组,使用 `addRoute` 方法动态导入到路由中 getMenuDataService().then(res => { if (res.data.bizCode === 'SUCCESS') { const treeData = listToTree(res.data.result) const routerList = addRouteRedirect(treeData) const layout = routes.find((item) => item.name === 'layout')! layout.children = [...layout.children!, ...routerList] router.addRoute(layout) router.addRoute({ path: '/404', component: () => import('@/views/404.vue') }) resolve(layout.children) }
}) .catch((err) => { reject(err) })
|