v-for در آرایه ها

v-for در آرایه ها

در مقاله قبلی راجع به دستور های شرطی 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: [
            { numder: '211000000' , unit: 'thousand'},
            { numder: '211' , unit: 'million'},
            { numder: '0.211' , unit: 'billion'}
          ]},
          {name: 'canada', population: [
            { numder: '38000000' , unit: 'thousand'},
            { numder: '38' , unit: 'million'},
            { numder: '0.038' , unit: 'billion'}
          ]},
          {name: 'finland', population: [
            { numder: '6000000' , unit: 'thousand'},
            { numder: '6' , unit: 'million'},
            { numder: '0.006' , unit: 'billion'}
          ]},
          {name: 'france', population: [
            { numder: '67000000' , unit: 'thousand'},
            { numder: '67' , unit: 'million'},
            { numder: '0.067' , unit: 'billion'}
          ]},
          {name: 'india', population: [
            { numder: '1366000000' , unit: 'thousand'},
            { numder: '1366' , unit: 'million'},
            { numder: '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 === 'میلیون'">
            <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 === 'میلیون'">
            <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: 'میلیون'},
            { number: '0.211' , unit: 'میلیارد'}
          ]},
          {name: 'canada', population: [
            { number: '38000000' , unit: 'هزار'},
            { number: '38' , unit: 'میلیون'},
            { number: '0.038' , unit: 'میلیارد'}
          ]},
          {name: 'finland', population: [
            { number: '6000000' , unit: 'هزار'},
            { number: '6' , unit: 'میلیون'},
            { number: '0.006' , unit: 'میلیارد'}
          ]},
          {name: 'france', population: [
            { number: '67000000' , unit: 'هزار'},
            { number: '67' , unit: 'میلیون'},
            { number: '0.067' , unit: 'میلیارد'}
          ]},
          {name: 'india', population: [
            { number: '1366000000' , unit: 'هزار'},
            { number: '1366' , unit: 'میلیون'},
            { number: '1.366' , unit: 'میلیارد'}
          ]},
        ]
      },
      methods: {

      }
    });
  </script>
</body>

</html>


این قسمت از دوره هم به پایان رسید. اما در ادامه قسمت‌های بعدی ارائه می‌شوند.

نظرات
اگر login نکردی برامون ایمیلت رو بنویس: