App.vue
AppMain.vue
import { useDialog, useMessage } from 'naive-ui'
window.$useDialog = useDialog()
window.$message = useMessage()
global.d.ts
import type { DialogApiInjection } from 'naive-ui/lib/dialog/src/DialogProvider'
import type { MessageApiInjection } from 'naive-ui/lib/message/src/MessageProvider'
declare global {
interface Window {
$message: MessageApiInjection
$useDialog: DialogApiInjection
}
}
render 中 NInput 的value 必须定义onUpdateValue 才能更新视图
import { NFormItem, type FormItemRule} from 'naive-ui'
...
const controlRemark = ref('')
const controlRemarkRef = ref(null)
const rule: FormItemRule = {
trigger: ['input', 'blur'],
validator() {
if (!controlRemark.value.trim()) {
return new Error('你的校验提示语!')
}
}
}
window.$useDialog.warning({
title: '提示',
style: {
width: '500px'
},
content: () =>
h(
'div',
{
class: 'text-base'
},
[
h('div', ['您确认一些操作【', h('i', orderNo), '】记录?']),
h(
'div',
{ class: 'text-gray text-sm pt-1 pb-1' },
'descdescdescdesc'
),
h(
NFormItem,
{
ref: controlRemarkRef,
label: 'label',
labelPlacement: 'left',
rule
},
() =>
h(NInput, {
clearable: true,
autofocus: true,
placeholder: 'placeholder',
type: 'textarea',
value: controlRemark.value,
maxlength: 255,
showCount: true,
onUpdateValue: (val: any) => {
controlRemark.value = val
},
class: 'text-left'
})
)
]
),
positiveText: '确定',
negativeText: '取消',
iconPlacement: 'top',
maskClosable: false,
onPositiveClick: async () => {
return new Promise((resolve, reject) => {
controlRemarkRef.value?.validate('blur', (errors) => {
if (errors) {
reject()
} else {
...your logic here
}
})
})
},
onNegativeClick: async () => {
return true
}
})
为啥IconPark 而不是iconfont? iconfont前段时间挂了 & IconPark 图标还挺好看 & 尝点新鲜的
1.注册-创建项目-添加图标-生成在线链接
2.index.html header 新增一个script 引入链接
常见问题 Failed to resolve component: iconpark-icon
解决方案 vite.config.ts
...
plugins:[
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === 'iconpark-icon'
}
}
}),
vueJsx({
isCustomElement: (tag) => tag === 'iconpark-icon'
}),
...
]
vite.config.ts
const __APP_INFO__ = {
pkg: { dependencies, devDependencies, name, version },
lastBuildTime: moment().format('YYYY年MM月DD日 HH:mm:ss')
}
...
define: {
// fix process is not defined https://github.com/vitejs/vite/issues/1973#issuecomment-787571499
'process.platform': null,
__APP_INFO__: JSON.stringify(__APP_INFO__)
},
...
esbuild: {
drop: mode === 'production' ? ['console', 'debugger'] : undefined
},
main.ts
const { lastBuildTime, pkg } = __APP_INFO__
const viteMode = import.meta.env.MODE || 'production'
const title = pkg.name + ' ' + pkg.version
const content = viteMode + ' ' + lastBuildTime
console.log(
`%c ${title} %c ${content} `,
`padding: 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060 ;`,
`padding: 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e ;`
)
appMain.vue
初次进入路由时页面展示正常,再次进入时页面空白,devtools中keepAlive组件下为空
页面组件如下
Grid组件是封装了一个table CURD业务组件,基本上所有的页面都只有这一个组件
修改如下
defineOptions({
name: 'Pool'
})
....
路由资源由接口返回,需将资源中Component组件字符串转换为路由组件地址,实现动态导入
vue2中的动态导入实现
// _import_production.js
module.exports = file => () => {
file = file.indexOf('/views/') === 0 ? file.slice(7) : file
let obj
try {
obj = import('@/views/' + file)
} catch (e) {
obj = import('@/views/errorPage/404')
}
return obj
}
....
// 遍历后台传来的路由字符串,转换为组件对象
route.component = _import(route.component); // 导入组件
vue3+viteGlob 导入
const Layout = () => import('@/layout/index.vue')
const modules = import.meta.glob(`@/views/**/**.vue`)
export const NotFoundRoutes: Array = [{ path: '/:pathMatch(.*)', redirect: '/404', hidden: true }]
......
export const filterAsyncRouteForSSO = (resourceList: RouterRowTy[]) => {
return resourceList.map((route: any) => {
if (route.component === 'layout') {
route.component = Layout
} else {
route.component = modules[route.component]
}
if (route.children && route.children.length) {
route.children = filterAsyncRouteForSSO(route.children)
}
return route
})
}
...
// 生成路由模块动态导入
let filterAsyncRoutes = filterAsyncRouteForSSO(resourceList)
// NotFoundRoutes 异常匹配路由 须放在路由匹配规则的最后
filterAsyncRoutes = [filterAsyncRoutes, NotFoundRoutes].flat()