رندر کردن لیست در Vue.js — از صفر تا صد
Vue.js یک فریمورک وباپلیکیشن با استفاده آسان است که میتواند برای توسعه اپلیکیشنهای تعامل در سمت فرانت مورد استفاده قرار گیرد. در این مقاله به بررسی روشهای مختلف رندر کردن لیست در Vue.js میپردازیم. اینها میتوانند شامل رندر کردن بازهای از اعداد، رندر کردن کامپوننت، قالب و موارد دیگر باشند.
v-for با یک بازه
v-for میتواند یک عدد صحیح برای رندر کردن یک بازه از اعداد بگیرد.
برای نمونه اگر فایل src/index.js مانند زیر داشته باشیم:
1new Vue({
2 el: "#app",
3 data: {}
4});
و فایل index.html به صورت زیر باشد:
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>App</title>
5 <meta charset="UTF-8" />
6 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
7 </head>
8<body>
9 <div id="app">
10 <span v-for="num in 10">
11 {{num}}
12 </span>
13 </div>
14 <script src="src/index.js"></script>
15 </body>
16</html>
در این صورت نتیجه زیر به دست میآید:
1 2 3 4 5 6 7 8 9 10
از v-for میتوان برای تعریف حلقهای روی عناصر template استفاده کرد. برای نمونه میتوانیم در فایل src/index.js کدی مانند زیر بنویسیم:
1new Vue({
2 el: "#app",
3 data: {}
4});
و اگر در فایل index.html کدی مانند زیر داشته باشیم:
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>App</title>
5 <meta charset="UTF-8" />
6 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
7 </head>
8 <body>
9 <div id="app">
10 <template v-for="num in 10">
11 <span>
12 {{num}}
13 </span>
14 <span>|</span>
15 </template>
16 </div>
17 <script src="src/index.js"></script>
18 </body>
19</html>
در این صورت نتیجه زیر به دست میآید و روی صفحه نمایش مییابد:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
v-for با v-if
در صورتی که این دو با هم استفاده شوند، v-for اولویت بالاتری نسبت به v-if خواهد داشت. با این حال نباید آنها را از این جهت که v-for تقدم بالاتری نسبت به v-if دارد با هم استفاده کنیم. اگر میخواهید برخی عناصر را در زمان رندر کردن آیتمهای یک آرایه فیلتر کنید، باید از یک «مشخصه محاسبه شده» (Computed Property) بهره بگیرید.
اگر تنها بخش کوچکی از عناصر یک آرایه قرار است رندر شود، باید روی کل لیست بچرخد و بررسی کند آیا عبارت مورد نظر شرایط خواسته شده را دارد یا نه. برای نمونه به کد جاوا اسکریپت و HTML زیر توجه کنید:
- فایل src/index.js
1new Vue({
2 el: "#app",
3 data: {
4 numbers: [1, 2, 3, 4, 5]
5 }
6});
- فایل index.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>App</title>
5 <meta charset="UTF-8" />
6 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
7 </head>
8 <body>
9 <div id="app">
10 <span v-for="num in numbers" v-if="num !== 3">
11 {{num}}
12 </span>
13 </div>
14 <script src="src/index.js"></script>
15 </body>
16</html>
این کد چندان کارآمد نیست، زیرا هر بار که حلقه رندر میشود، Vue باید روی همه عناصر بچرخد و بررسی کند آیا num!== 3 مقدار true دارد یا نه. به جای آن باید از مشخصه محاسبه شده به صورت زیر استفاده کنیم.
- فایل src/index.js
1new Vue({
2 el: "#app",
3 data: {
4 numbers: [1, 2, 3, 4, 5]
5 },
6 computed: {
7 not3() {
8 return this.numbers.filter(p => p !== 3);
9 }
10 }
11});
- فایل index.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>App</title>
5 <meta charset="UTF-8" />
6 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
7 </head>
8 <body>
9 <div id="app">
10 <span v-for="num in not3">
11 {{num}}
12 </span>
13 </div>
14 <script src="src/index.js"></script>
15 </body>
16</html>
کد فوق کارایی بالایی دارد، زیرا not3 تنها زمانی مجدداً محاسبه میشود که numbers تغییر یابد. ضمناً تنها آیتمهای not3 در زمان رندر بررسی میشوند و از این رو v-for لازم نیست روی همه آیتمها بچرخد. همچنین منطق کمتری در قالب وجود دارد و موجب میشود که تمیز بماند و نگهداری کد آسانتر باشد.
با انتقال v-if به عنصر والدی که v-for دارد میتوانیم مزیتهای عملکردی بیشتری نیز به دست آوریم، زیرا هر آنچه درون آن است تنها زمانی رندر مجدد میشود که شرط مورد نظر برقرار باشد. به مثال زیر توجه کنید:
- فایل src/index.js
1new Vue({
2 el: "#app",
3 data: {
4 persons: ["Joe", "Jane", "Mary"],
5 show: false
6 }
7});
- فایل index.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>App</title>
5 <meta charset="UTF-8" />
6 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
7 </head>
8 <body>
9 <div id="app">
10 <div v-if="show">
11 <div v-for="person in persons">
12 {{person}}
13 </div>
14 </div>
15 </div>
16 <script src="src/index.js"></script>
17 </body>
18</html>
در این حالت هیچ چیز رندر نمیشود، زیرا show به صورت false است. Vue نیازی به بررسی عناصر داخلی ندارد. این وضعیت بسیار بهتر است:
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>App</title>
5 <meta charset="UTF-8" />
6 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
7 </head>
8 <body>
9 <div id="app">
10 <div v-for="person in persons" v-if="show">
11 {{person}}
12 </div>
13 </div>
14 <script src="src/index.js"></script>
15 </body>
16</html>
در کد فوق Vue باید روی همه مداخل بچرخد و بررسی کنید آیا شرط در v-if مقدار درستی بازگشت میدهد یا نه. همچنان که میبینیم با این که کد تفاوت اندکی یافته است، اما عملکرد به میزان زیادی ارتقا یافته است.
v-for با یک کامپوننت
از v-for میتوان روی کامپوننتهای سفارشی مانند دیگر عناصر استفاده کرد. برای نمونه میتوانیم کدی مانند زیر بنویسیم:
- فایل src/index.js
1Vue.component("num", {
2 props: ["num"],
3 template: "<span>{{num}}</span>"
4});
5new Vue({
6 el: "#app",
7 data: {
8 numbers: [1, 2, 3, 4, 5]
9 }
10});
- فایل index.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>App</title>
5 <meta charset="UTF-8" />
6 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
7 </head>
8 <body>
9 <div id="app">
10 <num v-for="num in numbers" :num="num" :key="num" />
11 </div>
12 <script src="src/index.js"></script>
13 </body>
14</html>
که نتیجه زیر را به دست میدهد:
12345
توجه کنید که خصوصیت key: ارائه شده است. این خصوصیت از Vue نسخه 2.2.0 الزامی است. ضمناً با نوشتن کد زیر یک num به درون مشخصه num کامپوننت num ارسال کردهایم:
1:num="num"
بدین ترتیب میتوانیم هر چه میخواهیم درون کامپوننت تزریق کنیم و تزویج بین آنها را کاهش دهیم.
سخن پایانی
امکان رندر کردن بازهای از اعداد با v-for وجود دارد و به این منظور باید به جای آرایه یا یک شیء، اعداد ارائه شوند. v-for و v-if نباید با هم استفاده شوند، چون v-if الزامی به اجرا در هر بار تکرار ندارد و میتوان تعداد آیتمهایی که قرار است در حلقه قرار گیرند را کاهش داد. ضمناً میتوانیم روی یک قالب و کامپوننت با v-for مانند هر عنصر دیگری بچرخیم.