// useUserService.ts
function isAuthenticated() {
return !!user.value;
}
// کامپوننت A
<script>
const { isAuthenticated } = useUserService();
</script>
<template>
<p v-if="isAuthenticated()">سلام</p>
</template>
توابع در Vue رفتار متفاوتی از توابع معمولی دارند.
در این مثال، تابع
isAuthenticated()
مانند یک computed
عمل میکند و هر بار که مقدار user
تغییر کند یا کامپوننت A دوباره رندر شود، فراخوانی خواهد شد.این اتفاق به این دلیل میافتد که Vue تمام وابستگیهای واکنشپذیر را درون بدنهی تابع شناسایی کرده و هر زمان که یکی از آنها تغییر کند، کامپوننت را دوباره رندر میکند.
بنابراین، تفاوت زیادی در استفاده از یک تابع به جای
computed
وجود ندارد. اما اگر داخل تابع منطق پیچیدهتری وجود داشته باشد، بهتر است از computed
استفاده کنید، زیرا فقط زمانی که وابستگیهای آن تغییر کنند، محاسبه مجدد میشود، در حالی که تابع در هر رندر اجرا میشود.#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
❤1
اگر صفحهای را از طریق
از طریق watch:
از طریق هوک روتر
روش دوم این امکان را فراهم میآورد که از
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
<router-view>
نمایش میدهید که شامل پارامترهای مسیری (مانند محصولات، کاتالوگها یا کاربران از طریق شناسه) است و باید در صورت تغییر پارامتر، اطلاعات جدیدی بارگذاری کنید، یعنی باید تغییرات پارامتر را پیگیری کنید، این کار را میتوان به دو روش انجام داد.از طریق watch:
watch(
() => route.params.id,
async () => {
userData.value = await fetchUser(to.params.id);
},
{ immediate: true }
);
از طریق هوک روتر
onBeforeRouteUpdate
:import { onBeforeRouteUpdate } from 'vue-router'
onBeforeRouteUpdate(async (to, from) => {
if (to.params.id !== from.params.id) {
userData.value = await fetchUser(to.params.id);
}
})
روش دوم این امکان را فراهم میآورد که از
onBeforeRouteLeave
نیز استفاده کنید، اگر به هر دلیلی نیاز باشد.#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍1
Media is too big
VIEW IN TELEGRAM
حالت بخار (Vapor Mode) در Vue.js یک استراتژی کامپایل جایگزین است که برای بهبود عملکرد برنامههای Vue.js طراحی شده است. این حالت به جای استفاده از Virtual DOM (VDOM)، کامپوننتها را مستقیماً به HTML تبدیل میکند
vapor mode در vue 3.6 اضافه خواهد شد
#️⃣#tip #vue #dub
👥@IR_javascript_group
🆔@IR_javascript
vapor mode در vue 3.6 اضافه خواهد شد
#️⃣#tip #vue #dub
👥@IR_javascript_group
🆔@IR_javascript
🔥2🤯1
برای کسانی که نمیدانند، در VS Code (با افزونهی Volar) یک فرمان کاربردی وجود دارد که امکان تقسیم یک فایل به دو پنجره بر اساس بخشهای SFC را فراهم میکند.
#️⃣#tool #vue
👥@IR_javascript_group
🆔@IR_javascript
#️⃣#tool #vue
👥@IR_javascript_group
🆔@IR_javascript
👍1
ویدیو دوبله شده در مورد بهینهسازی عملکرد Vue [+لینک]
عملکرد بهینه یکی از عوامل کلیدی در اپلیکیشنهای مدرن تحت وب است. عملکرد ضعیف منجر به کاهش تعامل کاربران، کاهش نرخ تبدیل و در نهایت از دست دادن فرصتهای تجاری میشود. این دوره به شما کمک میکند تا:
زمان بارگذاری و عملکرد اجرایی اپلیکیشن Vue.js خود را بهطور چشمگیری بهبود دهید.
تکنیکهای پیشرفته بهینهسازی که توسط متخصصان صنعت استفاده میشود را اجرا کنید.
مشکلات عملکردی را بهصورت کارآمد اشکالزدایی و برطرف کنید.
تصمیمات معماری آگاهانهای اتخاذ کنید که بر سرعت برنامه تأثیر میگذارد.
تجربهای استثنایی برای کاربران از طریق بهینهسازی عملکرد ارائه دهید.
به ما بپیوندید و با تسلط بر بهینهسازی عملکرد Vue.js، اپلیکیشنهای خود را به سطحی جدید از سرعت و کارایی برسانید.
🔗https://www.aparat.com/v/tdvpkja?playlist=17549421
#️⃣#tip #dub #vue
👥@IR_javascript_group
🆔@IR_javascript
عملکرد بهینه یکی از عوامل کلیدی در اپلیکیشنهای مدرن تحت وب است. عملکرد ضعیف منجر به کاهش تعامل کاربران، کاهش نرخ تبدیل و در نهایت از دست دادن فرصتهای تجاری میشود. این دوره به شما کمک میکند تا:
زمان بارگذاری و عملکرد اجرایی اپلیکیشن Vue.js خود را بهطور چشمگیری بهبود دهید.
تکنیکهای پیشرفته بهینهسازی که توسط متخصصان صنعت استفاده میشود را اجرا کنید.
مشکلات عملکردی را بهصورت کارآمد اشکالزدایی و برطرف کنید.
تصمیمات معماری آگاهانهای اتخاذ کنید که بر سرعت برنامه تأثیر میگذارد.
تجربهای استثنایی برای کاربران از طریق بهینهسازی عملکرد ارائه دهید.
به ما بپیوندید و با تسلط بر بهینهسازی عملکرد Vue.js، اپلیکیشنهای خود را به سطحی جدید از سرعت و کارایی برسانید.
🔗https://www.aparat.com/v/tdvpkja?playlist=17549421
#️⃣#tip #dub #vue
👥@IR_javascript_group
🆔@IR_javascript
👍4
در CSS**، قابلیت **@scope برای محدود کردن دامنهی اعمال استایلها معرفی شده است:
### 🔹 مثال:
این ویژگی میتواند در برخی موارد مفید باشد، اما جایگزین کاملی برای Vue Scoped Styles نیست.
### 🔸 تفاوت با Vue Scoped:
- در Vue، اگر یک کامپوننت را در یک لیست رندر کنید، هر نمونهی کامپوننت یک data-attribute منحصربهفرد دارد که استایلهای آن را جدا نگه میدارد.
- اما در @scope**، دامنهی استایلها ممکن است **با سایر نمونهها ترکیب شود و یکپارچگی آن حفظ نشود.
با این حال، @scope برای موارد ساده و Vanilla CSS یک قابلیت کاربردی و مفید محسوب میشود. 🎨
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
### 🔹 مثال:
<template>
<div class="box">
<button class="button">Click me</button>
</div>
</template>
<style>
@scope (.box) {
.button {
color: red;
}
}
</style>
این ویژگی میتواند در برخی موارد مفید باشد، اما جایگزین کاملی برای Vue Scoped Styles نیست.
### 🔸 تفاوت با Vue Scoped:
- در Vue، اگر یک کامپوننت را در یک لیست رندر کنید، هر نمونهی کامپوننت یک data-attribute منحصربهفرد دارد که استایلهای آن را جدا نگه میدارد.
- اما در @scope**، دامنهی استایلها ممکن است **با سایر نمونهها ترکیب شود و یکپارچگی آن حفظ نشود.
با این حال، @scope برای موارد ساده و Vanilla CSS یک قابلیت کاربردی و مفید محسوب میشود. 🎨
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
🔥2
اگر یک آرایه دارید که هر عنصر آن شامل یک مقدار computed است، بهتر است یک مقدار computed برای کل آرایه ایجاد کنید تا اینکه برای هر عنصر جداگانه یک مقدار computed داشته باشید.
### نمونه نامناسب
### نمونه بهینه
با این روش، محاسبات بهینهتر انجام میشود و از ایجاد چندین مقدار computed غیرضروری جلوگیری خواهد شد.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
### نمونه نامناسب
const rows = productRows.map(row => ({
...row,
total: computed(() => row.price * row.qty),
}));
### نمونه بهینه
const computedRows = computed(() =>
productRows.map(row => ({
...row,
total: row.price * row.qty,
}))
);
با این روش، محاسبات بهینهتر انجام میشود و از ایجاد چندین مقدار computed غیرضروری جلوگیری خواهد شد.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍1
در هستهی Nuxt قابلیت هیدراسیون تنبل (Lazy Hydration) اضافه شده است—پس دیگر نیازی به ساخت راهکارهای سفارشی نیست! اما بیایید قدمبهقدم بررسی کنیم.
### 🚀 Vue 3.5 و ارتقای SSR
در Vue 3.5 SSR بهبود یافته و حالا کامپوننتهای غیرهمزمان (Async Components) میتوانند زمان هیدراته شدن خود را از طریق استراتژی hydrate در API `defineAsyncComponent()` کنترل کنند. مثلاً، میتوان تعیین کرد که یک کامپوننت فقط هنگام نمایش در صفحه هیدراته شود:
### 🔥 Nuxt 3.16 و پشتیبانی از Delayed Hydration
📅 در ۷ مارس ۲۰۲۵ نسخهی Nuxt 3.16 منتشر شد که شامل ویژگیهای جدید، بهبود عملکرد، ابزارهای توسعهی بهتر و... بود، اما مهمترین قابلیت اضافهشده، Delayed Hydration است. توسعهدهندگان Nuxt در وبلاگ خود جزئیات این قابلیت را توضیح دادهاند.
#### ✅ مثال: هیدراته شدن کامپوننت هنگام ورود به ویوپورت
✅ حالا کامپوننت فقط وقتی در زون دید کاربر قرار بگیرد، لود و اجرا میشود—دیگر نیازی به نوشتن اسکریپتهای پیچیده برای ردیابی و بارگذاری نیست.
🔹 همچنین میتوان از hook جدید `hydrated` برای اجرای دستورات خاص پس از هیدراته شدن کامپوننت استفاده کرد:
### 📌 چه خبر؟
🔹 این ویژگی تنظیمات مختلفی دارد که میتوانید نحوهی کارکرد آن را در مستندات Nuxt مطالعه کنید.
🔹 Nuxt بهسرعت در حال پیشرفت است و وقت آن رسیده که این قابلیت را در محیط Production تست کنیم.
🔹 شاید وقتش رسیده که کامپوننتهای سمت سرور (Server Components) را هم امتحان کنیم؟ (قابلیت آزمایشی nuxt-islands – اما این بحث را میگذاریم برای بعد 😉)
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
### 🚀 Vue 3.5 و ارتقای SSR
در Vue 3.5 SSR بهبود یافته و حالا کامپوننتهای غیرهمزمان (Async Components) میتوانند زمان هیدراته شدن خود را از طریق استراتژی hydrate در API `defineAsyncComponent()` کنترل کنند. مثلاً، میتوان تعیین کرد که یک کامپوننت فقط هنگام نمایش در صفحه هیدراته شود:
import { defineAsyncComponent, hydrateOnVisible } from 'vue';
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
});
### 🔥 Nuxt 3.16 و پشتیبانی از Delayed Hydration
📅 در ۷ مارس ۲۰۲۵ نسخهی Nuxt 3.16 منتشر شد که شامل ویژگیهای جدید، بهبود عملکرد، ابزارهای توسعهی بهتر و... بود، اما مهمترین قابلیت اضافهشده، Delayed Hydration است. توسعهدهندگان Nuxt در وبلاگ خود جزئیات این قابلیت را توضیح دادهاند.
#### ✅ مثال: هیدراته شدن کامپوننت هنگام ورود به ویوپورت
<!-- کامپوننت تنها زمانی هیدراته میشود که در محدودهی دید کاربر قرار بگیرد -->
<LazyExpensiveComponent hydrate-on-visible />
✅ حالا کامپوننت فقط وقتی در زون دید کاربر قرار بگیرد، لود و اجرا میشود—دیگر نیازی به نوشتن اسکریپتهای پیچیده برای ردیابی و بارگذاری نیست.
🔹 همچنین میتوان از hook جدید `hydrated` برای اجرای دستورات خاص پس از هیدراته شدن کامپوننت استفاده کرد:
<LazyComponent hydrate-on-visible @hydrated="onComponentHydrated" />
### 📌 چه خبر؟
🔹 این ویژگی تنظیمات مختلفی دارد که میتوانید نحوهی کارکرد آن را در مستندات Nuxt مطالعه کنید.
🔹 Nuxt بهسرعت در حال پیشرفت است و وقت آن رسیده که این قابلیت را در محیط Production تست کنیم.
🔹 شاید وقتش رسیده که کامپوننتهای سمت سرور (Server Components) را هم امتحان کنیم؟ (قابلیت آزمایشی nuxt-islands – اما این بحث را میگذاریم برای بعد 😉)
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍1
### چرا باید از استفاده کنترلنشده از
#### یک. برهم خوردن جریان واکنشی (Reactive Flow)
استفاده از
در ظاهر ساده است، اما وقتی همین کد در چند مؤلفه با دادههای مشابه یا اثرات جانبی دیگر تکرار شود، کنترل جریان دادهها سختتر شده و رفتار برنامه غیرقابل پیشبینی میشود.
Vue معماری واکنشگرای یکطرفه (از داده به UI) را ترویج میدهد، اما
#### دو. کاهش خوانایی و دشواری در نگهداری
وقتی در یک مؤلفه چندین
این نوع پراکندگی منطق در `watch`ها:
- خوانایی کد را پایین میآورد
- بازسازی (refactor) و انتقال منطق به composableها را دشوار میکند
در مقابل، میتوان این رفتارها را در یک computed مجتمع یا composable مشخص و مستقل تعریف کرد.
#### سه. تأثیر منفی بر عملکرد
مثلاً اگر یک شیء عمیق را با
اگر
ویژگیهای محاسبهشونده کش میشوند، سبکتر هستند و اجرای بهتری دارند.
#### چهار. خطر نشت حافظه (Memory Leak)
در مؤلفههایی که با شرط
و در
اگر این
---
### ✅ راهکار پیشنهادی
قبل از استفاده از `watch`، ابتدا این پرسش را از خودتان بپرسید:
> «آیا میتوان این مسئله را با `computed`، `props` یا
در بسیاری از موارد پاسخ *بله* است، و انتخاب راهحلهای اعلانی (declarative) باعث خوانایی، عملکرد بهتر و مدیریت سادهتر خواهد شد.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
watch
پرهیز کرد؟#### یک. برهم خوردن جریان واکنشی (Reactive Flow)
استفاده از
watch
گاهی باعث پنهان شدن منطق واکنشگرایی میشود. برای مثال:watch(() => userId.value, async (newId) => {
const data = await fetchUserData(newId);
userData.value = data;
});
در ظاهر ساده است، اما وقتی همین کد در چند مؤلفه با دادههای مشابه یا اثرات جانبی دیگر تکرار شود، کنترل جریان دادهها سختتر شده و رفتار برنامه غیرقابل پیشبینی میشود.
Vue معماری واکنشگرای یکطرفه (از داده به UI) را ترویج میدهد، اما
watch
اغلب برای تبدیل داده به داده استفاده میشود که جریان را پیچیده میکند و اشکالزدایی را دشوارتر میسازد.#### دو. کاهش خوانایی و دشواری در نگهداری
وقتی در یک مؤلفه چندین
watch
بهصورت زنجیرهای نوشته شوند، ساختار کد بهشکل کلاف سردرگمی درمیآید که فهم آن زمانبر است:watch(() => settings.value.theme, applyTheme);
watch(() => settings.value.language, loadTranslations);
watch(() => settings.value.notifications, updateNotifications);
این نوع پراکندگی منطق در `watch`ها:
- خوانایی کد را پایین میآورد
- بازسازی (refactor) و انتقال منطق به composableها را دشوار میکند
در مقابل، میتوان این رفتارها را در یک computed مجتمع یا composable مشخص و مستقل تعریف کرد.
#### سه. تأثیر منفی بر عملکرد
مثلاً اگر یک شیء عمیق را با
deep: true
مانیتور کنید:watch(settings, (newVal, oldVal) => {
// مقایسه عمیق کل ساختار
}, { deep: true });
اگر
settings
شامل اشیاء یا آرایههای بزرگ باشد، عملکرد برنامه افت خواهد کرد. از طرفی، بسیاری از کاربردهای watch
را میتوان با computed
حل کرد:const isDarkTheme = computed(() => settings.value.theme === 'dark');
ویژگیهای محاسبهشونده کش میشوند، سبکتر هستند و اجرای بهتری دارند.
#### چهار. خطر نشت حافظه (Memory Leak)
در مؤلفههایی که با شرط
v-if
نمایش داده میشوند، اگر watch
بدون مدیریت درست ایجاد شود:<template>
<div v-if="showComponent">
<SomeComponent />
</div>
</template>
و در
SomeComponent
بنویسیم:watch(async() => someReactiveValue.value, await doSomething);
اگر این
watch
هنگام نابودی مؤلفه (unmount) لغو نشود، بهمرور زمان منابع حافظه را اشغال کرده و باعث نشت حافظه میشود.---
### ✅ راهکار پیشنهادی
قبل از استفاده از `watch`، ابتدا این پرسش را از خودتان بپرسید:
> «آیا میتوان این مسئله را با `computed`، `props` یا
emit
حل کرد؟»در بسیاری از موارد پاسخ *بله* است، و انتخاب راهحلهای اعلانی (declarative) باعث خوانایی، عملکرد بهتر و مدیریت سادهتر خواهد شد.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍1
کلونکردن عمیق اشیاء واکنشپذیر در Vue 3
Vue 3 از *Proxy* برای واکنشپذیری استفاده میکند، که این مسئله زمانی که بخواهید اشیاء را کلون کنید، مشکلاتی ایجاد میکند. روشهای استاندارد به صورت مورد انتظار عمل نمیکنند:
استفاده از عملگر `...` یا مشابه آن:
اگر شما از عملگر
استفاده از `JSON.stringify` و `JSON.parse`:
وقتی از
### چرا این اتفاق میافتد؟
Vue 3 از *Proxy* برای ایجاد واکنشپذیری استفاده میکند. *Proxy* در واقع یک "نظارتکننده" بر روی اشیاء است که هر تغییر در دادهها را شبیهسازی میکند و به Vue اطلاع میدهد تا رابط کاربری بهروز شود. زمانی که شما از روشهای استاندارد کپی استفاده میکنید، این ویژگیهای *Proxy* نادیده گرفته میشوند و به همین دلیل نمیتوانید از کپیهای انجامشده بهطور کامل استفاده کنید.
سه روش کاربردی برای این کار:
1. ترکیب
2. کپیکردن عمیق دستی
3. استفاده از کتابخانههای موجود
این روشها به شما کمک میکنند تا اشیاء واکنشپذیر را به طور صحیح کلون کنید بدون اینکه ارجاع به *Proxy* حفظ شود یا متدهای آن از بین بروند.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
Vue 3 از *Proxy* برای واکنشپذیری استفاده میکند، که این مسئله زمانی که بخواهید اشیاء را کلون کنید، مشکلاتی ایجاد میکند. روشهای استاندارد به صورت مورد انتظار عمل نمیکنند:
const state = reactive({ user: { name: "Al" } });
// مشکلات:
const badCopy1 = { ...state }; // حفظ ارجاع به Proxy
const badCopy2 = JSON.parse(JSON.stringify(state)); // از دست دادن متدها و Proxy
استفاده از عملگر `...` یا مشابه آن:
اگر شما از عملگر
...
برای کپی کردن یک شیء واکنشپذیر استفاده کنید، این کپی فقط ارجاع به *Proxy* اصلی را میگیرد، نه خود دادهها. به عبارت دیگر، تغییرات در شیء جدید میتواند بر شیء اصلی تأثیر بگذارد.استفاده از `JSON.stringify` و `JSON.parse`:
وقتی از
JSON.stringify
برای تبدیل شیء به یک رشته و سپس از JSON.parse
برای بازگشایی آن استفاده میکنید، متدهای شیء واکنشپذیر از بین میروند و همچنین ارتباط با *Proxy* قطع میشود. این به این معناست که ویژگیهای واکنشپذیری از دست میروند و این کپی دیگر به صورت واکنشپذیر نخواهد بود.### چرا این اتفاق میافتد؟
Vue 3 از *Proxy* برای ایجاد واکنشپذیری استفاده میکند. *Proxy* در واقع یک "نظارتکننده" بر روی اشیاء است که هر تغییر در دادهها را شبیهسازی میکند و به Vue اطلاع میدهد تا رابط کاربری بهروز شود. زمانی که شما از روشهای استاندارد کپی استفاده میکنید، این ویژگیهای *Proxy* نادیده گرفته میشوند و به همین دلیل نمیتوانید از کپیهای انجامشده بهطور کامل استفاده کنید.
سه روش کاربردی برای این کار:
1. ترکیب
toRaw
و structuredClone
import { toRaw } from 'vue';
const original = reactive({ data: 123 });
const copy = structuredClone(toRaw(original));
2. کپیکردن عمیق دستی
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const clone = Array.isArray(obj) ? [] : {};
for (const key in obj) {
clone[key] = deepClone(obj[key]);
}
return clone;
}
const copy = reactive(deepClone(toRaw(original)));
3. استفاده از کتابخانههای موجود
import { cloneDeep } from 'lodash-es';
const copy = reactive(cloneDeep(toRaw(obj)));
این روشها به شما کمک میکنند تا اشیاء واکنشپذیر را به طور صحیح کلون کنید بدون اینکه ارجاع به *Proxy* حفظ شود یا متدهای آن از بین بروند.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍2
در این پست، API جدیدی با نام effectScope() برای پکیج @vue/reactivity معرفی میشود. یک نمونه از EffectScope میتواند بهصورت خودکار، افکتهایی را که درون یک تابع همزمان اجرا میشوند، گردآوری کند تا در زمان مناسب همگی با هم حذف شوند.
در تابع setup() درون یک کامپوننت Vue، افکتها بهصورت خودکار جمعآوری شده و به همان نمونهی کامپوننت متصل میشوند. هنگام از بین رفتن کامپوننت، این افکتها نیز بهطور خودکار حذف میشوند. این ویژگی، ساده و شهودی است.
اما هنگامی که این افکتها را خارج از کامپوننتها یا در قالب یک پکیج مستقل استفاده کنیم، کار به این سادگی نیست. برای نمونه، حذف افکتهای computed و watch به صورت دستی به شکل زیر خواهد بود:
و برای حذف آنها:
بهویژه در کدهای ترکیبی طولانی، جمعآوری دستی افکتها کاری زمانبر و مستعد خطاست. فراموشکردن این کار یا نداشتن دسترسی به افکتهای ایجادشده، میتواند منجر به نشتی حافظه یا رفتارهای غیرمنتظره شود.
اما با وجود EffectScope بصورت زیر میشود
### Scopeهای تودرتو
Scopeهای تودرتو نیز باید توسط scope والد جمعآوری شوند. زمانی که scope والد حذف شود، همهی scopeهای فرزند نیز حذف خواهند شد:
---
### Scopeهای جداشده (Detached)
پارامتر
---
### تابع onScopeDispose
تابع
---
### دریافت scope فعلی
API جدید
🔗https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
در تابع setup() درون یک کامپوننت Vue، افکتها بهصورت خودکار جمعآوری شده و به همان نمونهی کامپوننت متصل میشوند. هنگام از بین رفتن کامپوننت، این افکتها نیز بهطور خودکار حذف میشوند. این ویژگی، ساده و شهودی است.
اما هنگامی که این افکتها را خارج از کامپوننتها یا در قالب یک پکیج مستقل استفاده کنیم، کار به این سادگی نیست. برای نمونه، حذف افکتهای computed و watch به صورت دستی به شکل زیر خواهد بود:
const disposables = []
const counter = ref(۰)
const doubled = computed(() => counter.value * ۲)
disposables.push(() => stop(doubled.effect))
const stopWatch۱ = watchEffect(() => {
console.log(`counter: ${counter.value}`)
})
disposables.push(stopWatch۱)
const stopWatch۲ = watch(doubled, () => {
console.log(doubled.value)
})
disposables.push(stopWatch۲)
و برای حذف آنها:
disposables.forEach((f) => f())
disposables = []
بهویژه در کدهای ترکیبی طولانی، جمعآوری دستی افکتها کاری زمانبر و مستعد خطاست. فراموشکردن این کار یا نداشتن دسترسی به افکتهای ایجادشده، میتواند منجر به نشتی حافظه یا رفتارهای غیرمنتظره شود.
اما با وجود EffectScope بصورت زیر میشود
// effect، computed، watch، و watchEffect که درون این scope ساخته میشوند، جمعآوری خواهند شد
const scope = effectScope()
scope.run(() => {
const doubled = computed(() => counter.value * ۲)
watch(doubled, () => console.log(doubled.value))
watchEffect(() => console.log('تعداد: ', doubled.value))
})
// برای حذف همه افکتها در این scope
scope.stop()
### Scopeهای تودرتو
Scopeهای تودرتو نیز باید توسط scope والد جمعآوری شوند. زمانی که scope والد حذف شود، همهی scopeهای فرزند نیز حذف خواهند شد:
const scope = effectScope()
scope.run(() => {
const doubled = computed(() => counter.value * ۲)
effectScope().run(() => {
watch(doubled, () => console.log(doubled.value))
})
watchEffect(() => console.log('تعداد: ', doubled.value))
})
// حذف تمام افکتها، از جمله موارد در scopeهای تودرتو
scope.stop()
---
### Scopeهای جداشده (Detached)
پارامتر
detached
در effectScope
اجازه میدهد تا scope بهصورت جدا از scope والد ایجاد شود. این ویژگی برای سناریوهایی مانند «مقداردهی اولیه تنبل» (Lazy Initialization) مفید است.let nestedScope
const parentScope = effectScope()
parentScope.run(() => {
const doubled = computed(() => counter.value * ۲)
nestedScope = effectScope(true /* detached */)
nestedScope.run(() => {
watch(doubled, () => console.log(doubled.value))
})
watchEffect(() => console.log('تعداد: ', doubled.value))
})
// فقط scope والد حذف میشود
parentScope.stop()
// scope تودرتو را در زمان مناسب حذف میکنیم
nestedScope.stop()
---
### تابع onScopeDispose
تابع
onScopeDispose
عملکردی مشابه onUnmounted
دارد، اما برای scope فعلی (نه نمونه کامپوننت). این قابلیت به فانکشنهای ترکیبی کمک میکند تا اثرات جانبی خود را همراه با scope مربوطه پاکسازی کنند.import { onScopeDispose } from 'vue'
const scope = effectScope()
scope.run(() => {
onScopeDispose(() => {
console.log('پاکسازی شد!')
})
})
scope.stop() // چاپ: پاکسازی شد!
---
### دریافت scope فعلی
API جدید
getCurrentScope()
برای دریافت scope فعلی معرفی شده است:import { getCurrentScope } from 'vue'
getCurrentScope() // EffectScope | undefined
🔗https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
GitHub
rfcs/active-rfcs/0041-reactivity-effect-scope.md at master · vuejs/rfcs
RFCs for substantial changes / feature additions to Vue core - vuejs/rfcs
### مثالها
#### مثال الف: استفادهی مشترک از composable
تابع
اگر
ابتدا:
سپس یک تابع کمکی برای مدیریت اشتراک ایجاد میکنیم:
اکنون:
این نسخه از
---
#### مثال ب: Scopeهای موقتی (Ephemeral)
در اینجا scopeها بهصورت موقتی ساخته و حذف میشوند.
---
### تأثیر در هسته Vue
در حال حاضر، در
با پیادهسازی این RFC، دیگر نیازی به بازنویسی
🔗https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
#### مثال الف: استفادهی مشترک از composable
تابع
useMouse()
یک نمونهی خوب برای ایجاد اثرات جانبی جهانی است:function useMouse() {
const x = ref(۰)
const y = ref(۰)
function handler(e) {
x.value = e.x
y.value = e.y
}
window.addEventListener('mousemove', handler)
onUnmounted(() => {
window.removeEventListener('mousemove', handler)
})
return { x, y }
}
اگر
useMouse()
در چند کامپوننت فراخوانی شود، هرکدام یک listener جدید ایجاد کرده و refs جداگانه خواهند داشت. برای جلوگیری از این کار پرهزینه، میتوانیم از scope جداشده و onScopeDispose
استفاده کنیم:ابتدا:
- onUnmounted(() => {
+ onScopeDispose(() => {
window.removeEventListener('mousemove', handler)
})
سپس یک تابع کمکی برای مدیریت اشتراک ایجاد میکنیم:
function createSharedComposable(composable) {
let subscribers = ۰
let state, scope
const dispose = () => {
if (scope && --subscribers <= ۰) {
scope.stop()
state = scope = null
}
}
return (...args) => {
subscribers++
if (!state) {
scope = effectScope(true)
state = scope.run(() => composable(...args))
}
onScopeDispose(dispose)
return state
}
}
اکنون:
const useSharedMouse = createSharedComposable(useMouse)
این نسخه از
useMouse
تنها یک بار listener را اضافه میکند و در صورت عدم نیاز، آن را حذف مینماید.---
#### مثال ب: Scopeهای موقتی (Ephemeral)
export default {
setup() {
const enabled = ref(false)
let mouseState, mouseScope
const dispose = () => {
mouseScope && mouseScope.stop()
mouseState = null
}
watch(
enabled,
() => {
if (enabled.value) {
mouseScope = effectScope()
mouseState = mouseScope.run(() => useMouse())
} else {
dispose()
}
},
{ immediate: true }
)
onScopeDispose(dispose)
},
}
در اینجا scopeها بهصورت موقتی ساخته و حذف میشوند.
onScopeDispose
اطمینان حاصل میکند که useMouse
بهدرستی پاکسازی شود، درحالیکه onUnmounted
در این فرآیند فراخوانی نمیشود.---
### تأثیر در هسته Vue
در حال حاضر، در
@vue/runtime-dom
توابع computed
بازنویسی میشوند تا به نمونهی کامپوننت متصل شوند. بنابراین موارد زیر معادل نیستند:// متفاوت
import { computed } from '@vue/reactivity'
import { computed } from 'vue'
با پیادهسازی این RFC، دیگر نیازی به بازنویسی
computed
نخواهد بود و vue
میتواند مستقیماً از نسخهی @vue/reactivity
استفاده کند.🔗https://github.com/vuejs/rfcs/blob/master/active-rfcs/0041-reactivity-effect-scope.md
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
GitHub
rfcs/active-rfcs/0041-reactivity-effect-scope.md at master · vuejs/rfcs
RFCs for substantial changes / feature additions to Vue core - vuejs/rfcs
اگر در یک اپلیکیشن چندین تابع غیرهمزمان (مانند بارگذاری دادهها از بکاند) بهطور همزمان اجرا میشود و نیاز به نمایش یک انیمیشن پیشلودر واحد داریم، میتوانیم بهراحتی این کار را از طریق یک تابع composable پیادهسازی کنیم:
---
### AppLoader.vue
### useAppLoader.ts
### SomeComponent
---
این مثال از
برای نسخههای قدیمیتر Vue، میتوان از هر تابعی برای تولید یک شناسهی منحصر به فرد استفاده کرد.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
---
### AppLoader.vue
<script setup>
import { useAppLoader } from "@/app/composables/useAppLoader";
const { loading } = useAppLoader();
</script>
<template>
<div class="loader" :class="{ active: loading }">
<div class="loaderBar" />
</div>
</template>
### useAppLoader.ts
import { computed, reactive, ref } from "vue";
const loaderSet = reactive(new Set<string>());
const loading = computed(() => loaderSet.size > 0);
export function useAppLoader(id) {
function startLoading() {
loaderSet.add(id);
}
function stopLoading() {
loaderSet.delete(id);
}
return { loading, startLoading, stopLoading };
}
### SomeComponent
import { useId } from "Vue";
import { useAppLoader } from "@/app/composables/useAppLoader";
const { startLoading, stopLoading } = useAppLoader(useId());
startLoading();
product.value = await api.products.product(props.productId);
stopLoading();
---
این مثال از
useId
استفاده میکند که در Vue 3.5 معرفی شده است. برای نسخههای قدیمیتر Vue، میتوان از هر تابعی برای تولید یک شناسهی منحصر به فرد استفاده کرد.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍1
راحت ترین معماری برای یک برنامه مبتنی بر Vue 3، معماری ماژولار (ماژولمحور) است.
در این رویکرد، ساختار برنامه از همان ابتدا به ماژولهای منطقی و مستقل با وابستگی حداقلی تقسیم میشود. برای مثال، در یک فروشگاه آنلاین، میتوان ماژولهایی مانند:
- ماژول کاتالوگ محصولات
- ماژول صفحه محصول
- ماژول حساب کاربری / پنل شخصی کاربر
را تعریف کرد.
علاوه بر اینها، یک ماژول پوسته (App Shell) نیز وجود دارد؛ بخشی که ساختار کلی برنامه را شامل میشود، نظیر: هدر، فوتر، منوی کناری و ناحیه اصلی نمایش محتوا. بهتر است منابع عمومی و پرکاربرد مانند:
- متدهای API
- کتابخانه بینالمللیسازی
- کامپوننتهای پایهای نظیر
- توابع کمکی مانند
در این ماژول قرار گیرند.
---
هر ماژول، پوشهها و ساختار مستقل خود را دارد که معمولاً شامل بخشهای زیر است:
-
-
-
-
- و در صورت نیاز:
---
این جداسازی با وابستگی کم، این امکان را فراهم میکند که هر ماژول بهصورت **نسبتاً مستقل توسعه یابد**؛ که این موضوع در عمل موجب بهبود عملکرد تیم توسعه، سهولت نگهداری کد، و افزایش احتمال موفقیت پروژه میشود.
(ادامه دارد ... .)
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
در این رویکرد، ساختار برنامه از همان ابتدا به ماژولهای منطقی و مستقل با وابستگی حداقلی تقسیم میشود. برای مثال، در یک فروشگاه آنلاین، میتوان ماژولهایی مانند:
- ماژول کاتالوگ محصولات
- ماژول صفحه محصول
- ماژول حساب کاربری / پنل شخصی کاربر
را تعریف کرد.
علاوه بر اینها، یک ماژول پوسته (App Shell) نیز وجود دارد؛ بخشی که ساختار کلی برنامه را شامل میشود، نظیر: هدر، فوتر، منوی کناری و ناحیه اصلی نمایش محتوا. بهتر است منابع عمومی و پرکاربرد مانند:
- متدهای API
- کتابخانه بینالمللیسازی
useI18n
- کامپوننتهای پایهای نظیر
BaseButton
- توابع کمکی مانند
stringHelpers
در این ماژول قرار گیرند.
---
هر ماژول، پوشهها و ساختار مستقل خود را دارد که معمولاً شامل بخشهای زیر است:
-
components
(کامپوننتها) -
composables
(توابع ترکیبی) -
assets
(منابع گرافیکی و استاتیک) -
utils
(توابع کمکی) - و در صورت نیاز:
api`، `routes`، `views`، `layouts
---
این جداسازی با وابستگی کم، این امکان را فراهم میکند که هر ماژول بهصورت **نسبتاً مستقل توسعه یابد**؛ که این موضوع در عمل موجب بهبود عملکرد تیم توسعه، سهولت نگهداری کد، و افزایش احتمال موفقیت پروژه میشود.
(ادامه دارد ... .)
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍5🔥2👎1
در این مطلب میخواهیم درباره دو هوک کاربردی در Vue به نامهای
### این دو چه کاری انجام میدهند؟
- `onRenderTracked`: نشان میدهد که Vue هنگام رندر شدن، چه چیزهایی را دنبال و رصد میکند (یعنی چه چیزی را "ردگیری" میکند).
- `onRenderTriggered`: مشخص میکند که چه چیزی تغییر کرده و باعث اجرای مجدد رندر شده است.
### چه زمانی باید از آنها استفاده کرد؟
- زمانی که یک کامپوننت بیش از حد و بدون دلیل واضحی رندر میشود.
- وقتی قصد بهینهسازی عملکرد (Performance Debugging) را دارید.
- زمانی که مشغول بررسی کدی هستید که توسط فرد دیگری نوشته شده یا خودتان مدتی پیش نوشتهاید و حالا علت رفتارهای آن را نمیدانید.
### نمونهای از استفاده:
زمانی که روی دکمه کلیک میکنید، در کنسول پیغامی مشابه زیر نمایش داده میشود:
### چه چیزی در این هوکها به شما داده میشود؟
Vue یک شیء با فیلدهای زیر به شما تحویل میدهد:
-
-
-
-
-
### چه کاربردهای مفیدی دارند؟
#### شناسایی رندرهای غیرضروری
فرض کنید کامپوننت شما هنگام تغییر یک متغیر رندر میشود، در حالی که آن متغیر اصلاً در قالب (template) استفاده نشده. در این حالت میتوانید با استفاده از
#### لاگگیری وابستگیها
میتوانید اطلاعات ردیابیشده را در قالب جدول چاپ کنید تا راحتتر متوجه شوید کامپوننت شما چه چیزهایی را دنبال میکند:
#### تحلیل عملکرد
میتوانید شمارندهای برای تعداد دفعات اجرای
---
### خلاصه:
-
-
- این ابزارها برای دیباگ و بهینهسازی بسیار کاربردی هستند.
- فقط در حالت توسعه (dev mode) استفاده شوند.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
onRenderTracked()
و onRenderTriggered()
صحبت کنیم — ابزارهایی که معمولاً کمتر مورد استفاده قرار میگیرند، در حالی که بسیار مفید هستند!### این دو چه کاری انجام میدهند؟
- `onRenderTracked`: نشان میدهد که Vue هنگام رندر شدن، چه چیزهایی را دنبال و رصد میکند (یعنی چه چیزی را "ردگیری" میکند).
- `onRenderTriggered`: مشخص میکند که چه چیزی تغییر کرده و باعث اجرای مجدد رندر شده است.
### چه زمانی باید از آنها استفاده کرد؟
- زمانی که یک کامپوننت بیش از حد و بدون دلیل واضحی رندر میشود.
- وقتی قصد بهینهسازی عملکرد (Performance Debugging) را دارید.
- زمانی که مشغول بررسی کدی هستید که توسط فرد دیگری نوشته شده یا خودتان مدتی پیش نوشتهاید و حالا علت رفتارهای آن را نمیدانید.
### نمونهای از استفاده:
<script setup>
import { ref, onRenderTracked, onRenderTriggered } from 'vue';
const count = ref(۰);
const name = ref('Vue');
onRenderTracked((e) => {
console.log('[tracked]', e);
});
onRenderTriggered((e) => {
console.log('[triggered]', e);
});
</script>
<template>
<div>
<p>شمارنده: {{ count }}</p>
<p>نام: {{ name }}</p>
<button @click="count++">افزایش</button>
</div>
</template>
زمانی که روی دکمه کلیک میکنید، در کنسول پیغامی مشابه زیر نمایش داده میشود:
[triggered] { target: ..., key: "count", type: "set" }
### چه چیزی در این هوکها به شما داده میشود؟
Vue یک شیء با فیلدهای زیر به شما تحویل میدهد:
-
effect
: ارجاع به افکت واکنشی (یعنی رندر مربوطه)-
target
: شیئی که تحت نظر قرار گرفته یا باعث اجرای مجدد شده (مانند ref
یا reactive
)-
key
: فیلد مشخصی که رصد شده (مثل count
یا name
)-
type
: نوع عملیات (مانند get`، `set`، `add`، `delete`، `clear
)-
oldValue
و newValue
(در onRenderTriggered
) — مقادیر پیش و پس از تغییر### چه کاربردهای مفیدی دارند؟
#### شناسایی رندرهای غیرضروری
فرض کنید کامپوننت شما هنگام تغییر یک متغیر رندر میشود، در حالی که آن متغیر اصلاً در قالب (template) استفاده نشده. در این حالت میتوانید با استفاده از
onRenderTriggered
و مشاهده خروجی کنسول، بفهمید که علت رندر چیست. اگر کلید مورد نظر در قالب استفاده نشده باشد، احتمالاً باید کد را بازنگری کنید.#### لاگگیری وابستگیها
میتوانید اطلاعات ردیابیشده را در قالب جدول چاپ کنید تا راحتتر متوجه شوید کامپوننت شما چه چیزهایی را دنبال میکند:
onRenderTracked((e) => {
console.table({
key: e.key,
type: e.type,
target: e.target
});
});
#### تحلیل عملکرد
میتوانید شمارندهای برای تعداد دفعات اجرای
onRenderTriggered
قرار دهید. اگر با یک کلیک، دهها بار این تابع اجرا شود، احتمال وجود یک مشکل در ساختار کامپوننت وجود دارد.---
### خلاصه:
-
onRenderTracked
= ببین Vue هنگام رندر چه چیزی را ردیابی میکند.-
onRenderTriggered
= ببین چه چیزی تغییر کرده و باعث رندر مجدد شده.- این ابزارها برای دیباگ و بهینهسازی بسیار کاربردی هستند.
- فقط در حالت توسعه (dev mode) استفاده شوند.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍3
کامپوننت KeepAlive در Vue یک کامپوننت پوششی خاص است که اجازه میدهد یک کامپوننت پس از حذف شدن از DOM همچنان در حافظه باقی بماند. بهعبارت دیگر، Vue آن را از بین نمیبرد، بلکه بهآرامی کنار میگذارد تا در صورت نیاز دوباره مورد استفاده قرار گیرد. عملکرد آن شبیه به
### کاربرد رایج:
فرض کنید در برنامه خود از زبانهها (Tabs) یا مسیرها (Routes) استفاده میکنید و میخواهید هنگام جابهجایی بین زبانهها، اطلاعات واردشده، موقعیت اسکرول و سایر وضعیتها حفظ شوند:
### اگر بخواهم کنترل کنم چه چیزی کش شود، چه کنم؟
از نسخه دو ممیز یک ممیز صفر به بعد،
#### نمونهها:
رشتهای از نامها (با ویرگول جدا شده):
عبارت منظم (Regex):
آرایهای از نامها:
### همچنین میتوانید از prop به نام
---
### چه چیزهایی در Vue ۳ جدید است؟
در گذشته، یک کامپوننت یا کش میشد یا نمیشد — همین! اما در Vue ۳، امکانات بیشتری برای کنترل رفتار فراهم شده است.
### رفتار جدید: هوکهای
وقتی یک کامپوننت در
این یعنی شما میتوانید:
- تایمرها را موقتاً متوقف کنید
- از منابع سنگین جدا شوید (unsubscribe)
- انیمیشنها را متوقف کرده یا به حالت تعلیق درآورید
### چه زمانی بهتر است استفاده نشود؟
- زمانی که کامپوننت "ارزان" است و رندر شدن آن زمان زیادی نمیبرد
- زمانی که حفظ وضعیت کامپوننت برایتان اهمیتی ندارد
- زمانی که میخواهید کامپوننت با هر بار نمایش، کاملاً از نو ساخته شود
---
### خلاصهی مطالب:
-
- از
- امکان فیلتر کردن کامپوننتها با
- میتوان با
- فقط با یک فرزند (یا تگ
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
display: none
است، با این تفاوت که تمام دادهها، واکنشپذیری و وضعیت داخلی کامپوننت حفظ میشود.### کاربرد رایج:
فرض کنید در برنامه خود از زبانهها (Tabs) یا مسیرها (Routes) استفاده میکنید و میخواهید هنگام جابهجایی بین زبانهها، اطلاعات واردشده، موقعیت اسکرول و سایر وضعیتها حفظ شوند:
<KeepAlive>
<component :is="currentTabComponent" />
</KeepAlive>
### اگر بخواهم کنترل کنم چه چیزی کش شود، چه کنم؟
از نسخه دو ممیز یک ممیز صفر به بعد،
KeepAlive
دارای دو پراپرتی include و exclude است که میتوانید نام کامپوننتها را برای کش شدن یا نشدن، در آنها مشخص کنید.#### نمونهها:
رشتهای از نامها (با ویرگول جدا شده):
<KeepAlive include="a,b">
<component :is="view" />
</KeepAlive>
عبارت منظم (Regex):
<KeepAlive :include="/a|b/">
<component :is="view" />
</KeepAlive>
آرایهای از نامها:
<KeepAlive :include="['a', 'b']">
<component :is="view" />
</KeepAlive>
### همچنین میتوانید از prop به نام
max
استفاده کنید تا مشخص کنید حداکثر چند کامپوننت در حافظه نگهداری شود:<KeepAlive max="۲">
<component :is="currentTabComponent" />
</KeepAlive>
---
### چه چیزهایی در Vue ۳ جدید است؟
در گذشته، یک کامپوننت یا کش میشد یا نمیشد — همین! اما در Vue ۳، امکانات بیشتری برای کنترل رفتار فراهم شده است.
### رفتار جدید: هوکهای
onActivated
و onDeactivated
وقتی یک کامپوننت در
KeepAlive
قرار میگیرد، برخلاف حالت عادی، Vue دیگر unmounted
را اجرا نمیکند. در عوض، این دو هوک اجرا میشوند:onActivated(() => {
console.log('من دوباره فعال شدم!');
});
onDeactivated(() => {
console.log('وقت استراحته!');
});
این یعنی شما میتوانید:
- تایمرها را موقتاً متوقف کنید
- از منابع سنگین جدا شوید (unsubscribe)
- انیمیشنها را متوقف کرده یا به حالت تعلیق درآورید
### چه زمانی بهتر است استفاده نشود؟
- زمانی که کامپوننت "ارزان" است و رندر شدن آن زمان زیادی نمیبرد
- زمانی که حفظ وضعیت کامپوننت برایتان اهمیتی ندارد
- زمانی که میخواهید کامپوننت با هر بار نمایش، کاملاً از نو ساخته شود
---
### خلاصهی مطالب:
-
KeepAlive
کامپوننتها را در حافظه نگه میدارد - از
onActivated
و onDeactivated
بهجای unmounted
استفاده میکند - امکان فیلتر کردن کامپوننتها با
include
و exclude
وجود دارد - میتوان با
max
تعداد کامپوننتهای ذخیرهشده را محدود کرد - فقط با یک فرزند (یا تگ
<component>
) بهدرستی کار میکند #️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
❤2
گاهی اوقات هنگام نوشتن یک کامپوننت، انواع ویژگیها مانند
### دقیقاً چه اتفاقی میافتد؟
Vue تمامی ویژگیهایی را که صراحتاً بهعنوان props تعریف نکردهاید**، جمعآوری کرده و آنها را روی **المان ریشهای (Root Element) کامپوننت شما قرار میدهد.
#### مثال:
و درون
در این صورت، ویژگیهای
ساده و کاربردی، نه؟
---
### اگر از ساختار سفارشی استفاده کرده باشم چه میشود؟
اگر نخواهید Vue بهطور خودکار این ویژگیها را به هر جایی منتقل کند و ترجیح دهید خودتان تعیین کنید این ویژگیها به کدام عنصر بروند**، در این صورت میتوانید از `v-bind="$attrs"` استفاده کنید.
#### نمونه:
در اینجا فقط دکمه دوم ویژگیهایی مثل `id` و `class` را دریافت میکند.
---
### اگر اصلاً نخواهید Vue چیزی منتقل کند چه؟
اگر بخواهید کنترل کامل را در دست داشته باشید، میتوانید انتقال خودکار ویژگیها را غیرفعال کنید. کافیست گزینه زیر را در کامپوننتتان اضافه کنید:
در این حالت، **هیچ ویژگیای به عنصر ریشهای (div) اضافه نمیشود و تنها به دکمه منتقل خواهد شد. این کار زمانی بسیار مفید است که بخواهید استایلها یا رویدادها دقیقاً روی یک عنصر تعاملی مثل دکمه اعمال شوند.
---
### نکات مهم:
- هر چیزی که prop نباشد، در
- بهصورت پیشفرض، تمام این ویژگیها به عنصر ریشهای کامپوننت افزوده میشوند.
- اگر میخواهید کنترل بیشتری داشته باشید، از
- میتوان
- اگر نام یک ویژگی با نام prop یکی باشد، آن ویژگی دیگر وارد
این ویژگیها به شما کمک میکنند کنترل دقیقتری بر ساختار، استایل و رفتار کامپوننتهای خود داشته باشید — خصوصاً در کامپوننتهای قابل استفاده مجدد و پیچیده.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
id`، `class`، `style
و یا ویژگیهایی با پیشوند data-*
را به آن ارسال میکنید، اما این ویژگیها در خروجی نهایی ناپدید میشوند. چرا؟ چون Vue بهصورت پیشفرض این ویژگیها را بهطور خودکار روی تمام المنتها اعمال نمیکند. ولی موضوع به همین سادگی هم نیست — ظرافتهایی دارد.### دقیقاً چه اتفاقی میافتد؟
Vue تمامی ویژگیهایی را که صراحتاً بهعنوان props تعریف نکردهاید**، جمعآوری کرده و آنها را روی **المان ریشهای (Root Element) کامپوننت شما قرار میدهد.
#### مثال:
<MyButton class="big red" id="super-btn" />
و درون
MyButton.vue
چنین چیزی نوشتهاید:<template>
<button>کلیک کن</button>
</template>
در این صورت، ویژگیهای
class="big red"
و id="super-btn"
به دکمه اضافه میشوند. ساده و کاربردی، نه؟
---
### اگر از ساختار سفارشی استفاده کرده باشم چه میشود؟
اگر نخواهید Vue بهطور خودکار این ویژگیها را به هر جایی منتقل کند و ترجیح دهید خودتان تعیین کنید این ویژگیها به کدام عنصر بروند**، در این صورت میتوانید از `v-bind="$attrs"` استفاده کنید.
#### نمونه:
<template>
<div>
<button>دکمه شماره یک</button>
<button v-bind="$attrs">دکمه شماره دو</button>
</div>
</template>
در اینجا فقط دکمه دوم ویژگیهایی مثل `id` و `class` را دریافت میکند.
---
### اگر اصلاً نخواهید Vue چیزی منتقل کند چه؟
اگر بخواهید کنترل کامل را در دست داشته باشید، میتوانید انتقال خودکار ویژگیها را غیرفعال کنید. کافیست گزینه زیر را در کامپوننتتان اضافه کنید:
<template>
<div class="wrapper">
<button v-bind="$attrs">دکمه</button>
</div>
</template>
<script setup>
defineOptions({
inheritAttrs: false
})
</script>
در این حالت، **هیچ ویژگیای به عنصر ریشهای (div) اضافه نمیشود و تنها به دکمه منتقل خواهد شد. این کار زمانی بسیار مفید است که بخواهید استایلها یا رویدادها دقیقاً روی یک عنصر تعاملی مثل دکمه اعمال شوند.
---
### نکات مهم:
- هر چیزی که prop نباشد، در
$attrs
قرار میگیرد.- بهصورت پیشفرض، تمام این ویژگیها به عنصر ریشهای کامپوننت افزوده میشوند.
- اگر میخواهید کنترل بیشتری داشته باشید، از
inheritAttrs: false
و v-bind="$attrs"
استفاده کنید.- میتوان
$attrs
را هم در بخش setup
و هم در template
بهکار برد.- اگر نام یک ویژگی با نام prop یکی باشد، آن ویژگی دیگر وارد
$attrs
نمیشود.این ویژگیها به شما کمک میکنند کنترل دقیقتری بر ساختار، استایل و رفتار کامپوننتهای خود داشته باشید — خصوصاً در کامپوننتهای قابل استفاده مجدد و پیچیده.
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍2
کتاب Chibi Vue نوشتهی یویچی کیکوچی، راهنمایی جامع و دقیق دربارهی ساختار درونی فریمورک Vue ۳ است. این کتاب بهویژه برای توسعهدهندگانی که بهصورت عمیق در حال یادگیری Vue هستند، بسیار سودمند است.
در این کتاب میخوانید:
تحلیل جامع هستهی Vue، شامل: سامانهی واکنشپذیری، کامپایلر قالبها، و سیستم رندرینگ.
پیادهسازی عملی و گامبهگام نسخهای سادهشده از Vue از ابتدا.
زبان این کتاب انگلیسی است.
🔗https://book.chibivue.land/
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
در این کتاب میخوانید:
تحلیل جامع هستهی Vue، شامل: سامانهی واکنشپذیری، کامپایلر قالبها، و سیستم رندرینگ.
پیادهسازی عملی و گامبهگام نسخهای سادهشده از Vue از ابتدا.
زبان این کتاب انگلیسی است.
🔗https://book.chibivue.land/
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
chibivue
Writing Vue.js: Step by Step, from just one line of "Hello, World".
متوقف کردن یک Watcher
Watcher**هایی که بهصورت همزمان (synchronous) درون تابع `setup()` یا در قالب `<script setup>` تعریف میشوند، به نمونه (instance) کامپوننت مالک وابسته هستند و بهطور خودکار هنگام **unmount شدن آن کامپوننت متوقف خواهند شد. در اغلب موارد، نیازی نیست نگران متوقف کردن دستی آنها باشید.
نکتهی کلیدی در اینجاست که Watcher باید بهصورت همزمان ایجاد شود؛ اگر Watcher در یک تابع غیرهمزمان (asynchronous) مانند
برای متوقف کردن دستی یک Watcher**، میتوان از تابع بازگشتی استفاده کرد. این روش هم برای `watch` و هم برای `watchEffect` کاربرد دارد:
توجه داشته باشید که تنها در موارد بسیار محدود نیاز به ایجاد **Watcher بهصورت غیرهمزمان وجود دارد، و در هر زمان ممکن، بهتر است از ایجاد همزمان استفاده شود.
اگر نیاز دارید منتظر دادهای غیرهمزمان بمانید، میتوانید منطق Watcher خود را مشروط طراحی کنید:
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
Watcher**هایی که بهصورت همزمان (synchronous) درون تابع `setup()` یا در قالب `<script setup>` تعریف میشوند، به نمونه (instance) کامپوننت مالک وابسته هستند و بهطور خودکار هنگام **unmount شدن آن کامپوننت متوقف خواهند شد. در اغلب موارد، نیازی نیست نگران متوقف کردن دستی آنها باشید.
نکتهی کلیدی در اینجاست که Watcher باید بهصورت همزمان ایجاد شود؛ اگر Watcher در یک تابع غیرهمزمان (asynchronous) مانند
setTimeout
ایجاد گردد، دیگر به کامپوننت والد وابسته نخواهد بود و باید بهصورت دستی متوقف شود تا از نشت حافظه (memory leak) جلوگیری شود. به مثال زیر توجه کنید:<script setup>
import { watchEffect } from 'vue'
// این Watcher بهصورت خودکار متوقف خواهد شد
watchEffect(() => {})
// ...اما این یکی نه!
setTimeout(() => {
watchEffect(() => {})
}, ۱۰۰)
</script>
برای متوقف کردن دستی یک Watcher**، میتوان از تابع بازگشتی استفاده کرد. این روش هم برای `watch` و هم برای `watchEffect` کاربرد دارد:
const unwatch = watchEffect(() => {})
// ...در زمانی دیگر، زمانی که دیگر نیازی نیست
unwatch()
توجه داشته باشید که تنها در موارد بسیار محدود نیاز به ایجاد **Watcher بهصورت غیرهمزمان وجود دارد، و در هر زمان ممکن، بهتر است از ایجاد همزمان استفاده شود.
اگر نیاز دارید منتظر دادهای غیرهمزمان بمانید، میتوانید منطق Watcher خود را مشروط طراحی کنید:
// دادهای که بهصورت غیرهمزمان بارگذاری میشود
const data = ref(null)
watchEffect(() => {
if (data.value) {
// انجام عملیات زمانی که داده بارگذاری شد
}
})
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
❤1👍1
در هنگام استفاده از
تنها راهحل مؤثری که تاکنون یافته شده، غیرفعال کردن این حالت (mode) در زمان توسعه است.
نمونهای از کد مربوطه:
در این وضعیت، پیشنهاد میشود برای جلوگیری از بروز مشکل، در محیط توسعه از مقدار پیشفرض
#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
router-view
همراه با transition
و تعیین `mode="out-in"`، در حالت توسعه (dev mode)، هنگام جابهجایی بین مسیرها (routes) اغلب با مشکل نمایش صفحه سفید مواجه میشویم.تنها راهحل مؤثری که تاکنون یافته شده، غیرفعال کردن این حالت (mode) در زمان توسعه است.
نمونهای از کد مربوطه:
<router-view v-slot="{ Component }">
<Transition mode="out-in">
<component :is="Component" />
</Transition>
</router-view>
در این وضعیت، پیشنهاد میشود برای جلوگیری از بروز مشکل، در محیط توسعه از مقدار پیشفرض
mode
یا از حالتهایی مانند "in-out"
یا بدون مشخصکردن mode
استفاده شود و تنها در محیط تولید (production) از حالت out-in
بهره بگیرید، چرا که این حالت در محیط توسعه ممکن است باگهایی مانند نمایش صفحه سفید موقت ایجاد کند.#️⃣#tip #vue
👥@IR_javascript_group
🆔@IR_javascript
👍3❤1