2021/9/19
长沙,周四,晴
修改别人的代码bug很痛苦,目前我就是这样,看上一个前端小子的uniapp,优化和解决一些问题。自己负责的项目使用vue3重构工作也只能搁浅一段时间,记录一下使用vue3。
首先是代码版本:package.json文件
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"serve": "vite preview"
},
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.15.2",
"echarts": "^5.1.2",
"element-plus": "^1.0.2-beta.70",
"vue": "^3.2.4",
"vuex": "^4.0.1",
"vuex-persistedstate": "^4.0.0-beta.3"
},
"devDependencies": {
"@types/node": "^15.14.1",
"@vitejs/plugin-vue": "^1.2.4",
"@vue/compiler-sfc": "^3.1.4",
"typescript": "^4.3.5",
"vite": "^2.4.0",
"vue-tsc": "0.0.24"
}
vite.config.ts配置就不贴代码了,都是一些常规,项目是一个类似数据管理系统,页面特别多,使用标签页遍历出来页面视图,每一个视图都是一个vue文件,使用v2的时候使用component标签,在is上绑定resolve => require(['./components' + item.URL],resolve),在v3的时继续使用直接无效,官方提供了defineAsyncComponent方法实现,结合vite的摇树优化,可以使用import.meta.glob('../contentChild//')先去加载所有页面的()=>import(url),再使用vue的components接收一个对象,用一个对象去给import.meta.glob每一个函数套上一层defineAsyncComponent方法,部分代码:
import Error404 from '@/components/error/404.vue'
import PageLoading from '@/components/loading.vue'
import networkError from '@/components/error/networkError.vue'
const Components: any = {
Error404,
networkError,
}
const handleComName = function (url: string, sign: boolean): string {
const Name = url
.substring(url.substring(0, url.lastIndexOf('/')).lastIndexOf('/'))
.replace(/\//gi, '')
.replace('.vue', '')
return sign ? Name : Components[Name] ? Name : 'Error404'
}
// @ts-ignore
const Modeuls: any = import.meta.glob('../contentChild/*/*')
const AsyncComOptions = {
// 工厂函数
loader: null,
// 加载异步组件时要使用的组件
loadingComponent: PageLoading,
// 加载失败时要使用的组件
errorComponent: networkError,
// 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
// delay: 20000,
// 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
// 默认值:Infinity(即永不超时,单位 ms)
timeout: 3000,
// 定义组件是否可挂起 | 默认值:true
// suspensible: false,
/**
*
* @param {*} error 错误信息对象
* @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
* @param {*} fail 一个函数,指示加载程序结束退出
* @param {*} attempts 允许的最大重试次数
*/
onError(error: any, retry: any, fail: any, attempts: any) {
if (error.message.match(/fetch/) && attempts <= 3) {
// 请求发生错误时重试,最多可尝试 3 次
retry()
} else {
// 注意,retry/fail 就像 promise 的 resolve/reject 一样:
// 必须调用其中一个才能继续错误处理。
fail()
}
},
}
Object.keys(Modeuls).map((item) => {
const com = handleComName(item, true)
Components[com] = defineAsyncComponent({
...AsyncComOptions,
loader: Modeuls[item],
})
})
export default defineComponent({
name: 'Tabs',
components: Components,
setup(){
// 标签页集合
const tabs: Array<IMenu> = reactive([])
// 当前激活的标签页
const currentTabValue = ref<string | null>(null)
const addTab = (data: IMenu) => {
const ModelValue = data.isDialog ? 'CDID' : 'URL'
const CurrentURL:string | null = data[ModelValue] as string | null
console.log(CurrentURL);
// 判断是否在标签栏里已经打开了点击的菜单
const { is, index } = Lookup(tabs, CurrentURL, ModelValue)
// !is && tabs.push(Object.freeze(data))
if (is) {
currentTabValue.value = CurrentURL
tabs[index] = data
} else {
// 如果没找到页面,则判断是否有菜单名称,如果没有菜单名称,则不是点击左侧菜单进来,而是子页面主动跳转,跳转中可能存在url在数据库被改动,而前端未做同步,那么就跳转到错误页面
const Tab = data.CDMC
? data
: {
CDID: '404',
CDMC: '路径错误',
CZLX: '404',
FJID: 0,
ID: '404',
URL: '../../components/error/networkError.vue',
XH: '404',
child: null,
menuHide: true,
}
tabs.push(Object.freeze(Tab))
currentTabValue.value = CurrentURL
data.isDialog && ctx.emit('update:modelValue', Tab)
}
}
// 点击一个标签页
const activeTab = (tab: any) => {
ctx.emit('update:modelValue', tabs[tab.index])
}
watch(
() => props.modelValue,
(val) => {
currentTabValue.value = val.URL
addTab(val)
}
)
const currentComNameFN = function (url: string): string {
const tempUrl = url.substring(url.indexOf("\/")+1,url.length)
return tempUrl.substring(0,tempUrl.indexOf("\/"))
}
return {
currentTabValue,
tabs,
currentComNameFN,
}
}
})
<el-tabs
class="tabs-box"
v-model="currentTabValue"
type="card"
@tab-remove="removeTab"
@tab-click="activeTab"
>
<el-tab-pane
v-for="(item, index) in tabs"
:key="item.CDID"
:name="item.URL.indexOf('/com/') === -1 ? item.URL : item.CDID"
:closable="index !== 0"
>
<div class="contentChild-box">
<keep-alive>
<suspense>
<component
:key="item.CDID"
:is="currentComNameFN(item.URL)"
v-bind:formoptions="item.formoptions"
v-bind:formdata="item.formdata"
v-bind:tabid="item.CDID"
></component>
</suspense>
</keep-alive>
</div>
</el-tab-pane>
</el-tabs>
代码没有贴完,有一些删改,大致就是这样。