金闪闪
44.31M · 2026-03-26
安装:
# npm
npm install --save-dev @arco-design/web-vue
# yarn
yarn add --dev @arco-design/web-vue
# 在 main.js 中完整引入
import { createApp } from 'vue'
import ArcoVue from '@arco-design/web-vue'
import App from './App.vue';
import '@arco-design/web-vue/dist/arco.css'
const app = createApp(App)
app.use(ArcoVue)
app.mount('#app')
在组件中即可使用 <a-xxx></a-xxx> 的方式来使用 ArcoDesign 设计好的组件,例如
<template>
<a-space>
<a-button type="primary">Primary</a-button>
<a-button>Secondary</a-button>
<a-button type="dashed">Dashed</a-button>
<a-button type="outline">Outline</a-button>
<a-button type="text">Text</a-button>
</a-space>
</template>
views---AboutView
<template>
<div class="about">
<h1>This is an about page</h1>
<h1 class="text-3xl font-bold underline text-blue-700">Hello world!</h1>
<p>程序员的梦工厂</p>
<a-button type="primary">注册登录</a-button>
<a-avatar :style="{ backgroundColor: '#3370ff' }">
<icon-user />
</a-avatar>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>
TailwindCSS 安装
yarn add tailwindcss@3 postcss autoprefixer -D
npx tailwindcss init -p
tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
@/assets/styles/main.css
@tailwind base;
@tailwind components;
@tailwind utilities;
import { createRouter, createWebHistory } from 'vue-router'
import { isLogin } from '@/utils/auth'
import DefaultLayout from '@/views/layouts/DefaultLayout.vue'
import BlankLayout from '@/views/layouts/BlankLayout.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
component: DefaultLayout,
children: [
{
path: '',
redirect: 'home',
},
{
path: 'home',
name: 'pages-home',
component: () => import('@/views/pages/HomeView.vue'),
},
{
path: 'space/apps',
name: 'space-apps-list',
component: () => import('@/views/space/apps/ListView.vue'),
},
{
path: 'space/apps/:app_id',
name: 'space-apps-detail',
component: () => import('@/views/space/apps/DetailView.vue'),
},
],
},
{
path: '/',
component: BlankLayout,
children: [
{
path: 'auth/login',
name: 'auth-login',
component: () => import('@/views/auth/LoginView.vue'),
},
],
},
],
})
// todo:路由守卫逻辑还未实现
router.beforeEach(async (to, from) => {
if (!isLogin() && to.name != 'auth-login') {
return { path: '/auth/login' }
}
})
export default router
src---views---HomeView
<script setup lang="ts">
import { useAccountStore } from '@/stores/account'
const accountStore = useAccountStore()
function updateName() {
accountStore.update({ name: '小小课' })
}
</script>
<template>
<p>这是主页</p>
<p>当前登录的账号是:{{ accountStore.account.name }}</p>
<p>当前登录的邮箱是:{{ accountStore.account.email }}</p>
<a-button type="primary" @click="updateName">更新名字</a-button>
<a-button @click="accountStore.clear">重置</a-button>
<router-link to="/space/apps">跳转到应用列表</router-link>
</template>
<style scoped></style>
src---stores---account
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 初始值
const initAccount = {
name: '慕小课',
email: 'imooc@163.com',
avatar: '',
}
export const useAccountStore = defineStore('account', () => {
// 1.定义数据
const account = ref({ ...initAccount })
// 2.函数/动作
function update(params: any) {
Object.assign(account.value, params)
}
function clear() {
account.value = { ...initAccount }
}
return { account, update, clear }
})
src---utils---request.ts
import { apiPrefix } from '@/config'
// 1.超时时间为100s
const TIME_OUT = 100000
// 2.基础的配置
const baseFetchOptions = {
method: 'GET',
mode: 'cors',
credentials: 'include',
headers: new Headers({
'Content-Type': 'application/json',
}),
redirect: 'follow',
}
// 3.fetch参数类型
type FetchOptionType = Omit<RequestInit, 'body'> & {
params?: Record<string, any>
body?: BodyInit | Record<string, any> | null
}
// 4.封装基础的fetch请求
const baseFetch = <T>(url: string, fetchOptions: FetchOptionType): Promise<T> => {
// 5.将所有的配置信息合并起来
const options: typeof baseFetchOptions & FetchOptionType = Object.assign(
{},
baseFetchOptions,
fetchOptions,
)
// 6.组装url
let urlWithPrefix = `${apiPrefix}${url.startsWith('/') ? url : `/${url}`}`
// 7.解构出对应的请求方法、params、body参数
const { method, params, body } = options
// 8.如果请求是GET方法,并且传递了params参数
if (method === 'GET' && params) {
const paramsArray: string[] = []
Object.keys(params).forEach((key) => {
paramsArray.push(`${key}=${encodeURIComponent(params[key])}`)
})
if (urlWithPrefix.search(/?/) === -1) {
urlWithPrefix += `?${paramsArray.join('&')}`
} else {
urlWithPrefix += `&${paramsArray.join('&')}`
}
delete options.params
}
// 9.处理post传递的数据
if (body) {
options.body = JSON.stringify(body)
}
// 10.同时发起两个Promise(或者是说两个操作,看谁先返回,就先结束)
return Promise.race([
// 11.使用定时器来检测是否超时
new Promise((resolve, reject) => {
setTimeout(() => {
reject('接口已超时')
}, TIME_OUT)
}),
// 12.发起一个正常请求
new Promise((resolve, reject) => {
globalThis
.fetch(urlWithPrefix, options as RequestInit)
.then((res) => {
resolve(res.json())
})
.catch((err) => {
reject(err)
})
}),
]) as Promise<T>
}
export const request = <T>(url: string, options = {}) => {
return baseFetch<T>(url, options)
}
export const get = <T>(url: string, options = {}) => {
return request<T>(url, Object.assign({}, options, { method: 'GET' }))
}
export const post = <T>(url: string, options = {}) => {
return request<T>(url, Object.assign({}, options, { method: 'POST' }))
}
vite.config.ts
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
rewrite(path) {
return path.replace(/^/api/, '')
},
},
},
},
})
internal---server---http.py
CORS(self, resources={
r"/*": {
"origins": "*",
"supports_credentials": True,
# "methods": ["GET", "POST"],
# "allow_headers": ["Content-Type"],
}
})