من اینجا اعتراف میکنم که یکی از سخت ترین کارهای دنیا ساخت Data Table هاست. مخصوصا اگر شما با حجم زیادی از اطلاعات سروکار داشته باشید; این مسئله پیچیده تر میشه. اما در نهایت من موفق شدم! توی این پست میخوام براتون توضیح بدم که چجوری با استفاده از Vue.js جدولی بسازیم که بسیار هماهنگ باشه و جدای اون قابلیت شخصی سازی بسیار زیادی هم داشته باشه.
اول از همه ، واقعا همیشه نیاز نیست که شما بیاید و مثل من دوباره از اول چرخ رو اختراع کنید! همیشه از قبل کسانی بودند که همچین نیازی داشتند و این نیاز رو در قالب Framework و یا Component در آوردن که شما بتونید به راحتی به خواسته خودتون برسید. به طور مثال تو همهی کتابخونههای معروف Vue.js مثل Vuetify که من توی پروژهام استفاده کردم ، این قابلیت به صورت پیشفرض وجود داره!
سازندهی زبان برنامه نویسی C++ یه جملهی معروف داره که میگه:
The standard library saves programmers from having to reinvent the wheel.
-Bjarne Stroustrup
درسته که Bjarne Stroustrup این حرف رو برای زبان برنامه نویسی C++ زده ولی این جمله همه جا کاربرد داره!
حالا که میدونید نباید چرخ رو از اول اختراع کرد ، فکر میکنید من چرا دارم این کار رو میکنم؟
ما توی پروژهامون نیاز داشتیم تا وقتی کاربر روی هر ردیف از Table که رفت بتونه کلیک راست کنه و یه صفحهی جدید از اون لینک باز بشه! این چیز خیلی ساده به نظر میاد! شاید الان با خودتون فکر کنید که خب این که خیلی سادهاس و فقط نیاز داره که یک تگ a بزاریم وسط اون tr>td ها که کار راه بیوفته!
اما نه به همین راحتی ها هم نبود! بزارید بهتون نشون بدم که چرا این روش جواب نمیگیره....
<tbody> <tr> <a href="/hello"> <td>تست</td> <td>تست</td> <td>تست</td> </a> </tr> </tbody
اگر شما اینجوری بخواید row های یک جدول رو لینک کنید به بخش دیگه ، دچار یک مشکل بزرگ میشید. اول اینکه CSS هاتون رو هرجوری که بنویسید ظاهر این جدول به درستی درنمیاد چون توی استاندارد W3C این کار اشتباه محض هست!
که خب من در تلاش اولام این اشتباه رو انجام دادم! راه حل دوم چی بود؟ خب گفتم حالا که اینجوری نمیشه قطعا یکی دیگه به همین مشکل خورده و توی اینترنت راه حل هایی باید وجود داشته باشه!
دست از تلاش برنداشتم! همینجوری گشتم و گشتم و گشتم و فهمیدم که بله یه راه حل هایی هست اما همشون باعث اضافه شدن پیچیدگیهایی به ساختار Component میشن که اصلا نیازی نیست.
یکی از راه حل ها اینجوری بود که میگفت: خب بجای اینکه تگ a کل tr رو بپوشونه بیا و تگ a رو بزار توی td که جای درست و استاندارداش اونجاست و برای اینکه کل ردیف ام لینک بشه از جاوا اسکریپت استفاده کن!
این راه حل جواب میده! ولی دقیقا اون چیزی نیست که باید باشه.
نفر بعدی که بهم جواب داد واقعا آدم فنیای بود ولی بازم نتیجه دلخواه منو نداشت. اون آدم اینجوری میگفت: چه کاریه که بخوای کلیک راست داشته باشی؟ هروقت که کاربر روی یک ردیف کلیک چپ کرد اون ردیف رو با دستور زیر توی یک تب جدید باز کن; اینجوری نیازی هم به کلیک راست ندارند و همه چی توی تب جدید باز میشه! کدی هم که باید بنویسی مثل این میشه:
let routeData = this.$router.resolve({name: 'routename'}); window.open(routeData.href, '_blank');
این راه حل خیلی خوب بود! ولی مدیر فنی ما حتما میگفت که باید امکان کلیک راست وجود داشته باشه! اینجوری شد که من مجبور شدم تا از اول چرخ رو اختراع کنم و یک جدول با استفاده از تگ div بسازم!
تگ div دیگه هیچکدوم از این قوانین رو نداشت و هرجوری که بخوای میتونی ازش استفاده کنی. پس من شروع به کار شدم و یه کامپوننت به اسم Table.vue تو ابزارهام اضافه کردم!
اگر شما هم مشکل منو دارید دیگه از اول چرخ رو اختراع نکنید! من یه دونه ساختم و بیاید از چرخ من استفاده کنید و برای خودتون شخصی سازیاش کنید. این کامپوننت vue.js رو میتونید از این لینک پیداش کنید.
برای استفاده کردن از این کامپوننت فقط کافیه این دو خط زیر بخونید تا خودتون کلیت قضیه رو متوجه بشید!
اول از همه باید این کامپوننت رو import کنید! با دستور زیر میتونید این کار رو تو بخش script انجام بدید.
import Table from "@/components/Utility/Table" export default { name: "Home", components: { Table }, }
بعد از اینکه به درستی این کار رو انجام دادید فقط کافیه که جدول خودتون رو بسازید ولی قبلش نیازه که حتما عنوان هاتونو از قبل تعریف کنید. برای تعریف عنواین میتونید از بخش data این کار رو انجام بدید.
data(){ return {} headers: [ { text: "نام کمپین", value: "name", width: "250", isOrder: false }, { text: "شماره", value: "id", width: "80", isOrder: false }, { text: "مشتری", value: "customer", width: "120", isOrder: false }, { text: "فاکتور", value: "factorId", isOrder: false }, ], orderMode: "DESC", } },
اگر دقت کنید من بجز هدرهایی که تعریف کردم یه متغیر به اسم orderMode ام تعریف کردم تا نوع مرتب سازی اطلاعات رو تعریف کنم.
این جدول همهی اطلاعاتی که نیاز داره رو از سرور به صورت فایل json دریافت میکنه. من همهی دیتا هایی که نیاز بوده رو توی متغیری به اسم campaigns ذخیره کردم.
<Table :tableLength="campaigns.length"> <template v-slot:header> <div role="row"> <div v-for="h in headers" :key="h.value" role="columnheader"> <span v-if="h.value === 'customer'"> {{h.text}} </span> <span v-else @click="sortByHeaders(h.value)"> {{ h.text }} <v-icon v-if="h.isOrder" x-small> {{orderMode === "DESC" ? "mdi-arrow-down" : "mdi-arrow-up"}} </v-icon> </span> </div> </div> <template> <template v-slot:body> <nuxt-link v-for="item in campaigns" :key="item.id" :to="'/campaigns/' + item.hash" role="row"> <div role="cell"> {{item}} </div> </nuxt-link> </template> <Table>
در نهایت به هچین چیزی برای جدول میرسیم. فقط یه نکتهای بگم که من یه قابلیت برای مرتب سازی بر اساس هر عنوان هم اضافه کردم که تابع sortByHeader این کار رو انجام میده و دلیل اینکه من برای عنوان مشتری این قابلیت مرتب سازی رو نذاشتم اینه که نام مشتریها نیازی به مرتب سازی نداشتند و اگر کاربر رو بخش نام مشتری بزنه هیچ اتفاقی نمیافته.
امیدوارم پست براتون کاربردی بوده باشه و اگر سوالی داشتی بهم ایمیل بزنید خوشحال میشم بتونم کمکتون کنم. ایمیل من: hasanparasteh@gmail.com