vue3 admin 后台管理项目小计

Naive UI全局挂载useDialog、useMessage

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
  }
}

Naive UI Dialog 自定义 content render NInput输入框 + 校验

render 中 NInput 的value 必须定义onUpdateValue 才能更新视图

效果
vue3 admin 后台管理项目小计_第1张图片

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 字节跳动开源图标库

为啥IconPark 而不是iconfont? iconfont前段时间挂了 & IconPark 图标还挺好看 & 尝点新鲜的
1.注册-创建项目-添加图标-生成在线链接
2.index.html header 新增一个script 引入链接
vue3 admin 后台管理项目小计_第2张图片
vue3 admin 后台管理项目小计_第3张图片
常见问题 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全局变量挂载、输出打包时间及环境|esbuild 移除console

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 ;`
)

vue3 admin 后台管理项目小计_第4张图片

router-view/keep-alive 视图白屏问题

appMain.vue

    
      
        
          
        
      
    

初次进入路由时页面展示正常,再次进入时页面空白,devtools中keepAlive组件下为空
页面组件如下
Grid组件是封装了一个table CURD业务组件,基本上所有的页面都只有这一个组件


  1. 即使vue3支持template下有多个根节点 keepalive包裹的组件需要只有一个根元素 不能是fragment
  2. keepalive包裹的组件需设置name (unplugin-vue-define-options/vite 插件)
  3. (不建议)给router-view 设置key = route.fullPath 解决白屏 但keep-alive会失效

修改如下

defineOptions({
  name: 'Pool'
})
....

异步路由 动态导入

路由资源由接口返回,需将资源中Component组件字符串转换为路由组件地址,实现动态导入
vue3 admin 后台管理项目小计_第5张图片
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()

你可能感兴趣的:(import,this,ui,javascript,vue.js,vue,前端框架)