A long time ago, I wrote an article about how to get started with Vue3. X and did some learning with Ant-Design-Vue. At the end of the article I said that there would be a lot of nice UI frameworks as the 3.x version progressed. It wasn’t long before Element-Plus appeared. Recently, Naive UI of University of Utah has also aroused the interest of developers.

Therefore, I began to study its documents with interest. I had never really contacted Vite before, and I also learned how to build a simple front-end project with Vite+Naive.

Install the parts

Vite is a font for Naive people. You need to install vfonts for Naive people. You need to install vfonts for Naive people

Import 'vfonts/ lato.css '// Common fonts import 'vfonts/ Firacode.css' // uniform fontsCopy the code

You also need to install vicons icon library, which is Naive by default.

Layout of the part

The document gives a lot of layout examples, so you just need to choose the paste you want. I chose a layout where the head is fixed to the side sidebar and the right scroll can switch themes. Note that in order to achieve this effect, the outermost parent element needs to have the style position set to relative. The n-layout parent of the header and the n-layout parent of the sidebar must be configured with position=”absolute” and must be configured in the way described in the document. It is not possible to add position: Absolute by styling yourself.

<div class="container"> <! Position :relative --> <n-layout position="absolute"> <Header class=" Header ": Inverted ="inverted" @toggleInverd="toggleInverd" /> <n-layout has-sider position="absolute" class="content"> <Sidebar :inverted="inverted" /> <n-layout content-style="padding: 24px;" > <Breadcrumb /> <n-message-provider> <router-view></router-view> </n-message-provider> </n-layout> </n-layout> </n-layout> </div>Copy the code

Sidebar and routing

The content in the sidebar needs to be generated dynamically through routing. Naive sidebar can be developed in combination with N-Layout-SIDER and Menu component. Naive Menu component is a bright point, but also has some limitations. When developing the side using other UI components, we often need to develop a separate sub-component to place links, titles, etc., and then use the recursion power of the component to generate components based on the route.

But Naive Menu is another minimalist idea. You just call components and add list contents in a sample way to create menus. There are no subcomponents and no recursive nesting.

<n-menu :inverted="inverted" :collapsed-width="64" :collapsed-icon-size="22" @update:value="handleUpdateValue" // Options ="navs" :value="active" />Copy the code

So, for developers, just import the route list and paste it in, but be aware that I may not have read the document carefully. The last name and chart shown in the menu here must be called LLabel and icon in the data list. Otherwise, the menu components will not display properly, and each list item must have a unique key, which can have the same name as the name in the route.

// routes.js import { h, } from "vue"; import Home from '@/components/Home.vue' import { NIcon } from "naive-ui"; import { BookOutline as BookIcon, PersonOutline as PersonIcon, WineOutline as WineIcon, } from "vicons/ionicons-v5"; function renderIcon(icon) { return () => h(NIcon, null, { default: () => h(icon) }); } const routes = [{ path: '/', name: 'Index', key: 'Index', redirect: '/dashboard/index', hidden: true, label: RenderIcon (BookIcon), renderIcon(BookIcon), renderIcon(BookIcon), renderIcon(BookIcon), renderIcon(BookIcon), renderIcon(BookIcon) 'Dashboard', Redirect: '/ Dashboard /index', Component: Home, Label: "Home ", Icon: renderIcon(BookIcon), Meta: {label: }, children: [{path: "/dashboard/index", name: 'DashboardIndex', key: 'DashboardIndex', Component: () => import('../views/HelloWorld.vue'), label: "Hello", icon: renderIcon(BookIcon), meta: { label: "Hello", } }, { path: "/dashboard/page1", name: 'DashboardPage1', key: 'DashboardPage1', component: () => import('../views/ page1.vue '), label: "first page ", icon: renderIcon(PersonIcon), meta: {label: renderIcon(PersonIcon); }}]}, // page 2 {path: "/users", name: 'users ', key:' users ', Redirect: '/users/index', Component: Home, label: "Account ", icon: renderIcon(WineIcon), meta: {label:" account ",}, children: [{path: '/users/index', name: 'UsersIndex', key: 'UsersIndex', component: () => import('../views/ page2.vue '), label: "Page2 ", icon: renderIcon(WineIcon), meta: {label: },}],},] export default routes;Copy the code

But it’s also unlikely that you can simply use the route list as it’s documented. Then there’s the problem, I don’t want to show all the links in the routing list, what do I do? Traditionally, I could add a custom hidden property to a column that doesn’t need to be shown, and then not show it when developing the component. However, Naive menu components are highly packaged and do not provide such judgment to filter the display.

Therefore, it is better to copy a route list and make relevant judgments on the copied route list. But new problems arise if you copy using the simplest form, json.parse (json.stringify (list)), and you find that the list is filtered but the icon is gone.

This is because the icon is generated by h function, it is the type of a function, the JSON to do is copy function, so you need to achieve a real sense of deep copy method, and then with a deep copy to copy a routing table to do filtering, deep copy of the implementation approach has a lot of, online copy, is not in now.

import { useRouter, useRoute } from "vue-router"; import routes from "@/router/routes"; import { deepClone } from "@/utils/index"; let active = ref(""); function filterNavs(ary) { ary.forEach((item, index) => { if (item.children) { filterNavs(item.children); } else { if (item.hidden) { ary.splice(index, 1); }}}); return ary; }... setup() { ... const route = useRoute(); const navs = filterNavs(deepClone(routes)); Const handleUpdateValue = (key, item) => {active.value = key; router.push({ path: item.path }); }; return { navs, handleUpdateValue, ... }}Copy the code

So how to realize the route jump? Because the link form jump cannot be added in the previous way, the menu component gives an update event method, in which the jump route can be configured to realize the jump, as shown in the above code.

Implement global hints with AXIOS

Finally, global hints. Most of the time we want to globally wrap AXIOS and generate a message when a request succeeds or fails. First, I need to introduce axios globally. I’ve wrapped my own HTTP method around AXIos, If it is under the environment of js on vue globalProperties you only need to do it is ok to global configuration ‘app. Config. GlobalProperties. HTTP method, If it is under the environment of js on vue globalProperties you only need to do it is ok to global configuration ` app. Config. GlobalProperties. HTTP method, If it is under the environment of js on vue globalProperties you only need to do it is ok to global configuration ‘app. Config. GlobalProperties. HTTP = $HTTP; ‘But in the TS environment is not allowed, I am not familiar with TS, but also found other blogs to see how to configure.

Ts import $HTTP from "./ API /axios" // Global configuration Declare Module '@vue/ Run-time core' {interface ComponentCustomProperties { $http: Function, } } const app = createApp(App); app.config.globalProperties.$http = $http;Copy the code

Then I use const {CTX} = getCurrentInstance() in the concrete code as before; And CTX.$HTTP to execute the code only to find that it prompts me httpisundefined. Print CTX to find that HTTP is indeed undefined. Print CTX to find that there is indeed no httpisundefined. Printing CTX finds that HTTP is indeed not added. After some baidu research, it is found that if the global Vue method defined in TS environment is added to appContext, relevant methods need to be invoked here.

import { defineComponent, getCurrentInstance } from "vue"; export default defineComponent({ setup() { const { appContext } = getCurrentInstance(); const { $http } = appContext.config.globalProperties; $http({ url: "/test" }); }});Copy the code

At this point the error message can go, but how to display the message? I do not understand the intention of Naive authors. In Naive Naive components such as Mesage and Notification, you need to have a parent layer nested in the outer layer

Use the premise

If you want to use messages, you need to put the component that calls its methods inside the **n-message-provider** and use **useMessage** to get the API.

Ant-design-vue, for example, just introduces Message directly, and I don’t see why there is a layer here. Because hints are something I would use on every page, I put them outside the Router-View

<n-message-provider>
    <router-view></router-view>
</n-message-provider>
Copy the code

So, the container is ready, but if you follow the ant-design-Vue experience and use the introduced message directly, you will be prompted that the corresponding method for message is undefined.

Naive useMessage has to be triggered in a certain DOM structure, or at least in a setup function, but I’m referencing it in my own wrapped Axios function. Where does that happen? In fact, when I call HTTP, I’m going to be calling it from setup, so I’m going to be calling it from setup when I’m encapsulating HTTP, So I just need to call useMessage in my wrapped HTTP method, which has a drawback that I haven’t thought of dealing with yet, namely that every call to $HTTP produces an instance of useMessage, but I’ll think about that later.

// custom axios import {useMessage} from 'naive- UI '; . function $axios(options:any) { ... } function $HTTP (options:any, success:any, failure:any) {const message = useMessage(); return $axios({ ... }) .then(res => { ... message.success(res.message, { duration: 5000 }); }) .catch(err => { ... message.error(res.message, { duration: 5000 }); })}Copy the code

This should display the global AXIos error message properly

conclusion

I have to say that Naive UI is a UI framework for vue3.x with excellent user experience, and the author’s poetic and artistic atmosphere is also revealed in the official documents. As Naive is attracting more and more developers’ attention, we will surely find some shortcomings and welcome several major updates in the future. Let’s all wish Naive UI better and better.