قبل از معرفی کامپوننتها اجازه دهید سیستم template در ویو را بررسی کنیم. سیستم template ویو براساس سینتکس HTML است:
برای یک prop میتوانیم مقدار پیشفرضی را نیز تعیین کنیم. یعنی در صورت عدم ارسال شیء میتوانیم تعیین کنیم که چه شیءایی در حالت پیشفرض نمایش داده شود:
درون یک کامپوننت نیز میتوانیم یکسری دیتا را تعریف کنیم. اما باید در نظر داشته باشید که هر وهله از کامپوننت، scope مجزای خودش را دارد. در نتیجه پیشنهاد میشود دیتا حتماً به صورت یک تابع تعریف شود و همچنین دادههای درون آن نیز در scope کامپوننت تعریف شوند:
برای رفع این مشکل کافی است به اینصورت دیتا را تعریف کنیم:
Vue.component('blogPost', {
data: function() {
return {
stars: 5,
hover: 5
}
},
props: // as before...,
template: // as before
});
تغییر دیتا درون کامپوننتها
تا اینجا توانستیم از کامپوننت والد دادههایی را به کامپوننتهای فرزند ارسال کنیم. اکنون میخواهیم قابلیت تغییر دیتای تعریف شدهی درون کامپوننت والد را درون کامپوننتها نیز داشته باشیم:
Vue.component('child', {
props: ['message'],
methods: {
changeName() {
this.message = "New Name!..."
}
},
template: '#child-template'
});
new Vue({
el: '#app',
data() {
return {
name: 'DNT!'
}
}
});
تمپلیت کامپوننت فوق نیز به صورت x-template درون DOM تعریف شده است:
<script type="text/x-template" id="child-template">
<div>
<p>{{ message }}</p>
<button @click="changeName">Change Name</button>
</div>
</script>
فراخوانی کامپوننت نیز به اینصورت میباشد:
<div id="app">
<child :message="name"></child>
</div>
همانطور که مشاهده میکنید، دیتای name را از طریق ویژگی message توانستهایم به کامپوننت child ارسال کنیم. درون تمپلیت آن نیز یک دکمه را برای تغییر مقدار این ویژگی تعریف کردهایم. تغییر این ویژگی نیز یک assignment ساده است. اما اگر بر روی دکمهی Change Name کلیک کنید، هشدار زیر را درون کنسول مشاهده خواهید کرد:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "message"
found in
---> <Child>
<Root>
دلیل آن نیز مشخص است؛ زیرا با تغییر این ویژگی، کامپوننت والد از وجود تغییرات مطلع نشدهاست و فقط این تغییرات، درون کامپوننت child صورت گرفتهاست. برای اطلاعرسانی کامپوننت والد میتوانیم از یک ایونت ویژه استفاده کنیم و کامپوننت والد را از وجود تغییرات مطلع کنیم:
changeName() {
this.message = "New Name!...",
this.$emit("change-name", this.message);
}
برای تگ child نیز این ایونت را اضافه خواهیم کرد:
<child :message="name" @change-name="name = $event"></child>
در اینحالت با تغییر ویژگی message، مقدار دیتای name نیز بلافاصله تغییر پیدا خواهد کرد.
Slots
Slot یک روش عالی برای جایگزینی محتوای درون یک کامپوننت است. فرض کنید میخواهیم کامپوننتمان به صورت زیر باشد:
در اینحالت باید درون تمپلیت مکان قرارگیری Hello را تعیین کنیم. اینکار را میتوانیم با قرار دادن تگ slot انجام دهیم:
Vue.component('modal', {
template: `
...
<div class="modal-body">
<slot></slot>
</div>
...
`
});
اکنون هر محتوایی که درون تگ modal قرار گیرد، در قسمت slot نمایش داده خواهد شد. این نوع slot به صورت پیشفرض میباشد. در واقع میتوانیم slotها را نیز نامگذاری کنیم. به عنوان مثال یک slot برای عنوان modal، یک slot برای بدنه modal و یک slot دیگر برای فوتر modal تعریف کنیم:
Vue.component('modal', {
template: `
<div class="modal fade" id="detailsModal" tabindex="-1" role="dialog" aria-labelledby="detailsModalLabel" aria-hidden="false">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="detailsModalLabel">
<slot name="title"></slot>
</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<slot name="body"></slot>
</div>
<div class="modal-footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</div>
`
});
اکنون میتوانیم محتوای مورد نظر را برای قرارگیری درون slotها تعیین کنیم:
<modal>
<template slot="title">Title</template>
<template slot="body">Lorem ipsum dolor sit amet.</template>
<template slot="footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</template>
</modal>