در مقاله قبلی راجع به دستور های شرطی v-if و v-show صحبت کردیم، در این مقاله قصد داریم با ایجاد حلقه روی یک آرایه یا object، به ازای هر یک از آیتم های آنها یک tag جدید ایجاد کنیم.
v-for در آرایهها
v-for
یک directive پایه برای Vue.js است و شاید در گذشته با ساختار آن آشنا شدهاید. v-for
در واقع یک حلقه ی ساده for است که در Vue.js به شکل v-for
در آمده است.
برای شروع یک فایل HTML به نام index.html
میسازیم. این فایل در ابتدا خالی است که باید در ادامه با استفاده از دادههایی که تعریف میشود و همچنین استفاده از دستور v-for
آن را پر کرد. فایل مورد نظر به صورت زیر است:
<html>
<head>
<title>V-for directive</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
},
methods: {
}
});
</script>
</body>
</html>
برای پر کردن فایل ایجاد شده، قصد داریم ابتدا لیستی از کشورها را به صورت یک آرایه درست کنیم و سپس با استفاده از دستور v-for
آنها را در سند خود نشان دهیم. برای این کار ابتدا باید یک آرایه، با نام countries
ایجاد کرده و سپس نام تعدادی از کشورها را درون آن بنویسیم. آرایه countries
که تعریف کردیم به صورت زیر است:
data: {
countries:['brazil', 'canada', 'finland', 'france', 'india']
},
در این آرایه، نام پنج کشور نوشته شده است که قصد داریم در ادامه آنها را درون <HTML>
نشان دهیم. با توجه به این که در کنار یادگیری Vue.js قصد داریم با <HTML>
نیز کار کنیم، در این قسمت سعی میکنیم نام کشورهای نوشته شده را به صورت یک لیست بدون شماره گذاری نمایش دهیم. برای این کار از <ul>
و <li>
استفاده میکنیم.
برای نمایش لیست کشورها در داخل Vue دو راه وجود دارد:
راه اول: تکتک کشورها را داخل یک ردیف از هر لیست قرار دهیم بدون این که از هیچ یک از directive های Vue.js استفاده کنیم. به کد زیر توجه کنید:
<div id="app">
<span>لیست کشورها</span>
<ul>
<li>{{countries[0]}}</li>
<li>{{countries[1]}}</li>
<li>{{countries[2]}}</li>
<li>{{countries[3]}}</li>
<li>{{countries[4]}}</li>
</ul>
</div>
کدی که در بالا نوشته شد کد اشتباهی نیست اما یک کد طولانی است. تصور کنید یک آرایه با طول 100 داشته باشید و بخواهید آن را در <HTML>
نشان دهید، در این صورت باید 100 خط کد بزنید تا بتوانید این آرایه را نمایش دهید. اگر هیچ گونه خطایی در حین نوشتن کد نداشته باشید و با اطمینان کامل از این که در آینده قصد تغییر این آرایه را نخواهید داشت، تازه بعد از گذشت چند دقیقه خواهید توانست کد خود را تمام کنید.
راه دوم: راه بهتر و کوتاهتری که برای نمایش آیتم های یک آرایه داخل <HTML>
به کار برده میشود استفاده از directive، v-for
است. با استفاده از v-for
میتوان کدهای طولانی را تنها با یک خط نمایش داد. برای این کار کافی است مانند کد زیر عمل کنید:
<div id="app">
<span>لیست کشورها</span>
<ul>
<li v-for="country in countries" >{{country}}</li>
</ul>
</div>
همانطور که مشاهده میشود تنها با یک خط توانستیم نام تمام کشورها را درون یک لیست نمایش دهیم.
چند تا نکته در مورد v-for
وجود دارد که بهتر است بدانید:
1. v-for
به طور مستقیم به <li>
اضافه شد نه <ul>
اولیه، این کار به این معنی است که به ازای هر country از آرایه countries یک <li>
جدید ساخته میشود.
2. Countries یک property است که در ابتدا خودمان آن را درون data تعریف کردیم، بنابراین برای از استفاده از آن در v-for
نیز باید از همین اسم استفاده شود.
3. در v-for
از متغیر country استفاده شده است. اسم این متغیر یک اسم اختیاری است و میتوان از هر اسم دیگری نیز به جای آن استفاده کرد اما باید توجه کرد که اگر از اسم دیگری استفاده شود برای نمایش آن درون کد و محل استفاده نیز باید از همان اسم (در اینجا منظور {{country}}
است) استفاده کرد.
خروجی کدی که نوشتهایم به شکل زیر است:
در بخش قبلی با استفاده از v-for
توانستیم روی یک آرایه، حلقه زده و آیتم های آن را نمایش دهیم. اما استفاده از v-for
همیشه به این سادگی نیست، در این بخش قصد داریم با کمی تغییر در کدهای قبلی، آن را مقداری پیچیدهتر کنیم.
آرایهای که قبلا نوشتیم را به صورت زیر تغییر میدهیم:
data: {
countries:[
{name: 'brazil', population: [
{ number: '211000000' , unit: 'هزار'},
{ number: '211' , unit: 'million'},
{ number: '0.211' , unit: 'billion'}
]},
{name: 'canada', population: [
{ number: '38000000' , unit: 'هزار'},
{ number: '38' , unit: 'million'},
{ number: '0.038' , unit: 'billion'}
]},
{name: 'finland', population: [
{ number: '6000000' , unit: 'هزار'},
{ number: '6' , unit: 'million'},
{ number: '0.006' , unit: 'billion'}
]},
{name: 'france', population: [
{ number: '67000000' , unit: 'هزار'},
{ number: '67' , unit: 'million'},
{ number: '0.067' , unit: 'billion'}
]},
{name: 'india', population: [
{ number: '1366000000' , unit: 'هزار'},
{ number: '1366' , unit: 'million'},
{ number: '1.366' , unit: 'billion'}
]},
]
},
در آرایه ی جدید، افزون بر نام کشورها، جمعیت آنها نیز در سه حالت هزار، میلیون و میلیارد نوشته شده است. قصد داریم که با ساخت یک جمله برای هر کشور، نام و جمعیت آن را بنویسیم. البته دقت شود که جمعیت هر کشور در سه حالت نوشته شده است که برای نمایش حالتهای مختلف آن نیز لازم است مجدداْ از v-for
استفاده شود. به کدی که در زیر نوشته شده است دقت کنید:
<div id="app" dir="rtl">
<div>لیست کشورها</div></br>
<div v-for="country in countries" >
<span>کشور</span>
<span>{{country.name}}</span>
<span>دارای جمعیت </span>
<span>{{country.population[1].number}}</span>
<span>{{country.population[1].unit}}</span>
<span>است.</span>
</div>
</div>
خروجی کدی که تا به اینجا نوشتیم به صورت زیر است:
برای نمایش حالت های مختلف از جمعیت کافی است دوباره از حلقه v-for
استفاده کنیم. با توجه به کد زیر خواهید فهمید که این شیوه از کدنویسی قابل تعمیم بوده و هر چقدر که آرایه مورد استفاده تو در تو باشد باز هم با این روش میتوان به آیتم های داخلی آن دسترسی داشت.
<div id="app" dir="rtl">
<h2>لیست کشورها</h2></br>
<div v-for="country in countries" >
<span>کشور</span>
<span>{{country.name}}</span>
<span>دارای جمعیت </span>
<span>{{country.population[1].number}}</span>
<span>{{country.population[1].unit}}</span>
<span>(</span>
<span v-for="population in country.population">
<span>{{population.number}}</span>
<span>{{population.unit}} ، </span>
</span>
<span>)</span>
<span>است.</span>
</div>
</div>
</div>
خروجی جدید متناسب با کد بالا، به شکل زیر است:
حال فرض کنید که قصد داشته باشیم که در داخل پرانتز جمعیت کشورهایی را که فقط بر حسب میلیون است، نشان دهیم و به دو حالت دیگر (هزار و میلیارد) کاری نداشته باشیم. در این صورت باید از دستور v-if
(که روش استفاده از آن در مقاله های قبلی بیان شد) استفاده کنیم. برای انجام این کار کافی است مانند کد زیر عمل کنیم:
<div id="app" dir="rtl">
<h2>لیست کشورها</h2></br>
<div v-for="country in countries" >
<span>کشور</span>
<span>{{country.name}}</span>
<span>دارای جمعیت </span>
<span>(</span>
<span v-for="population in country.population">
<span v-if="population.unit === 'million'">
<span>{{population.number}}</span>
<span>{{population.unit}}</span>
</span>
</span>
<span>)</span>
<span>است.</span>
</div>
</div>
</div>
استفاده از key در دستور v-for
در استفاده از v-for
یک صفت (attribute) به اسم key نیز وجود دارد که باید در درون v-for
استفاده شود. البته هر چند که استفاده نکردن از آن در کدها شاید مشکل بزرگی ایجاد نکند و فقط به هشدار در کنسول مرورگر بسنده کند، اما با بزرگ شده برنامه ممکن است مشکلاتی را به وجود آورد. بنابراین پیشنهاد میشود برای جلوگیری از بروز مشکلات احتمالی همیشه از key استفاده شود.
هنگامی که حلقه v-for
درون object ها دور میزند، هیچ سرنخی برای شیوه ردیابی و مقایسه object ها با همدیگر ندارد، زیرا نمیتواند یک object را از دیگری تفکیک کند. یعنی از آنجا که Vue نمیتواند مقدارهای object را تشخیص داده و از هم جدا کند، کل بخشی را که توسط این حلقهایجاد شده است دوباره اجرا میکند. شاید برای ما، این مشکل بسیار کوچک باشد و مشکلات عملکردی به وجود آمده نیز کم باشد اما موضوعی است که باید آن را بخاطر بسپارید و سعی کنید این کار را برای عملکرد بهتر (best practice) انجام دهید.
اما روش استفاده از آن به چه شکل خواهد بود؟
key
: حلقه ی v-for
برای شناسایی object ها نیاز به یک مشخصه یکتا دارد. برای مثال میتوان از name کشورها یا index هر کشور استفاده کرد. البته اگر نام تکراری در کشورها وجود داشته باشد استفاده کردن از name برای key
کار درستی نیست و بهتر است از همان index استفاده شود. در کد زیر از index استفاده شده است.
<div v-for="(country, indexC) in countries" :key="indexC">
.
.
.
<span v-for="(population, indexP) in country.population" :key="indexP">
کد نهایی که تا الان با هم نوشتهایم به شکل زیر در آمده است:
<html>
<head>
<title>V-for directive</title>
</head>
<body>
<div id="app" dir="rtl">
<h2>لیست کشورها</h2></br>
<div v-for="(country, indexC) in countries" :key='indexC' >
<span>کشور</span>
<span>{{country.name}}</span>
<span>دارای جمعیت </span>
<span>(</span>
<span v-for="(population, indexP) in country.population" :key="indexP">
<span v-if="population.unit === 'million'">
<span>{{population.number}}</span>
<span>{{population.unit}}</span>
</span>
</span>
<span>)</span>
<span>است.</span>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
countries:[
{name: 'brazil', population: [
{ number: '211000000' , unit: 'هزار'},
{ number: '211' , unit: 'million'},
{ number: '0.211' , unit: 'billion'}
]},
{name: 'canada', population: [
{ number: '38000000' , unit: 'هزار'},
{ number: '38' , unit: 'million'},
{ number: '0.038' , unit: 'billion'}
]},
{name: 'finland', population: [
{ number: '6000000' , unit: 'هزار'},
{ number: '6' , unit: 'million'},
{ number: '0.006' , unit: 'billion'}
]},
{name: 'france', population: [
{ number: '67000000' , unit: 'هزار'},
{ number: '67' , unit: 'million'},
{ number: '0.067' , unit: 'billion'}
]},
{name: 'india', population: [
{ number: '1366000000' , unit: 'هزار'},
{ number: '1366' , unit: 'million'},
{ number: '1.366' , unit: 'billion'}
]},
]
},
methods: {
}
});
</script>
</body>
</html>
این قسمت از دوره هم به پایان رسید. اما در ادامه قسمتهای بعدی ارائه میشوند.