با vue-element-admin به سرعت SPAهای پیچیده بسازید

نوشته امانوئل جان✏️
معماری اپلیکیشن تک صفحه ای (SPA) یکی از بزرگترین گرایش ها در توسعه وب برای مدتی در حال حاضر بوده است. به عنوان توسعه دهندگان، فریم ورک های جاوا اسکریپت مانند Angular، React، Svelte و Vue.js به شما امکان می دهند با استفاده از یک رابط خط فرمان (CLI) یک SPA ایجاد کنید. برخی از مواردی که ممکن است به SPA نیاز داشته باشید عبارتند از:
- هنگامی که در حال ساخت یک برنامه تجارت الکترونیک مانند Jumia یا یک سرویس پخش فیلم مانند Netflix هستید
- معمولاً وقتی در حال ساخت داشبورد مدیریت هستید
داشبوردهای مدیریت پیچیده هستند زیرا درخواست های شبکه، نمودارها، ارتباطات بلادرنگ، جداول داده، اجزای رابط کاربری و موارد دیگر را مدیریت می کنند. به دلیل پیچیدگی، تیم های توسعه دهنده تمایل به خرید قالب های از پیش ساخته شده و سفارشی سازی آنها دارند.
اما اگر یک توسعهدهنده frontend هستید که عمدتاً با Vue.js کار میکنید، vue-element-admin یکی از بهترین قالبهای مدیریت رایگان و منبع باز Vue است. در این مقاله، نحوه استفاده از vue-element-admin را یاد می گیریم و برخی از ویژگی های آن را بررسی می کنیم.
پرش به جلو:
چیست vue-element-admin
?
vue-element-admin سلف vue-admin-template است. این یک راه حل آماده تولید و فرانت اند برای رابط های مدیریت است که از آن استفاده می کند element-ui
ابزار. این الگو دارای بسیاری از ویژگی های پیچیده است که می توانید برای داشبوردهای سطح سازمانی استفاده کنید.
بیایید برخی از ویژگی های اصلی این پروژه را بررسی کنیم.
احراز هویت
داشبورد مدیریت باید قابلیت ورود به سیستم را برای تأیید یک کاربر داشته باشد. در vue-admin-template، عمل ورود اطلاعات کاربر (نام کاربری و رمز عبور) را به سرور ارسال میکند و سرور رمزی را برمیگرداند که در یک کوکی ذخیره میشود:
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
مجوز
یکی دیگر از ویژگی های مهم داشبورد مدیریت، تعیین نقش ها و مجوزهای کاربر است. در این الگو، نقش کاربر از توکن برگشتی از سرور به دست می آید. نقش کاربر تعیین می کند که به کدام مسیر می توانند دسترسی داشته باشند. این به صورت پویا محاسبه می شود:
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else {
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
const { roles } = await store.dispatch('user/getInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
} catch (error) {
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) { next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
قطعه کد بالا نحوه اجرای مجوزهای سطح صفحه در این الگو را نشان می دهد. کاربران با مجوزهای مختلف، نوارهای کناری متفاوتی را مشاهده می کنند و فقط می توانند تعداد محدودی از صفحات را وارد کنند. اگر جدول مسیریابی شما به صورت پویا در backend تولید می شود، ممکن است ترجیح دهید این را سفارشی کنید.
اجزای رابط کاربری
همانطور که قبلاً گفته شد، vue-element-admin از این استفاده می کند element-ui
جعبه ابزار UI. داشبوردهای مدیریت به اجزای قابل استفاده مجدد زیادی نیاز دارند و این الگو بیش از 25 مؤلفه رابط کاربری از جمله DragSelect
، ErrorDialog
، MarkdownEditor
، Pagination
، Charts
، و بیشتر.
Layout
جزء
یکی از اولین مؤلفهها یا نماهایی که هنگام ساخت داشبورد پیادهسازی میکنید، این است Layout
جزء. vue-element-admin
شامل:
- یک نوار کناری
- یک نوار ناوبری
-
TagsView
- محتوا
طرح بندی یک صفحه در پیکربندی روتر تعریف شده است:
{
path: '/401',
component: () => import('@/views/error-page/401'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'dashboard', affix: true }
}
]
},
این پیکربندی سفارشی کردن نوار کناری را برای مطابقت با نقش کاربر آسان می کند.
درخواست های شبکه
داشبوردهای مدیریت بسیاری از نقاط پایانی API را از باطن مصرف میکنند، بنابراین داشتن یک جریان سازمانیافته مهم است. vue-element-admin
این را به شیوه ای بسیار واضح و مختصر مدیریت می کند، بنابراین بیایید آن را تجزیه کنیم.
اول، ما یک request
ابزاری که می پیچد axios
. request
همه را اداره می کند POST
، GET
و سایر پارامترهای درخواست؛ سرصفحه های درخواست؛ و پیام های خطا درخواستهای API ماژولهایی هستند src/api
; یک درخواست معمولی به این صورت است:
export function getInfo(token) {
return request({
url: '/vue-element-admin/user/info',
method: 'get',
params: { token }
})
}
سپس ماژول شبکه وارد می شود vue-store
اقدامات، مانند این:
import { getInfo } from '@/api/user'
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
if (!data) {
reject('Verification failed, please Login again.')
}
const { roles, name, avatar, introduction } = data
// roles must be a non-empty array
if (!roles || roles.length <= 0) {
reject('getInfo: roles must be a non-null array!')
}
commit('SET_ROLES', roles)
commit('SET_NAME', name)
commit('SET_AVATAR', avatar)
commit('SET_INTRODUCTION', introduction)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
نمودار
داشبوردها نمودارهای زیادی برای فرم ها و داده های مختلف دارند. این یکی دیگر از نیازهای رایج است. این الگو Apache ECharts را توصیه می کند، یک کتابخانه تجسم جاوا اسکریپت قدرتمند، با استفاده آسان و انعطاف پذیر.
من شخصاً این کتابخانه را به کتابخانههای نمودارهای دیگر ترجیح میدهم، زیرا گالری گستردهاش را دارد، که هنگام پیادهسازی نمودارها برای مشتریانی که مطمئن نیستند میخواهند دادهها را نشان دهند، مفید است. ما در این مقاله به طور عمیق به ECcharts نخواهیم پرداخت. شما می توانید مستندات آنها را در اینجا بررسی کنید.
ساختمان با vue-admin-template
تا اینجا، ویژگی های آن را بررسی کرده ایم vue-admin-template
; بیایید پیش برویم و نحوه راهاندازی سریع داشبورد مدیریت با قالب را نشان دهیم.
پیش نیازها
مطمئن شوید که موارد زیر را نصب کرده اید:
این پروژه همچنین از یک سرور ساختگی استفاده می کند که با آن پیاده سازی شده است mockjs
. می توانید پیاده سازی ساختگی را در آن پیدا کنید ~/mock
.
پس از شبیه سازی مخزن، اجرا کنید npm install
برای نصب وابستگی های پروژه هدایت به src/router
و اصلاح کنید index.js
با این قطعه کد:
//src/router
/* eslint-disable */
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import Layout from '@/layout'
export const constantRoutes = [
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index')
}
]
},
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/auth-redirect',
component: () => import('@/views/login/auth-redirect'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error-page/404'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error-page/401'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'dashboard', affix: true }
}
]
},
{
path: '/posts',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/posts/index'),
name: 'Posts',
meta: { title: 'Posts', icon: 'post', affix: true }
}
]
},
{
path: '/profile',
component: Layout,
redirect: '/profile/index',
hidden: true,
children: [
{
path: 'index',
component: () => import('@/views/profile/index'),
name: 'Profile',
meta: { title: 'Profile', icon: 'user', noCache: true }
}
]
}
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
const createRouter = () => new Router({
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
نصب روتر Vue
این پروژه از Vue Router 3 استفاده می کند. در اینجا، ما دو نوع مسیر داریم: asyncRoutes
و constantRoutes
.
مسیرهای ثابت جهانی هستند. هر کاربر به این مسیرها دسترسی دارد، در حالی که مسیرهای غیر همگام به صورت پویا بر اساس نقش کاربر بارگذاری می شوند. یک مسیر معمولی مدیریت به صورت زیر خواهد بود:
{
path: '/transactions',
component: Layout,
redirect: '/transactions/info',
alwaysShow: true, // will always show the root menu
name: 'Transactions',
meta: {
title: 'Transactions',
icon: 'lock',
roles: ['superadmin', 'admin'] },
children: [
{
path: 'info',
component: () => import('@/views/transactions/info/index'),
name: 'TransactionInfo',
meta: {
title: 'Transactions Info',
roles: ['superadmin']
}
},
}
سپس به src/dashboard/views/index بروید و کد را با این تغییر دهید:
//src/dashboard/views/index
<template>
<div class="dashboard-editor-container">
<panel-group @handleSetLineChartData="handleSetLineChartData" />
<el-row style="background: #fff; padding: 16px 16px 0; margin-bottom: 32px">
<line-chart :chart-data="lineChartData" />
</el-row>
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<raddar-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<pie-chart />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<bar-chart />
</div>
</el-col>
</el-row>
<el-row>
<el-col
:xs="{ span: 24 }"
:sm="{ span: 24 }"
:md="{ span: 24 }"
:lg="{ span: 24 }"
:xl="{ span: 24 }"
style="padding-right: 8px; margin-bottom: 30px"
>
<post-table />
</el-col>
</el-row>
</div>
</template>
<script>
import PanelGroup from "./components/PanelGroup";
import LineChart from "./components/LineChart";
import RaddarChart from "./components/RaddarChart";
import PieChart from "./components/PieChart";
import BarChart from "./components/BarChart";
import PostTable from "./components/PostTable";
const lineChartData = {
newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165],
actualData: [120, 82, 91, 154, 162, 140, 145],
},
messages: {
expectedData: [200, 192, 120, 144, 160, 130, 140],
actualData: [180, 160, 151, 106, 145, 150, 130],
},
purchases: {
expectedData: [80, 100, 121, 104, 105, 90, 100],
actualData: [120, 90, 100, 138, 142, 130, 130],
},
shoppings: {
expectedData: [130, 140, 141, 142, 145, 150, 160],
actualData: [120, 82, 91, 154, 162, 140, 130],
},
};
export default {
name: "DashboardAdmin",
components: {
PanelGroup,
LineChart,
RaddarChart,
PieChart,
BarChart,
PostTable,
},
data() {
return {
lineChartData: lineChartData.newVisitis,
};
},
methods: {
handleSetLineChartData(type) {
this.lineChartData = lineChartData[type];
},
},
};
</script>
افزودن اجزای رابط کاربری
اگر با آن کار کرده اید element-ui
قبل از این، این اجزای رابط کاربری بسیار آشنا به نظر می رسند. در بالا، یک کامپوننت view جدید را معرفی کردیم، PostTable
. بیایید جلوتر برویم و این را بررسی کنیم.
یک فایل Vue جدید با نام ایجاد کنید PostTable.vue
که در src/views/dashboard/admin/components
و این خطوط کد را اضافه کنید:
//src/views/dashboard/admin/components/PostTable.vue
<template>
<el-table
v-loading="listLoading"
:data="list"
border
fit
highlight-current-row
style="width: 100%"
>
<el-table-column align="center" label="ID" width="">
<template slot-scope="{ row }">
<span>{{ row.id }}</span>
</template>
</el-table-column>
<el-table-column width="" align="center" label="Date">
<template slot-scope="{ row }">
<span>{{ row.timestamp | parseTime("{y}-{m}-{d} {h}:{i}") }}</span>
</template>
</el-table-column>
<el-table-column width="" align="center" label="Author">
<template slot-scope="{ row }">
<span>{{ row.author }}</span>
</template>
</el-table-column>
<el-table-column width="" label="Importance">
<template slot-scope="{ row }">
<svg-icon
v-for="n in +row.importance"
:key="n"
icon-class="star"
class="meta-item__icon"
/>
</template>
</el-table-column>
<el-table-column class-name="status-col" label="Status" width="">
<template slot-scope="{ row }">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
</template>
<script>
import { fetchList } from "@/api/article";
export default {
name: "PostTable",
filters: {
statusFilter(status) {
const statusMap = {
published: "success",
draft: "info",
deleted: "danger",
};
return statusMap[status];
},
},
data() {
return {
list: null,
listLoading: true,
listQuery: {
page: 1,
limit: 5,
},
};
},
created() {
this.getList();
},
methods: {
async getList() {
this.listLoading = true;
const { data } = await fetchList(this.listQuery);
const items = data.items;
this.list = items.map((v) => {
return v;
});
this.listLoading = false;
},
},
};
</script>
در نهایت در جدول مسیرمان مسیر را تعریف کردیم @/views/posts/index
; بیایید آن را ایجاد کنیم. ایجاد یک post/index.vue
در دایرکتوری views و این خطوط کد را اضافه کنید:
//src/post/index.vue
<template>
<div class="app-container">
<el-table
v-loading="listLoading"
:data="list"
border
fit
highlight-current-row
style="width: 100%"
>
<el-table-column align="center" label="ID" width="80">
<template slot-scope="{ row }">
<span>{{ row.id }}</span>
</template>
</el-table-column>
<el-table-column width="180px" align="center" label="Date">
<template slot-scope="{ row }">
<span>{{ row.timestamp | parseTime("{y}-{m}-{d} {h}:{i}") }}</span>
</template>
</el-table-column>
<el-table-column width="120px" align="center" label="Author">
<template slot-scope="{ row }">
<span>{{ row.author }}</span>
</template>
</el-table-column>
<el-table-column width="100px" label="Importance">
<template slot-scope="{ row }">
<svg-icon
v-for="n in +row.importance"
:key="n"
icon-class="star"
class="meta-item__icon"
/>
</template>
</el-table-column>
<el-table-column class-name="status-col" label="Status" width="110">
<template slot-scope="{ row }">
<el-tag :type="row.status | statusFilter">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column min-width="300px" label="Title">
<template slot-scope="{ row }">
<template v-if="row.edit">
<el-input v-model="row.title" class="edit-input" size="small" />
<el-button
class="cancel-btn"
size="small"
icon="el-icon-refresh"
type="warning"
@click="cancelEdit(row)"
>
cancel
</el-button>
</template>
<span v-else>{{ row.title }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="Actions" width="120">
<template slot-scope="{ row }">
<el-button
v-if="row.edit"
type="success"
size="small"
icon="el-icon-circle-check-outline"
@click="confirmEdit(row)"
>
Ok
</el-button>
<el-button
v-else
type="primary"
size="small"
icon="el-icon-edit"
@click="row.edit = !row.edit"
>
Edit
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { fetchList } from "@/api/article";
export default {
name: "Posts",
filters: {
statusFilter(status) {
const statusMap = {
published: "success",
draft: "info",
deleted: "danger",
};
return statusMap[status];
},
},
data() {
return {
list: null,
listLoading: true,
listQuery: {
page: 1,
limit: 10,
},
};
},
created() {
this.getList();
},
methods: {
async getList() {
this.listLoading = true;
const { data } = await fetchList(this.listQuery);
const items = data.items;
this.list = items.map((v) => {
this.$set(v, "edit", false); // https://vuejs.org/v2/guide/reactivity.html
v.originalTitle = v.title; // will be used when user click the cancel botton
return v;
});
this.listLoading = false;
},
cancelEdit(row) {
row.title = row.originalTitle;
row.edit = false;
this.$message({
message: "The title has been restored to the original value",
type: "warning",
});
},
confirmEdit(row) {
row.edit = false;
row.originalTitle = row.title;
this.$message({
message: "The title has been edited",
type: "success",
});
},
},
};
</script>
عالی. اکنون سرور توسعه دهنده خود را با آن اجرا کنید npm run dev
: برنامه آزمایشی ما، با شروع
npm run dev
کلیک وارد شدن و شما باید چیزی شبیه به این را ببینید: این خانه داشبورد است. کلیک نوشته ها، و شما باید چیزی شبیه به این را ببینید:
این شبیه یک داشبورد انتشار وبلاگ است، درست است؟
vue-element-admin
همچنین ویرایشگرهایی مانند TinyMCE و MarkdownEditor را به عنوان کامپوننت ارائه می دهد، بنابراین می توانید آنها را مستقیماً در این داشبورد ادغام کنید.
بیشتر بدانید vue-element-admin
از اسناد آن در اینجا.
نتیجه
داشبوردهای مدیریت یکی از وظایف اجتناب ناپذیری است که به شما به عنوان یک توسعه دهنده فرانت اند انجام می شود. vue-element-admin
یک قالب کاملا رایگان و منبع باز برای شما فراهم می کند تا بتوانید داشبورد را به راحتی بوت استرپ کنید. گردش کار، فهرست پروژه و پیکربندی مسیریابی به اندازه کافی برای برنامه های تک صفحه ای سطح سازمانی استاندارد هستند.
در این مقاله، ویژگی های اصلی را بررسی کردیم vue-element-admin
و به ساخت داشبورد مدیریت انتشارات وبلاگ ادامه داد.
برنامه های Vue خود را دقیقاً همانطور که یک کاربر انجام می دهد تجربه کنید
اشکال زدایی برنامه های Vue.js می تواند دشوار باشد، به خصوص زمانی که ده ها، اگر نه صدها جهش در طول یک جلسه کاربر وجود داشته باشد. اگر علاقه مند به نظارت و ردیابی جهش های Vue برای همه کاربران خود در تولید هستید، LogRocket را امتحان کنید.
LogRocket مانند یک DVR برای برنامه های وب و تلفن همراه است که به معنای واقعی کلمه هر چیزی را که در برنامه های Vue شما اتفاق می افتد از جمله درخواست های شبکه، خطاهای جاوا اسکریپت، مشکلات عملکرد و موارد دیگر ضبط می کند. به جای حدس زدن چرایی مشکلات، می توانید در مورد وضعیتی که برنامه شما در هنگام بروز مشکل در آن قرار داشت، جمع آوری کرده و گزارش دهید.
پلاگین LogRocket Vuex جهشهای Vuex را در کنسول LogRocket ثبت میکند، و زمینهای را در مورد اینکه چه چیزی منجر به خطا شده است، و اینکه برنامه در چه وضعیتی در هنگام بروز مشکل بوده است را به شما میدهد.
نحوه اشکال زدایی برنامه های Vue خود را مدرن کنید – نظارت را به صورت رایگان شروع کنید.