Skip to content
On this page

NaiveUI 的安装

我们把基本的全家桶安装完成之后,就该开始配置 UI 组件库了。那么作为一个脚手架安装 UI 组件库,有以下几种方式。

全局安装(不推荐)

import { createApp } from 'vue'
import naive from 'naive-ui'

const app = createApp(App)
app.use(naive)
1
2
3
4
5

然后在全局直接使用

<template>
  <n-button>naive-ui</n-button>
</template>
1
2
3

缺点:当你去使用一个 UI 组件库的时候,你会发现有很多的组件,其实你本没有使用,但是这样引入的话,会导致,整体打出来的包很大。

使用 UMD

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <script src="https://unpkg.com/vue"></script>
    <!-- 会使用最新版本,你最好指定一个版本 -->
    <script src="https://unpkg.com/naive-ui"></script>
  </head>
  <body>
    <div id="app">
      <n-button>{{ message }}</n-button>
    </div>
    <script>
      const App = {
        setup() {
          return {
            message: 'naive'
          }
        }
      }
      const app = Vue.createApp(App)
      app.use(naive)
      app.mount('#app')
    </script>
  </body>
</html>
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

在页面中直接加载 umd 版本,好处就是利用了 http 的多个下载线程,直接下载 UI 组件库的包,速度比全局要快。缺点就是依旧包很大,整体下载的意义不大。

按需全局安装

typeScript
import { NInput , useMessage } from 'naive-ui'

export const setupUi = (app: App): void => {
    const components = [NInput]

    components.forEach((component) => {
        app.component(component.name, component)
    })

    app.config.globalProperties.$message = useMessage
}
1
2
3
4
5
6
7
8
9
10
11

按照前文的说法,可以做一个创建,然后再 main.ts 种引入,最后做到按需部分加载,这样的设计在 webpack 中很常见,可以省去在.vue页面中的直接引用。

页面中按需引用

html
<template>
  <n-button>naive-ui</n-button>
</template>

<script setup lang='ts'>
import { NButton } from 'naive-ui'

</script>
1
2
3
4
5
6
7
8

自动引入

我个人学习的时候,发现这种方式可能是 vite 中的一大特色,他可以做到直接使用,并且直接处理对应管理,已达到项目中,即不用再页面中引入,又可以按需加载。

按需自动加载UI组件:   unplugin-vue-components

安装

pnpm i -D unplugin-auto-import

该插件主要作用是省去每次使用一个自定义组件,或 UI 组件库的组件时对组件的引入。兼容不同 UI 组件库,需要在安装对应 UI 组件库的前提下,并引入对应 UI 组件库的 resolvers

改组件提供各种 UI 组件库的 resolvers

// 当引入 "unplugin-vue-components/vite 组件之后,页面中需要引入组件的地方就都不需要引入了
import Components from "unplugin-vue-components/vite";
// 引入对应 UI库的 resolver,则对应UI组件库的组件也不需要单独引入了
import {
    AntDesignVueResolver,
    ElementPlusResolver,
    VantResolver,
    NaiveUiResolver,
} from "unplugin-vue-components/resolvers";
1
2
3
4
5
6
7
8
9

AutoImport

// 实现 Vue及Vue相关的库、api的 按需加载
import AutoImport from "unplugin-auto-import/vite";
AutoImport({
    imports: ["vue", "vue-router", "pinia"],
})
1
2
3
4
5

举一个例子

typescript
<script setup>
   <!-- ref 也不需要引入 -->
     const counter = ref(0);
     const add = () => counter.value++;
</script>
<template>
      <div>{{ counter }}</div>
      <button @click="add">counter+1</button>
    <!-- 以下组件都可以直接引入 -->
    <Foo></Foo>
    <el-button>elmentplus button</el-button>
    <n-button>naiveui button</n-button>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13

处理 vite.config.ts 文件

通常看到的 config 文件

typescript
export default defineConfig({
   plugins: [vue()]
})
1
2
3

这样写的缺点就是在未来,我想要配置多的 mode (模式) 的时候就会有一些问题

import { loadEnv } from 'vite'
import type { UserConfig, ConfigEnv } from 'vite'

const CWD = process.cwd();
export default ({ mode }: ConfigEnv): UserConfig => {
 const { VITE_NODE_ENV } = loadEnv(mode, CWD)
 const isProd = ['development', 'test', 'production'].includes(VITE_NODE_ENV)

 return {
   plugins: [vue()]
 }
}
1
2
3
4
5
6
7
8
9
10
11
12

配置自动导入

typescript
import vue from "@vitejs/plugin-vue";

// 当引入 "unplugin-vue-components/vite 组件之后,页面中需要引入组件的地方就都不需要引入了
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
import type { UserConfig, ConfigEnv } from "vite";

const CWD = process.cwd();
export default ({ mode }: ConfigEnv): UserConfig => {
  const { VITE_NODE_ENV } = loadEnv(mode, CWD);
  const isProd = ["development", "test", "production"].includes(VITE_NODE_ENV);
  console.log(isProd);

  return {
    plugins: [
      vue(),
      AutoImport({
        imports: [
          "vue",
          "vue-router",
          "pinia",
          {
            "naive-ui": [
              "useDialog",
              "useMessage",
              "useNotification",
              "useLoadingBar",
            ],
          },
        ],
      }),
      Components({
        resolvers: [NaiveUiResolver()],
      }),
    ],
  };
};
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

写一个页面测试一下

<template>
  <n-menu v-model:value="activeKey" mode="horizontal" :options="menuOptions" />

  <n-layout has-sider>
    <n-layout-sider content-style="padding: 24px;"> 海淀桥 </n-layout-sider>
    <n-layout>
      <n-layout-header>颐和园路</n-layout-header>
      <n-layout-content content-style="padding: 24px;">
        <router-view />
      </n-layout-content>
      <n-layout-footer>成府路</n-layout-footer>
    </n-layout>
  </n-layout>
</template>

<script lang="ts" setup>
import type { MenuOption } from "naive-ui";
import { RouterLink } from "vue-router";

const options: MenuOption[] = [
  {
    label: () =>
      h(
        RouterLink,
        {
          to: {
            name: "Home",
            params: {
              lang: "zh-CN",
            },
          },
        },
        { default: () => "回家" }
      ),
    key: "hear-the-wind-sing",
  },
  {
    label: () =>
      h(
        RouterLink,
        {
          to: {
            name: "About",
            params: {
              lang: "zh-CN",
            },
          },
        },
        { default: () => "About" }
      ),
    key: "a-wild-sheep-chase",
  },
];

const activeKey = ref<string | null>(null);
const menuOptions = reactive(options);
</script>

<style scoped>
.n-layout-header,
.n-layout-footer {
  background: rgba(128, 128, 128, 0.2);
  padding: 24px;
}

.n-layout-sider {
  background: rgba(128, 128, 128, 0.3);
}

.n-layout-content {
  background: rgba(128, 128, 128, 0.4);
}
</style>

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

页面成果

image.png

沪ICP备20006251号-1