جایگزینی برای Filterها

A Replacement for Filters

Vue.JS 2: راهی جایگزین برای filter ها - قسمت 55

در جلسه قبل با مفهوم فیلترها آشنا شدیم و می دانیم که می توانند در برنامه ما بسیار مفید باشند. تصور کنید که وب سایت شما دو زبانه باشد (نسخه ای از آن به انگلیسی و نسخه ای به فارسی به کاربران ارائه شود) اگر بخواهید تاریخ را نمایش دهید چه کار باید کرد؟ شما می توانید تاریخ را به صورت یک timestamp دریافت کرده و سپس بر اساس اینکه در حالت انگلیسی یا فارسی هستید، بدون تغییر دادن data، فرمت نمایش آن را برای کاربران خود تغییر دهید. به طور مثال اول از ماه و روز استفاده کرده یا از روز و ماه استفاده کنید (نوشتن تاریخ در کشور آمریکا و انگلیس متفاوت است)؟ تاریخ را به صورت قمری نشان داده یا آن را تبدیل به تاریخ شمسی کنید؟

بنابراین فیلترها می توانند بسیار کاربردی باشند اما در بسیاری از اوقات و شاید بتوان گفت در اکثر اوقات راه حل بهتری برای این نوع مسائل وجود دارد. این راه حل خصوصیات computed می باشند. بگذارید برایتان مثالی بزنم. فرض کنید آرایه ای از میوه ها را داشته باشیم و سپس یک فیلد input را برای آن تعریف کنیم. این فیلد input مسئول جستجو در بین اعضای این آرایه است، یعنی زمانی که کاربر چیزی را در آن تایپ می کند رشته مورد نظر را جستجو می کند. البته ما می خواهیم در همان ابتدا تمام میوه ها را نمایش داده و سپس بر اساس مقدار تایپ شده توسط کاربر، مقادیر دیگر را مخفی کنیم تا فقط میوه های مورد نظر کاربر در لیستِ نمایش داده شده باقی بماند.

به فایل App.vue بروید و مثل من عمل کنید:

// بقیه کدها //
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
  <h1>Filters & Mixins</h1>
  <p>{{ text | toUppercase | to-Lowercase }}</p>
  <hr />
  <input v-model="filterText" />
</div>
// بقیه کدها //

همانطور که می بینید در کد بالا input خود را تعریف کرده و با v-model آن را به خصوصیتی به نام filterText متصل کرده ام. در مرحله بعد باید آرایه میوه ها و این خصوصیت را نیز تعریف کنیم:

<script>
export default {
  data() {
    return {
      text: "Hello there!",
      fruits: ["Apple", "Banana", "Mango", "Melon"],
      filterText: ""
    };
  },
  filters: {
    toUppercase(value) {
      return value.toUpperCase();
    }
  }
};
</script>

آرایه fruits چند میوه مختلف را در خود دارد و خصوصیت filterText را نیز به صورت خالی قرار داده ایم.  در مرحله بعد باید کاری کنیم که آیتم های درون آرایه ها به صورت یک لیست نمایش داده شوند. من این کار را با یک v-for ساده انجام می دهم. توجه داشته باشید که در برخی از ویرایشگر های کد ممکن است خطا دریافت کنید و به شما گفته شود هرجا از v-for استفاده شده است باید یک key نیز bind شود تا عناصر از هم قابل تشخیص باشد. از آنجایی که پروژه ما فقط برای کار کردن روی بحث خصوصیات computed است، نیازی به انجام کار نیست و با ذخیره کدها همه چیز بدون مشکل اجرا می شود. این خطا فقط هشداری برای شماست تا در برنامه های واقعی از یک کلید استفاده کنید.

<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
  <h1>Filters & Mixins</h1>
  <p>{{ text | toUppercase | to-Lowercase }}</p>
  <hr />
  <input v-model="filterText" />
  <ul>
    <li v-for="fruit in fruits">{{ fruit }}</li>
  </ul>
</div>

حالا با مراجعه به مرورگر می توانید لیست را مشاهده کنید.

یکی از مشکلات اصلی فیلترها این است که هوشمند نیستند. به طور مثال اگر ما فیلتری را در این قسمت تعریف کنیم که میوه ها را بر اساس رشته نوشته شده توسط کاربر نمایش بدهد، دچار افت سرعت برنامه می شویم. ما در حال حاضر درون یک حلقه v-for هستیم و از طرفی فریم ورک Vue نمی تواند تشخیص دهد که آیا مقدار درون این فیلد واقعاً تغییر کرده است یا نه. ممکن است شما همان مقداری را که قبلاً تایپ کرده بودید، دوباره تایپ کنید اما Vue قادر به تشخیص این مسئله نیست و فیلتر را دوباره اجرا خواهد کرد. در برنامه های بزرگ در چنین شرایطی (اجرای دوباره فیلتر با هر با render شدن DOM آن هم درون یک حلقه v-for) باعث افت شدید سرعت برنامه می شود. به همین دلیل بر خلاف نسخه اول فریم ورک Vue، در نسخه دوم فیلترها به طور کلی محدودتر شده اند.

ما قبلاً با خصوصیات computed آشنا شدیم. مزیت این خصوصیات این است که فریم ورک Vue وابستگی های آن ها را تحت نظر می گیرد و تنها زمانی آن ها را تغییر داده و یا دوباره render می کند که این وابستگی ها واقعاً تغییر کرده باشند. همان طور که می دانید تمام خصوصیات محاسبه شده در واقع تابع هستند، بنابراین می توانیم یک خصوصیت فیلتر شده تعریف کنیم و درون آن آرایه fruits را بر اساس مقدار وارد شده توسط کاربر فیلتر نماییم:

<script>
export default {
  data() {
    return {
      text: "Hello there!",
      fruits: ["Apple", "Banana", "Mango", "Melon"],
      filterText: ""
    };
  },
  filters: {
    toUppercase(value) {
      return value.toUpperCase();
    }
  },
  computed: {
    filteredFruits() {
      return this.fruits.filter(element => {
        return element.match(this.filterText);
      });
    }
  }
};
</script>

همانطور که می بینید با استفاده از متد filter روی تک تک اعضای آرایه fruits رفته ایم و آن ها را به شرط این return می کنیم که با مقدار تایپ شده توسط کاربر match شوند (منطبق باشند). حالا به جای گردش کردن درون fruits می توان درون filteredFruits (خصوصیت computed ما) گردش کرد:

<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
  <h1>Filters & Mixins</h1>
  <p>{{ text | toUppercase | to-Lowercase }}</p>
  <hr />
  <input v-model="filterText" />
  <ul>
    <li v-for="fruit in filteredFruits">{{ fruit }}</li>
  </ul>
</div>

حالا برنامه ما بدون مشکل کار می کند. تفاوت اینجاست که این کدها بسیار سریع تر هستند و دچار کُندی برنامه نخواهیم شد.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

علی دررودی
03 تیر 1400
سلام خیلی ممنون از داکیومنت عالیتون. واقعا به دردم خورد. دو سه روزه درگیر فیلتر کردن لیست هستم. خدا خیرتون بده.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.