image.png

项目配置: TS + vite + Naive UI + hooks(替换vuex)
官网:https://www.naiveui.com/ 关于我们使用ts, vite,是因为我们之前项目已有积累, 不使用element, iview, antd,是因为相比于Naive而言,需要处理vue2的一些历史债务,有些历史包袱,最后用下来整体感觉很不错,丝滑,部分组件是使用不习惯, 老项目迁移的话不推荐, 新项目的可以考虑哦!

这里说下一些开发中的项目槽点

关于全局组件调用(Messge, dialog, loadingBar等)的使用

如官网所说
image.png
所以在我们项目里,一般也会拆出layout,划出子路由,最后有了

先挂载

  1. <template>
  2. <n-config-provider
  3. :locale="zhCN"
  4. :date-locale="dateZhCN"
  5. :theme="local.theme"
  6. :theme-overrides="themeOverrides"
  7. >
  8. <n-global-style />
  9. <n-notification-provider>
  10. <n-loading-bar-provider>
  11. <n-dialog-provider>
  12. <n-message-provider>
  13. <router-view />
  14. </n-message-provider>
  15. </n-dialog-provider>
  16. </n-loading-bar-provider>
  17. </n-notification-provider>
  18. </n-config-provider>
  19. </template>
  20. <script lang="ts" setup>
  21. import { zhCN, dateZhCN } from "naive-ui";
  22. import { useTheme } from "@/hooks/useTheme";
  23. let { themeOverrides, local } = useTheme();
  24. </script>
  25. <style lang="scss">
  26. @import "./styles/index.scss";
  27. </style>

再注册

  1. <script lang="ts" setup>
  2. import { useMessage,useNotification, useLoadingBar, useDialog } from 'naive-ui';
  3. import Menu from "./Menu.vue";
  4. import Tabs from "./Tabs.vue";
  5. import Header from "./Header.vue";
  6. import { useTheme } from '@/hooks/useTheme';
  7. const {local} = useTheme()
  8. window.$message = useMessage();
  9. window.$notification = useNotification()
  10. window.$loadingBar = useLoadingBar()
  11. window.$dialog = useDialog()
  12. </script>

在子路由中使用

  1. function onDel(row) {
  2. window.$loadingBar?.start();
  3. setTimeout(() => {
  4. window.$loadingBar?.finish();
  5. console.log("删除", row);
  6. }, 2000);
  7. }

ts文件声明(不写会标红哦)

  1. import type {
  2. LoadingBarProviderInst,
  3. DialogProviderInst,
  4. MessageProviderInst,
  5. NotificationProviderInst
  6. } from 'naive-ui';
  7. declare global {
  8. interface Window {
  9. $loadingBar?: LoadingBarProviderInst;
  10. $dialog?: DialogProviderInst;
  11. $message?: MessageProviderInst;
  12. $notification?: NotificationProviderInst;
  13. }
  14. }

权限树挂载

如果有初始默认值,一般是异步返回的值, 必须判断有数据的情况下,不然无法挂载成功

下拉菜单形式

  1. <n-tree-select
  2. v-if="props.detail?.id && modelRef.permissionIds.length > 0 || !props.detail"
  3. multiple
  4. cascade
  5. checkable
  6. clearable
  7. show-path
  8. key-field="id"
  9. label-field="permissionName"
  10. :options="authState.allPermission"
  11. :default-value="modelRef.permissionIds"
  12. :on-update:value="handleUpdateValue"
  13. />

直接tree类型转化

  1. <n-tree
  2. v-if="props.detail?.id && modelRef.permissionIds.length > 0 || !props.detail"
  3. block-line
  4. cascade
  5. checkable
  6. key-field="id"
  7. label-field="permissionName"
  8. :data="authState.allPermission"
  9. :default-checked-keys="modelRef.permissionIds"
  10. @update:checked-keys="handleUpdateValue"
  11. />

image.png

分页器和data-table混合使用

分页器可以独立使用, 也可以混合在table中使用,
以下是理想中的样式

image.png
作为分页器其实大概是需要4个值(当前页, 页码, 共多少条, 共多少页)

  1. pagination: {
  2. pageSize: 10,
  3. page: 1,
  4. pageCount: 1,
  5. itemCount: 0,
  6. prefix({ itemCount }) {
  7. return `共${itemCount}条`;
  8. },
  9. },

注意 row-key指定唯一ID remote 非常重要, 不加的话pageCount和itemCount,不能同时生效(同理分页器)

  1. <n-data-table
  2. :loading="loading.table"
  3. :columns="state.columns"
  4. :data="state.list"
  5. row-class-name="table-row"
  6. :row-key="(row) => row.key"
  7. remote //非常重要
  8. :pagination="state.pagination"
  9. @update:page="handlePageChange"
  10. />

关于列表渲染的列表维护