Skip to content

Fallthrough Attributes

این صفحه فرض می‌کند شما قبلاً مبانی کامپوننت‌ها را خوانده‌اید. اگر با کامپوننت‌ها آشنایی ندارید، ابتدا آن را بخوانید.

Attribute Inheritance

یک "fallthrough attribute" ویژگی یا listener رویداد v-on است که به کامپوننت پاس داده می‌شود، اما به طور صریح در props یا emits تعریف نشده است. مثال‌های رایج این موارد ویژگی‌های class، style و id هستند.

وقتی یک کامپوننت root element اصلی خود را رندر می‌کند، ویژگی‌های fallthrough به طور خودکار به attributeهای root element اضافه می‌شوند. به عنوان مثال، با در نظر گرفتن یک کامپوننت <MyButton> با تمپلیت زیر:

template
<!-- template of <MyButton> -->
<button>click me</button>

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

template
<MyButton class="large" />

DOM نهایی رندر شده به این صورت خواهد بود:

html
<button class="large">click me</button>

اینجا، <MyButton> ویژگی class را به عنوان یک prop پذیرفته شده اعلام نکرده است. بنابراین، class به عنوان یک ویژگی fallthrough در نظر گرفته می‌شود و به طور خودکار به عنصر ریشه <MyButton> اضافه می‌شود.

ادغام class و style

اگر root element کامپوننت فرزند از قبل ویژگی‌های class یا style را داشته باشد، آن با مقادیر class و style به ارث برده شده از والد ادغام می‌شود. فرض کنید تمپلیت <MyButton> در مثال قبلی را به این صورت تغییر دهیم:

template
<!-- template of <MyButton> -->
<button class="btn">click me</button>

سپس DOM نهایی رندر شده به این صورت خواهد بود:

html
<button class="btn large">click me</button>

v-on Listener Inheritance

همان قانون برای listenerهای رویداد v-on اعمال می‌شود:

template
<MyButton @click="onClick" />

دریافت‌کننده رویداد click به root element کامپوننت <MyButton> اضافه می‌شود، یعنی عنصر <button>. وقتی <button> اصلی کلیک شود، متد onClick از کامپوننت والد را فراخوانی می‌کند. اگر <button> از قبل یک دریافت‌کننده رویداد click با v-on داشته باشد، آنگاه هر دو فراخوانی می‌شوند.

Nested Component Inheritance

اگر یک کامپوننت، کامپوننت دیگری را به عنوان نود ریشه‌اش (root node) رندر کند، به عنوان مثال، <MyButton> را بازنویسی کردیم تا <BaseButton> را به عنوان ریشه‌اش رندر کند:

template
<!-- که صرفاً یک کامپوننت دیگر را رندر می‌کند <MyButton/> تمپلیت -->
<BaseButton />

سپس ویژگی‌های fallthrough دریافت شده توسط <MyButton> به طور خودکار به <BaseButton> ارسال می‌شوند.

توجه داشته باشید که:

  1. ویژگی‌های ارسال شده شامل هیچ‌کدام از attributeهایی که به عنوان props تعریف شده‌اند، یا listenerهای v-on رویدادهای تعریف شده توسط <MyButton> نمی‌شوند - به عبارت دیگر، props و listenerهای تعریف شده توسط <MyButton> "مصرف" شده‌اند.

  2. ویژگی‌های ارسال شده ممکن است به عنوان props توسط <BaseButton> پذیرفته شوند، اگر توسط آن اعلام شده باشند.

غیرفعال کردن Attribute Inheritance

اگر نمی‌خواهید یک کامپوننت به طور خودکار ویژگی‌ها را به ارث ببرد، می‌توانید inheritAttrs: false را در آپشن‌های کامپوننت تنظیم کنید.

از نسخه 3.3 می‌توانید از defineOptions مستقیماً در <script setup> استفاده کنید:

vue
<script setup>
defineOptions({
  inheritAttrs: false
})
// ...setup logic
</script>

سناریوی رایج برای غیرفعال کردن وراثت ویژگی‌ها زمانی است که attributeها نیاز دارند به عناصر دیگری به غیر از نود ریشه اعمال شوند. با تنظیم گزینه inheritAttrs بر روی false، می‌توانید کنترل کاملی بر اینکه ویژگی‌های fallthrough کجا باید اعمال شوند، داشته باشید.

می‌توانید به این ویژگی‌های fallthrough مستقیماً در expression‌های تمپلیت به عنوان ‎$attrs دسترسی داشته باشید:

template
<span>Fallthrough attributes: {{ $attrs }}</span>

شی ‎$attrs شامل تمام ویژگی‌هایی است که توسط props یا emits کامپوننت اعلام نشده‌اند (مثلا class، style، v-on و غیره).

توجه داشته باشید که:

  • برخلاف props، ویژگی‌های fallthrough حروف بزرگ و کوچک اصلی خود را در جاوااسکریپت حفظ می‌کنند، بنابراین یک ویژگی مثل foo-bar نیاز دارد که به صورت ‎$attrs['foo-bar'] صدا زده شود.

  • یک دریافت‌کننده رویداد v-on مثل ‎@click در شی به عنوان یک تابع تحت ‎$attrs.onClick در دسترس است.

با استفاده از مثال کامپوننت <MyButton> از بخش قبلی - گاهی اوقات ممکن است نیاز داشته باشیم <button> واقعی را درون یک <div> اضافی برای اهداف استایلی قرار دهیم:

template
<div class="btn-wrapper">
  <button class="btn">click me</button>
</div>

می‌خواهیم تمام ویژگی‌های fallthrough مثل class و listenerهای v-on به <button> داخلی اعمال شوند، نه <div> بیرونی. می‌توانیم با استفاده از inheritAttrs: false و v-bind="$attrs"‎ این کار را انجام دهیم:

template
<div class="btn-wrapper">
  <button class="btn" v-bind="$attrs">click me</button>
</div>

به یاد داشته باشید که v-bind بدون آرگومان تمام پراپرتی‌های یک شی را به عنوان attributeهای عنصر هدف متصل می‌کند.

Attribute Inheritance on Multiple Root Nodes

برخلاف کامپوننت‌هایی با یک root node، کامپوننت‌هایی با چندین root node رفتار خودکار اتصال attributeها را ندارند. اگر ‎$attrs به طور صریح اتصال داده نشده باشد، یک هشدار زمان اجرا صادر می‌شود.

template
<CustomLayout id="custom-layout" @click="changeValue" />

اگر <CustomLayout> تمپلیت چند ریشه‌ای زیر را داشته باشد، به دلیل اینکه Vue نمی‌تواند مطمئن باشد که ویژگی‌ها را کجا اعمال کند، هشداری نمایش داده می‌شود:

template
<header>...</header>
<main>...</main>
<footer>...</footer>

هشدار سرکوب می‌شود اگر ‎$attrs به طور صریح متصل شود:

template
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>

دسترسی به Fallthrough Attributes در جاوااسکریپت

اگر نیاز باشد، می‌توانید در <script setup> با استفاده از API تعریف شده useAttrs()‎ به ویژگی‌های fallthrough یک کامپوننت دسترسی پیدا کنید:

vue
<script setup>
import { useAttrs } from 'vue'

const attrs = useAttrs()
</script>

اگر از <script setup> استفاده نمی‌کنید، attrs به عنوان یک خاصیت از context در setup()‎ در دسترس خواهد بود:

js
export default {
  setup(props, ctx) {
    // در دسترس هستند ctx.attrs به عنوان fallthrough ویژگی‌های
    console.log(ctx.attrs)
  }
}

توجه داشته باشید اگرچه شی attrs اینجا همیشه آخرین fallthrough attributes را منعکس می‌کند، واکنش‌گرا نیست (به دلایل عملکردی). نمی‌توانید از watcherها برای مشاهده تغییرات آن استفاده کنید. اگر به واکنش‌گرایی نیاز دارید، از یک prop استفاده کنید. به عنوان جایگزین، می‌توانید از onUpdated()‎ برای افکت جانبی با آخرین attrs در هر به‌روزرسانی استفاده کنید.

اگر نیاز باشد، می‌توانید از طریق خاصیت ‎$attrs در مثال به fallthrough attributes یک کامپوننت دسترسی پیدا کنید:

js
export default {
  created() {
    console.log(this.$attrs)
  }
}
Fallthrough Attributes has loaded