Vue3 + naive-ui + fastapi 使用心得
这段时间一直在使用vue3+naive-ui+fastapi开发 WEB应用,今天找时间做一下总结:
- vue2 和 vue3的区别
- naive-ui 的使用要点
- fastapi 标准接口以及JWT token认证
vue2 和 vue3的写法上的区别
Vue 2 和 Vue 3 在写法上有一些关键区别,主要体现在以下几个方面:
1. 响应式系统
Vue 2
使用 Object.defineProperty()
实现响应式,需要提前声明所有属性。
javascript
data() {
return {
count: 0
}
}
Vue 3
使用 ES6 Proxy 实现响应式,可以动态添加属性。
javascript
import { ref, reactive } from 'vue';
setup() {
// 基本类型用 ref
const count = ref(0);
// 对象/数组用 reactive
const state = reactive({ name: 'Vue 3' });
return { count, state };
}
2. 组件选项式 API → 组合式 API
Vue 2(选项式 API)
javascript
export default {
data() { ... },
methods: { ... },
computed: { ... },
watch: { ... },
mounted() { ... }
}
Vue 3(组合式 API)
javascript
import { ref, computed, onMounted } from 'vue';
export default {
setup() {
// 状态和逻辑可以按功能组织
const count = ref(0);
const double = computed(() => count.value * 2);
const increment = () => count.value++;
onMounted(() => {
console.log('Component mounted');
});
return { count, double, increment };
}
}
3. 生命周期钩子
Vue 2
javascript
export default {
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeDestroy() {},
destroyed() {}
}
Vue 3
javascript
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue';
setup() {
onBeforeMount(() => {});
onMounted(() => {});
onBeforeUpdate(() => {});
onUpdated(() => {});
onBeforeUnmount(() => {}); // 替代 beforeDestroy
onUnmounted(() => {}); // 替代 destroyed
return {};
}
4. 模板语法
Vue 3 新增特性
-
Fragment:支持多个根节点
html<template> <h1>标题</h1> <p>内容</p> </template>
-
Teleport:将内容渲染到 DOM 的其他位置
html<teleport to="body"> <div class="modal">...</div> </teleport>
-
Suspense:异步组件加载
html<suspense> <template #default> <AsyncComponent /> </template> <template #fallback> <div>加载中...</div> </template> </suspense>
5. 组件注册
全局组件(Vue 2 vs Vue 3)
javascript
// Vue 2
Vue.component('MyComponent', { ... });
// Vue 3
const app = createApp(App);
app.component('MyComponent', { ... });
局部组件
javascript
// Vue 2
export default {
components: {
MyComponent: require('./MyComponent.vue').default
}
}
// Vue 3
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
}
}
6. 事件处理
Vue 2
html
<!-- 父组件 -->
<ChildComponent @custom-event="handleEvent" />
<!-- 子组件 -->
this.$emit('custom-event', data);
Vue 3
html
<!-- 父组件 -->
<ChildComponent @custom-event="handleEvent" />
<!-- 子组件(组合式 API) -->
import { defineEmits } from 'vue';
const emits = defineEmits(['custom-event']);
emits('custom-event', data);
7. 其他变化
- Vue 3 移除的 API :
$children
、$on
、$off
、$once
。 - Composition API 优势 :更好的类型支持、逻辑复用(通过
setup()
函数)。 - createApp :Vue 3 使用
createApp()
创建应用实例,更便于 Tree-Shaking。
naive-ui 的使用要点
1. 安装与引入
bash
npm install naive-ui
# 或
yarn add naive-ui
完整引入(推荐开发环境):
javascript
import { createApp } from 'vue';
import App from './App.vue';
import naive from 'naive-ui';
const app = createApp(App);
app.use(naive);
app.mount('#app');
按需引入(生产环境优化):
javascript
import { createApp } from 'vue';
import App from './App.vue';
import { NButton, NInput } from 'naive-ui';
const app = createApp(App);
app.component('NButton', NButton);
app.component('NInput', NInput);
app.mount('#app');
2. 基础组件使用
按钮 (NButton)
vue
<template>
<div>
<n-button type="primary">主要按钮</n-button>
<n-button type="success">成功按钮</n-button>
<n-button @click="handleClick">点击我</n-button>
</div>
</template>
<script setup>
const handleClick = () => {
console.log('Button clicked');
};
</script>
输入框 (NInput)
vue
<template>
<n-input v-model="username" placeholder="请输入用户名" />
</template>
<script setup>
import { ref } from 'vue';
const username = ref('');
</script>
对话框 (NDialog)
vue
<template>
<n-button @click="openDialog">打开对话框</n-button>
</template>
<script setup>
import { useDialog } from 'naive-ui';
const dialog = useDialog();
const openDialog = () => {
dialog.info({
title: '提示',
content: '这是一个对话框',
positiveText: '确定',
onPositiveClick: () => {
console.log('确认操作');
}
});
};
</script>
3. 状态管理与全局配置
主题配置
javascript
import { createApp } from 'vue';
import { create, NConfigProvider } from 'naive-ui';
const naive = create({
theme: {
// 自定义主题变量
common: {
primaryColor: '#165DFF'
}
}
});
const app = createApp(App);
app.use(naive);
全局方法
通过 useDialog
、useMessage
、useNotification
等钩子使用全局组件:
vue
<script setup>
import { useMessage } from 'naive-ui';
const message = useMessage();
const showMessage = () => {
message.success('操作成功');
};
</script>
4. 表单处理
表单验证 (NForm)
vue
<template>
<n-form ref="formRef" :model="formData" :rules="rules">
<n-form-item path="username" label="用户名">
<n-input v-model:value="formData.username" />
</n-form-item>
<n-form-item path="password" label="密码">
<n-input v-model:value="formData.password" type="password" />
</n-form-item>
<n-button type="primary" @click="handleSubmit">提交</n-button>
</n-form>
</template>
<script setup>
import { ref } from 'vue';
const formRef = ref(null);
const formData = ref({
username: '',
password: ''
});
const rules = {
username: {
required: true,
message: '请输入用户名',
trigger: ['input', 'blur']
},
password: {
required: true,
min: 6,
message: '密码至少6位',
trigger: ['input', 'blur']
}
};
const handleSubmit = () => {
formRef.value?.validate((errors) => {
if (!errors) {
console.log('表单提交成功', formData.value);
}
});
};
</script>
5. 布局组件
栅格系统 (NGrid)
vue
<template>
<n-grid :cols="24">
<n-gi span="12">左侧内容</n-gi>
<n-gi span="12">右侧内容</n-gi>
</n-grid>
</template>
卡片布局 (NCard)
vue
<template>
<n-card title="卡片标题" bordered>
<template #header-extra>
<n-button text size="small">更多</n-button>
</template>
<div>卡片内容</div>
</n-card>
</template>
6. 按需加载与国际化
按需加载
使用 unplugin-vue-components
和 unplugin-auto-import
自动导入组件:
javascript
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
export default defineConfig({
plugins: [
vue(),
Components({
resolvers: [NaiveUiResolver()]
})
]
});
国际化
javascript
import { createApp } from 'vue';
import App from './App.vue';
import { createI18n } from 'vue-i18n';
import { zhCN, darkTheme } from 'naive-ui';
const i18n = createI18n({
locale: 'zh-CN',
messages: {
'zh-CN': { ... }
}
});
const app = createApp(App);
app.use(i18n);
app.use(naive);
7. 深色模式
vue
<template>
<n-config-provider :theme="darkTheme ? darkTheme : undefined">
<App />
</n-config-provider>
</template>
<script setup>
import { ref } from 'vue';
import { darkTheme } from 'naive-ui';
const darkTheme = ref(false);
const toggleTheme = () => {
darkTheme.value = !darkTheme.value;
};
</script>
8. 性能优化
- Tree-Shaking:按需引入组件,减少打包体积。
- 虚拟列表 :使用
NList
或第三方库处理大量数据。 - 懒加载 :结合 Vue 的
Suspense
和defineAsyncComponent
实现组件懒加载。
9. 与 TypeScript 集成
Naive UI 内置完整类型定义,组合式 API 中可直接使用:
vue
<script setup lang="ts">
import { ref } from 'vue';
import { NFormInstance } from 'naive-ui';
const formRef = ref<NFormInstance | null>(null);
</script>
10. 自定义样式
通过 CSS 变量覆盖默认样式:
css
:root {
--n-primary-color: #165DFF;
--n-border-radius: 8px;
}