آموزش Vue.js: آشنایی با کامپوننت های Vue — بخش پنجم

۲۵۹ بازدید
آخرین به‌روزرسانی: ۱۴ شهریور ۱۴۰۲
زمان مطالعه: ۱۰ دقیقه
آموزش Vue.js: آشنایی با کامپوننت های Vue — بخش پنجم

کامپوننت‌ها واحدهای منفرد و مستقل یک اینترفیس هستند. کامپوننت‌ها می‌توانند State ،Markup و استایل داشته باشند. در این نوشته به بررسی کامپوننت های Vue می‌پردازیم. برای مطالعه بخش قبلی از سری مقالات آموزش Vue روی لینک زیر کلیک کنید:

شیوه استفاده از کامپوننت های Vue

کامپوننت‌های Vue را به چهار روش می‌توان تعریف کرد.

در ادامه کدنویسی این روش‌های مختلف را بررسی می‌کنیم.

روش اول تعریف کامپوننت Vue:

1new Vue({/* options */})

روش دوم تعریف کامپوننت Vue:

1Vue.component('component-name', {/* options */})

روش سوم تعریف کامپوننت Vue:

روش سوم از طریق استفاده از کامپوننت‌های لوکال است. این‌ها کامپوننت‌هایی هستند که تنها از سوی یک کامپوننت خاص قابل دسترسی هستند و امکان دسترسی به آن‌ها در جاهای دیگر وجود ندارد.

روش چهارم تعریف کامپوننت Vue:

در این روش از فایل‌های vue. استفاده می‌شود که «کامپوننت‌های تک فایلی» (SFC) نیز نامیده می‌شوند؛ در ادامه به توضیح جزییات سه روش اول فوق می‌پردازیم.

استفاده از ()new Vue یا ()Vue.component روشی استاندارد برای کاربرد Vue در زمان ساخت یک اپلیکیشن است که اپلیکیشن تک‌صفحه‌ای (SPA) محسوب نمی‌شود. از این روش در مواردی استفاده می‌شود که Vue صرفاً در برخی صفحات خاص مانند صفحه تماس با ما یا در صفحه سبد خرید استفاده شده باشد. همچنین ممکن است Vue در همه صفحه‌ها استفاده شده باشد، اما سرور لی‌آوت را رندر می‌کند و HTML را مستقیماً به کلاینت ارسال می‌کنید و بدین ترتیب اپلیکیشن Vue که ساخته‌اید بارگذاری می‌شود.

در یک SPA که Vue اقدام به ساخت HTML می‌کند، استفاده از کامپوننت‌های تک فایلی رواج بیشتری دارد زیرا روش راحت‌تری محسوب می‌شود.

بدین ترتیب وهله‌ای از Vue را با نصب روی یک عنصر DOM می‌سازیم. اگر یک تگ <div id="app"></div> داشته باشید، می‌توانید به صورت زیر از آن استفاده کنید:

1new Vue({ el: '#app' })

به این صورت یک کامپوننت با عبارت new Vue وهله‌سازی می‌شود و هیچ نام تگ متناظر ندارد. بنابراین به طور معمول کامپوننت کانتینر اصلی است.

کامپوننت‌های دیگر که در اپلیکیشن استفاده می‌شوند با استفاده از ()Vue.component وهله‌سازی می‌شوند. چنین کامپوننتی به ما امکان تعریف یک تگ را می‌دهد که با استفاده از آن می‌توانیم کامپوننت را چندین بار در اپلیکیشن جاسازی کنیم و خروجی کامپوننت را در مشخصه template تعیین کنیم:

1<
2div id = "app" >
3    <
4    user - name name = "Flavio" > < /user-name></div >
5
6    Vue.component('user-name', {
7        props: ['name'],
8        template: '<p>Hi {{ name }}</p>'
9    })
10new Vue({
11    el: '#app'
12})

در کد فوق ما یک کامپوننت ریشه Vue را روی app# مقداردهی می‌کنیم و درون آن از کامپوننت Vue به نام user-name استفاده می‌کنیم که خوشامدگویی ما به کاربر را انتزاع می‌کند. این کامپوننت یک prop می‌پذیرد که خصوصیتی برای ارسال داده‌ها به کامپوننت‌های است.

در فراخوانی ()Vue.component اقدام به ارسال user-name به عنوان پارامتر اول می‌کنیم. بدین ترتیب کامپوننت یک نام دارد. این نام را می‌توان به دو روش نوشت. روش نخست که استفاده می‌کنیم kebab-case نام دارد. روش دوم PascalCase نام دارد که شبیه به camelCase است، اما حرف نخست به صورت بزرگ نوشته می‌شود:

1Vue.component('UserName', {/* ... */})

Vue به صورت خودکار یک نام مستعار را به صورت درونی از user-name به UserName و برعکس استخراج می‌کند و از این رو می‌توانید از هر چیزی که دوست دارید استفاده کنید. به طور کلی بهتر است در جاوا اسکریپت از UserName استفاده کنید و در قالب از user-name بهره بگیرید.

کامپوننت‌های لوکال

هر کامپوننت که با استفاده از ()Vue.component ایجاد شود به صورت سراسری ثبت می‌شود. لازم نیست که آن را به یک متغیر انتساب دهیم یا آن را برای استفاده مجدد در قالب‌ها ارسال کنیم.

می‌توانید کامپوننت‌ها را به صورت محلی با انتساب یک شیء که شیء کامپوننت را به یک متغیر تعریف می‌کند، کپسوله‌سازی کنید:

1const Sidebar = { template: '<aside>Sidebar</aside>'}

سپس با استفاده از مشخصه components می‌توانید درون کامپوننت دیگری به آن دسترسی پیدا کنید:

1new Vue({ el: '#app', components: { Sidebar }})

کامپوننت را می‌توانید در همان فایل بنویسید، اما روشی مناسب برای انجام این کار با استفاده از ماژول‌های جاوا اسکریپت وجود دارد:

1import Sidebar from './Sidebar'
2export default {
3    el: '#app',
4    components: {
5        Sidebar
6    }
7}

استفاده مجدد از یک کامپوننت

هر کامپوننت فرزند می‌تواند چندین بار اضافه شود. هر وهله مجزا، مستقل از وهله‌های دیگر است:

1<div id="app">
2  <user-name name="Flavio"></user-name>
3  <user-name name="Roger"></user-name>
4  <user-name name="Syd"></user-name>
5</div>
1Vue.component('user-name', {
2  props: ['name'],
3  template: '<p>Hi {{ name }}</p>'
4})
5
6new Vue({
7  el: "#app"
8})

بلوک‌های سازنده یک کامپوننت

تا به این جا دیدیم که یک کامپوننت چگونه می‌تواند مشخصه‌های el ،props و template را قبول کند.

  • el تنها در کامپوننت‌های ریشه که با استفاده از ({})new Vue وهله‌سازی شده‌اند استفاده می‌شود و عنصر DOM را که کامپوننت روی آن سوار خواهد شد، تعیین می‌کند.
  • props همه مشخصه‌هایی را که می‌توان به کامپوننت فرزند ارسال کرد، لیست می‌کند.
  • template جایی است که می‌توانیم قالب کامپوننت را راه‌اندازی کنیم. این قالب مسئول تعریف کردن خروجی تولیدی کامپوننت است.

کامپوننت‌ها مشخصه‌های دیگری نیز می‌پذیرند:

  • Data که حالت محلی کامپوننت است.
  • Methods که شامل متدهای کامپوننت است.
  • computed که شامل مشخصه‌های محاسبه شده مرتبط با کامپوننت است.
  • watch شامل watchers کامپوننت است.

کامپوننت‌های تک فایلی

کامپوننت‌های Vue می‌توانند در فایل جاوا اسکریپت به صورت زیر اعلان شوند:

1Vue.component('component-name', {/* options */})

روش زیر نیز میسر است:

1new Vue({/* options */})

همچنین می‌توان آن را در یک فایل vue. مجزا تعیین کرد. این فایل vue. کاملاً جالب است، زیرا امکان تعریف موارد زیر را به دست می‌دهد:

  • منطق جاوا اسکریپت
  • قالب کد HTML
  • استایل‌بندی CSS

همه این موارد تنها در یک فایل صورت می‌گیرند و از این رو نام آن «کامپوننت تک فایلی» است. به مثال زیر توجه کنید:

1<template> <p>{{ hello }}</p></template>
2
3<script>export default { data() { return { hello: 'Hello World!' } }}</script>
4
5<style scoped> p { color: blue; }</style>

همه این قابلیت‌ها به لطف استفاده از Webpack میسر شده است. Vue CLI این قابلیت را به سادگی و به صورت آماده به کار عرضه می‌کند. فایل‌های vue. نمی‌توانند بدون تنظیم Webpack استفاده شوند و بدین ترتیب برای اپلیکیشن‌هایی که از Vue صرفاً روی یک صفحه بدون بهره‌گیری از اپلیکیشن تک‌صفحه‌ایِ کامل استفاده می‌کنند چندان مناسب نیست.

کامپوننت‌های تک فایلی روی Webpack تکیه دارند و بدین ترتیب امکان استفاده از قابلیت‌های مدرن وب را پیدا می‌کنند.

بدین ترتیب CSS شما می‌تواند با استفاده از SCSS یا Stylus تعریف شود، قالب می‌تواند با استفاده از Pug ساخته شود و همه چیزهایی که برای امکان‌پذیری این وضعیت نیاز دارید این است که به Vue اعلان کنید از کدام پیش پردازشگر زبان می‌خواهید استفاده کنید.

فهرست پیش پردازشگرهای پشتیبانی شده شامل موارد زیر هستند:

  • TypeScript
  • SCSS
  • Sass
  • Less
  • PostCSS
  • Pug

بدین ترتیب می‌توانیم صرف‌نظر از مرورگر هدف از امکانات مدرن جاوا اسکریپت (ES6-7-8) با استفاده از یکپارچه‌سازی Babel و ماژول‌های ES بهره بگیریم و بدین ترتیب امکان استفاده از گزاره‌های imort/export پدید می‌آید. همچنین می‌توانیم از ماژول‌های CSS برای دامنه‌بندی CSS خود استفاده کنیم.

وقتی از دامنه‌بندی CSS (یعنی scoping) صحبت می‌کنیم، منظورمان این است که به راحتی می‌توانیم کامپوننت‌های تک فایلی با بهره‌گیری از تگ‌های <style scoped> بنویسیم که به کامپوننت‌های دیگر نشت پیدا نکنند.

اگر عبارت scoped را درج نکنید، CSS به صورت سراسری تعریف می‌شود. اما افزودن تگ scoped موجب می‌شود که Vue به صورت خودکار یک کلاس خاص به کامپوننت اضافه کند که در اپلیکیشن شما یکتا است و از این رو تضمین می‌شود که CSS به کامپوننت‌های دیگر نشت نمی‌یابد.

اگر کد جاوا اسکریپت شما به دلیل نوع منطقی که باید اجرا کنید، بزرگ است می‌توانید از خصوصیت src برای اکسترنال ساختن آن استفاده کنید:

1<template> <p>{{ hello }}</p></template><script src="./hello.js"></script>

این مسئله برای CSS نیز صادق است:

1<template> <p>{{ hello }}</p></template><script src="./hello.js"></script><style src="./hello.css"></style>

به شیوه استفاده از آن برای تنظیم داده‌ها در بخش جاوا اسکریپت کامپوننت توجه کنید:

1export default { data() { return { hello: 'Hello World!' } }}

روش‌های رایج دیگر نیز به صورت زیر هستند:

1export default { data: function() { return { name: 'Flavio' } }}

کد فوق معادل کاری است که قبلاً انجام دادیم. به کد زیر نیز توجه کنید:

1export default { data: () => { return { name: 'Flavio' } }}

این کد متفاوت است زیرا در آن از تابع‌های arrow استفاده شده است. تابع‌های arrow تا زمانی که لازم است به متد یک کامپوننت دسترسی پیدا کنیم مناسب هستند. اگر بخواهیم از this استفاده کنیم با مشکل مواجه می‌شویم و چنین مشخصه‌ای با استفاده از تابع‌های arrow به کامپوننت محدود نمی‌شود. بنابراین لازم است که از تابع‌های معمولی به جای تابع‌های arrow استفاده کنیم.

به کد زیر توجه کنید:

1module.exports = { data: () => { return { name: 'Flavio' } }}

در کد فوق از ساختار CommonJS استفاده شده و این کد نیز عملکرد مناسبی دارد. اما توصیه می‌کنیم از ساختار ماژول‌های ES استفاده کنید، چون استاندارد جاوا اسکریپت محسوب می‌شود.

قالب‌های Vue

Vue.js از یک زبان قالب‌بندی استفاده می‌کند که یک سوپرست برای HTML محسوب می‌شود. به این معنی که هر HTML یک قالب معتبر برای Vue.js است. علاوه بر آن Vue.js دو کارکرد قدرتمند دیگر نیز ارائه می‌کند که میان‌یابی و دایرکتیوها هستند.

برای نمونه کد زیر یک قالب معتبر برای Vue.js است:

1<span>Hello!</span>

این قالب می‌تواند درون یک کامپوننت Vue که به صورت صریح اعلان شده قرار گیرد:

1new Vue({ template: '<span>Hello!</span>'})

همچنین می‌تواند درون یک کامپوننت تک فایلی قرار گیرد:

1<template> <span>Hello!</span></template>

مثال اول یک کاربرد بسیار مقدماتی است. گام بعدی این است که آن را واداریم یک قطعه از حالت کامپوننت، برای نمونه یک نام را در خروجی ارائه کند. این کار با استفاده از میان‌یابی (interpolation) میسر است. ابتدا برخی داده‌ها را به کامپوننت خود اضافه می‌کنیم:

1new Vue({ data: { name: 'Flavio' }, template: '<span>Hello!</span>'})

و سپس می‌توانیم آن را با استفاده از ساختار براکت‌های جفتی به قالب اضافه کنیم:

1new Vue({ data: { name: 'Flavio' }, template: '<span>Hello {{name}}!</span>'})

نکته جالب این است که از name به جای this.data.name استفاده کرده‌ایم. دلیل آن این است که Vue.js نوعی اتصال درونی اجرا می‌کند و امکان استفاده قالب از مشخصه را به صورتی که گویی مقداری لوکال است فراهم می‌سازد که بسیار کارآمد است. در یک کامپوننت تک فایلی به صورت زیر عمل می‌کنیم:

1<template> <span>Hello {{name}}!</span></template>
2
3<script>export default { data() { return { name: 'Flavio' } }}</script>

ما از یک تابع معمولی در اکسپورت خود استفاده کردیم و از تابع arrow اجتناب نمودیم. دلیل این امر آن است که ما در data باید به متد در وهله کامپوننت دسترسی پیدا کنیم و اگر this به کامپوننت اتصال نیافته باشد، نمی‌توانیم این کار را انجام دهیم، به همین دلیل از تابع arrow استفاده نمی‌کنیم.

توجه داشته باشید که ما می‌توانستیم از تابع arrow استفاده کنیم، اما در آن صورت باید به خاطر می‌سپردیم که در حالت استفاده از this از تابع معمولی استفاده می کریم. از این رو این روش امن‌تر به نظر می‌رسد.

اینک به بحث میان‌یابی خود باز می‌گردیم.

{{ name }} ممکن است شما را به یاد قالب‌های Mustache / Handlebars بیندازد، اما این صرفاً یک شباهت ظاهری است. در Vue می‌توانید کارهای بسیار بیشتری انجام دهید و انعطاف‌پذیری بیشتری وجود دارد. برای نمونه می‌توانید از هر عبارت جاوا اسکریپت درون میان‌یابی استفاده کنید، اما عملاً به یک عبارت محدود شده‌اید:

1{{ name.reverse() }}
2
3{{ name === 'Flavio'? 'Flavio': 'stranger' }}

Vue امکان دسترسی به برخی اشیای سراسری را درون قالب‌ها فراهم می‌کند که شامل Math و Date است و از این رو می‌توان از آن‌ها استفاده کرد:

1{{ Math.sqrt(16) * Math.random() }}

بهتر است از افزودن بر پیچیدگی منطق قالب‌ها اجتناب کنیم، اما این واقعیت که Vue امکان انعطاف‌پذیری بیشتری به خصوص در موارد امتحان کردن موارد مختلف به دست می‌دهد قابل چشم‌پوشی نیست.

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

مقدار موجود در هر میان‌یابی به محض تغییر هر مشخصه داده که به آن اتکا دارد به‌روزرسانی می‌شود. با استفاده از دایرکتیو v-once می‌توان از این واکنش‌پذیری جلوگیری کرد. بدین ترتیب نتیجه همواره رد می‌شود و بنابراین دیگر نمی‌توانید HTML در خروجی داشته باشید. در این حالت اگر به یک قطعه کد HTML نیاز دارید، باید به جای آن از دایرکتیو v-html استفاده کنید.

استایل‌دهی کامپوننت‌ها با استفاده از CSS

ساده‌ترین گزینه برای افزودن CSS به یک کامپوننت Vue.js، استفاده از تگ style مانند کد HTML است:

1<template>
2  <p style="text-decoration: underline">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      decoration: 'underline'
10    }
11  }
12}
13</script>

این کد می‌تواند کاملاً استاتیک باشد. اما اگر خواهیم آن چه underline می‌شود در داده‌های کامپوننت باشد، باید به صورت زیر عمل کنیم:

1<template>
2  <p :style="{'text-decoration': decoration}">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      decoration: 'underline'
10    }
11  }
12}
13</script>

style: یک میانبر برای v-bind:style است. از این میانبر در سراسر این راهنما استفاده خواهیم کرد.

توجه کنید که ما text-decoration را در گیومه قرار داده‌ایم. دلیل آن وجود خط تیره است که بخشی از شناساگر معتبر جاوا اسکریپت نیست. اگر از ساختار خاص camelCase که Vue.js فراهم کرده است، استفاده می‌کنید، می‌توانید از گیومه بهره نگیرید و textDecoration را به صورت زیر بازنویسی کنید:

1<template>
2  <p :style="{textDecoration: decoration}">Hi!</p>
3</template>

به جای اتصال یک شیء به style می‌توانید به یک مشخصه محاسبه شده ارجاع دهید:

1<template>
2  <p :style="styling">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      textDecoration: 'underline',
10      textWeight: 'bold'
11    }
12  },
13  computed: {
14    styling: function() {
15      return {
16        textDecoration: this.textDecoration,
17        textWeight: this.textWeight
18      }
19    }
20  }
21}
22</script>

کامپوننت‌های Vue کد ساده HTML تولید می‌کنند و از این رو می‌توان یک کلاس به هر عنصر اضافه کرد و یک سلکتور CSS متناظر به همراه مشخصه‌هایی اضافه کرد که آن را استایل‌بندی می‌کنند:

1<template>
2  <p class="underline">Hi!</p>
3</template>
4
5<style>
6.underline { text-decoration: underline; }
7</style>

می‌توانید از CSS به صورت زیر استفاده کنید:

1<template>
2  <p class="underline">Hi!</p>
3</template>
4
5<style lang="scss">
6body {
7  .underline { text-decoration: underline; }
8}
9</style>

شما می‌توانید کدی داشته باشید که مانند مثال فوق باشد. همچنین می‌توانید کلاس را به مشخصه کامپوننت اتصال دهید تا آن را دینامیک کنید و در صورت true بودن مشخصه داده، تنها روی آن کلاس اعمال کنید:

1<template>
2  <p :class="{underline: isUnderlined}">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      isUnderlined: true
10    }
11  }
12}
13</script>
14
15<style>
16.underline { text-decoration: underline; }
17</style>

اکنون به جای اتصال یک کلاس به شیء مانند کاری که در مورد <p:class="{text: isText}">Hi!</p> انجام دادیم، می‌توانید مستقیماً به یک رشته وصل کنید و به آن مشخصه داده ارجاع دهید:

1<template>
2  <p :class="paragraphClass">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      paragraphClass: 'underline'
10    }
11  }
12}
13</script>
14
15<style>
16.underline { text-decoration: underline; }
17</style>

شما می‌توانید چند کلاس را از طریق افزودن دو کلاس به paragraphClass در این مورد و یا با استفاده از یک آرایه انتساب دهید:

1<template>
2  <p :class="[decoration, weight]">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      decoration: 'underline',
10      weight: 'weight',
11    }
12  }
13}
14</script>
15
16<style>
17.underline { text-decoration: underline; }
18.weight { font-weight: bold; }
19</style>

همین کار را با استفاده از یک شیء درون‌خطی در اتصال کلاس می‌توان انجام داد:

1<template>
2  <p :class="{underline: isUnderlined, weight: isBold}">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      isUnderlined: true,
10      isBold: true
11    }
12  }
13}
14</script>
15
16<style>
17.underline { text-decoration: underline; }
18.weight { font-weight: bold; }
19</style>

همچنین می‌توانید دو گزاره را با هم ترکیب کنید:

1<template>
2  <p :class="[decoration, {weight: isBold}]">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      decoration: 'underline',
10      isBold: true
11    }
12  }
13}
14</script>
15
16<style>
17.underline { text-decoration: underline; }
18.weight { font-weight: bold; }
19</style>

ضمناً می‌توانید از یک مشخصه محاسبه شده استفاده کنید که یک شیء بازگشت می‌دهد و زمانی که کلاس‌های CSS زیادی داشته باشید که به یک عنصر اضافه می‌کنید، گزینه بهتری محسوب می‌شود:

1<template>
2  <p :class="paragraphClasses">Hi!</p>
3</template>
4
5<script>
6export default {
7  data() {
8    return {
9      isUnderlined: true,
10      isBold: true
11    }
12  },
13  computed: {
14    paragraphClasses: function() {
15      return {
16        underlined: this.isUnderlined,
17        bold: this.isBold
18      }
19    }
20  }
21}
22</script>
23
24<style>
25.underlined { text-decoration: underline; }
26.bold { font-weight: bold; }
27</style>

توجه داشته باشید که باید در مشخصه محاسبه شده با استفاده از [this.[propertyName به داده‌های کامپوننت ارجاع دهید، در حالی که در داده‌های قالب، مشخصه‌ها به سادگی به صورت مشخصه‌های سطح اول قرار می‌گیرند.

هر CSS که مانند مثال اول ما هاردکد نشده باشد، باید از سوی Vue پردازش شود و Vue کار پیشوندگذاری CSS را برای ما به زیبایی و به صورت خودکار انجام می‌دهد. بدین ترتیب می‌توانیم CSS تمیزی بنویسیم و در عین حال مرورگرهای قدیمی‌تر را نیز هدف بگیریم. برای مطالعه بخش بعدی روی لینک زیر کلیک کنید:

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
freecodecamp
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *