
در جلسه قبل موفق شدیم که داده های خود را درون localStorage ذخیره سازی کنیم اما هنوز فرآیند login خودکار را انجام نداده ایم. ما برای انجام login خودکار باید به فایل App.vue رفته و از lifecycle ای به نام Created استفاده کنیم اما قبل از آن به store.js رفته و action دیگری را تعریف می کنیم. این action مسئول اجرای login خواهد بود و چند شرط مختلف را چک خواهد کرد. در مرحله اول می گوییم:
tryAutoLogin({ commit }) { const token = localStorage.getItem('token'); if (!token) { return; } }, logout({ commit }) { commit('clearAuthData'); router.replace('/signin'); },
همانطور که مشخص است من نام این Action را tryAutoLogin گذاشته ام. در قدم اول مقدار token که همان توکن امنیتی ذخیره شده در localStorage است را دریافت کرده و آن را بررسی کرده ام. اگر token وجود نداشته باشد (علامت تعجب در شرط if) یعنی کاربر اصلا login نشده است بنابراین فقط return می کنیم که یعنی از تابع خارج می شویم اما این تنها شرط مورد بررسی ما نیست. شرط بعدی ما expirationDate است! اگر expirationDate از تاریخ فعلی بیشتر باشد یعنی توکن منقضی شده است و اعتباری ندارد بنابراین در این حالت هم نباید سعی در login کردن داشته باشیم:
tryAutoLogin({ commit }) { const token = localStorage.getItem('token'); if (!token) { return; } const expirationDate = localStorage.getItem('expirationDate'); const now = new Date(); if (now >= expirationDate) { return; } }
مقدار expirationDate در localStorage موجود است و ما می توانیم با متد getItem آن را بگیریم. برای دریافت تاریخ فعلی نیز از new Date استفاده می کنیم. در نهایت در یک شرط if بزرگ تر یا مساوی بودن now را بررسی می کنیم و اگر اینطور بود فقط return می کنیم تا از تابع خارج شویم.
اگر هیچ کدام از این شرط ها صحیح نبودند می توانیم به راحتی login کنیم اما mutation ای که مسئول login کردن کاربر بود به شکل زیر است:
authUser(state, userData) { state.idToken = userData.token; state.userId = userData.userId; }
یعنی userData را از ما می خواهد که همان token و userId است. توجه کنید که پاس دادن شیء userData واقعا به همین نام الزامی نیست بلکه باید شیء ای به این mutation پاس داده شود که بتوان از درون آن دو خصوصیت token و userId را استخراج کرد. یکسان بودن نام ها اصلا مهم نیست. بنابراین باید به localStorage برگشته و علاوه بر token و expirationDate، مقدار userId را نیز دریافت کنیم:
signup({ commit, dispatch }, authData) { axios .post("/accounts:signUp?key=AIzaSyDtirb936QLEAL9Hbkn1st5c3cF3U7_cFI", { email: authData.email, password: authData.password, returnSecureToken: true }) .then(res => { console.log(res); commit('authUser', { token: res.data.idToken, userId: res.data.localId }); const now = new Date(); const expirationDate = new Date(now.getTime() + res.data.expiresIn * 1000); const expirationDate = now.getTime() + res.data.expiresIn * 1000; localStorage.setItem('token', res.data.idToken); localStorage.setItem('userId', res.data.localId); localStorage.setItem('expirationDate', expirationDate); dispatch('storeUser', authData); dispatch('setLogoutTimer', res.data.expiresIn); }) .catch(error => console.log(error)); }
همین کار را در Login نیز انجام می دهیم:
login({ commit, dispatch }, authData) { axios .post( "/accounts:signInWithPassword?key=AIzaSyDtirb936QLEAL9Hbkn1st5c3cF3U7_cFI", { email: authData.email, password: authData.password, returnSecureToken: true } ) .then(res => { console.log(res); const now = new Date(); const expirationDate = new Date(now.getTime() + res.data.expiresIn * 1000); localStorage.setItem('token', res.data.idToken); localStorage.setItem('userId', res.data.localId); localStorage.setItem('expirationDate', expirationDate); commit('authUser', { token: res.data.idToken, userId: res.data.localId }); dispatch('setLogoutTimer', res.data.expiresIn); }) .catch(error => console.log(error)); },
حالا به tryAutoLogin برگشته و این مقدار را از localStorage می گیریم:
tryAutoLogin({ commit }) { const token = localStorage.getItem('token'); if (!token) { return; } const expirationDate = localStorage.getItem('expirationDate'); const now = new Date(); if (now >= expirationDate) { return; } const userId = localStorage.getItem('userId'); commit('authUser', { token: token, userId: userId }) }
در قدم اول باید متد Commit را از شیء context خارج می کردیم تا بتوانیم mutation خود را commit کنیم. سپس userId را دریافت کرده و درون ثابتی به همین نام قرار می دهیم. در نهایت برای Commit کردن یک شیء جاوا اسکریپتی را پاس داده ام که حاوی token و userId باشد. به نظر شما کد بالا کار می کند؟ از آنجایی که از قبل توکن خود را در localStorage داریم، به صفحه Clear Storage می روم و در انتهای آن گزینه Clear Site Data را می زنم تا از صفر و از اول شروع کنیم. حالا اگر دوباره login شویم و صفحه را refresh کنیم، login می شویم؟ خیر! چرا؟ به دلیل اینکه اصلا از tryAutoLogin در هیچ قسمتی از برنامه استفاده نکرده ایم! برای این کار به App.vue می رویم و از lifecycle ای به نام Created استفاده می کنیم:
<script> import Header from "./components/header/header.vue"; export default { name: "app", components: { "app-header": Header }, created() { this.$store.dispatch("tryAutoLogin"); } }; </script>
با این کار کدها باید کار کنند و اگر در مرورگر آن ها را تست کنید نیز این اتفاق می افتد (با refresh شدن صفحه، login می شویم) اما مشکلی داریم. پس از کلیک روی دکمه logout (نه refresh شدن صفحه)، مقادیر موجود در localStorage حذف نمی شوند. یادتان باشد که اگر روی دکمه logout کلیک شد، یعنی کاربر نمی خواهد login شود بنابراین باید این مقادیر را حذف کنیم.
برای این کار به فایل Store.js رفته و در اکشن logout بدین شکل عمل می کنیم:
logout({ commit }) { commit('clearAuthData'); localStorage.removeItem('expirationDate'); localStorage.removeItem('token'); localStorage.removeItem('userId'); router.replace('/signin'); },
removeItem باعث حذف شدن آیتم های پاس داده شده از localStorage می شود. البته می توانستیم به جای اینکه تک تک آیتم ها را بدین شکل حذف کنیم از متد clear به شکل زیر استفاده کنیم:
logout({ commit }) { commit('clearAuthData'); localStorage.clear(); router.replace('/signin'); }
اما در بسیاری از اوقات علاوه بر این گزینه ها، ممکن است داده های دیگری را در localStorage داشته باشیم که نخواهیم حذف شوند. همچنین شما می توانید یک شیء را در localStorage ذخیره کنید تا نیاز نباشد تک تک موارد را جداگانه ثبت و حذف کنید اما یادتان باشد که localStorage فقط مقادیر رشته ای را قبول می کند بنابراین برای ثبت اشیاء باید به شکل زیر عمل کنید:
localStorage.setItem('user', JSON.stringify(user));
JSON.stringify متدی جاوا اسکریپتی است که مقادیر پاس داده شده را به صورت رشته در می آورد. همچنین برای دریافت داده هایی که بدین شکل ذخیره شده اند می گوییم:
const user = JSON.parse(localStorage.getItem('user'));
JSON.parse شیء ما را از حالت رشته ای JSON خارج می کند تا بتوانیم مانند یک شیء عادی از آن استفاده کنیم. چنین مواردی همگی به سلیقه شما بستگی داشته و هیچ راه بهتری وجود ندارد. به شما تبریک می گویم! شما فصل دوم پیوست را نیز تمام کردید! ما از پروژه این فصل در فصل بعدی استفاده خواهیم کرد بنابراین حتما آن را از اینجا دانلود کنید:
- نصب و راهاندازی فریمورک VueJS
- مثالی قویتر و نصب محلی Vue
- درکی ساده از Tamplateها در Vue
- درک بهتر Directiveها + برخی از Directiveهای مشهور
- تعامل با Event Listenerها
- قدرت Vue با انواع Modifierها
- مبحث two-way-binding و پاسخ به تغییرات
- خصوصیات محاسبهشده (Computed Properties)
- روش جایگزین خصوصیات Computed
- استایلدهی پویا با اشیاء
- استایلدهی پویا اسمی بدون استفاده از کلاسها
- ایجاد شرط با v-if
- نمایش لیستها با v-for
- گردش درون اشیاء
- رهگیری عناصر در v-for
- اولین پروژه تمرینی – آمادهسازی اولیه
- پیادهسازی منطق شروع بازی
- تکمیل دکمه Attack
- کدنویسی متدهای باقیمانده در بازی
- نمایش log و اتمام پروژه
- آشنایی و تعامل بیشتر با شیء Vue
- نحوه مدیریت دادهها در شیء Vue
- استفاده از ref$ در قالبهای HTML
- آشنایی با Mount کردن Templateها
- نحوه بهروزرسانی DOM و چرخه زندگی شیء Vue
- استفاده از Lifecycleها در عمل
- راهاندازی سرور محلی Vue
- آشنایی با Vue CLI
- درک بهتر فایلهای Vue
- آشنایی با کامپوننتها
- ساخت کامپوننتها
- استفاده از کامپوننتها و قوانین آن
- ارتباط بین کامپوننتها با Props
- اعتبارسنجی Props
- رویدادهای شخصیسازیشده
- ارتباط بین کامپوننتهای خواهر و برادر
- استفاده از یک شیء سراسری Vue
- آشنایی با Slotها
- بررسی جزئیات بیشتری از Slotها
- قابلیتی جدید به نام Dynamic Components
- مرگ کامپوننتهای پویا
- فصل جدید و پروژه جدید
- پروژه Quote – پاسدادن دادهها با Prop
- پروژه Quote – تکمیل ثبت Quote
- تکمیل پروژه Quoteها
- فصل جدید، کار با فرمها
- کار با عناصر Textarea
- عناصر Checkbox و Radiobutton
- کار با منوهای آبشاری و جزئیات v-model
- تعریف عناصر شخصیسازیشده
- نگاهی عمیقتر به Directiveها
- ساخت یک Directive شخصی
- ثبت محلی Directiveها + قدمی پیشرفتهتر
- آشنایی با Filterها
- جایگزینی برای Filterها
- آشنایی با Mixinها
- جزئیات تکمیلی در مورد Mixinها
- آشنایی با انیمیشنها در Vue
- استفاده عملی از Transition و Animation
- ترکیب Transition و Animation
- استفاده از کلاسهای CSS مختلف
- تبدیل عناصر مختلف به یکدیگر با انیمیشن
- اعمال انیمیشن با جاوا اسکریپت
- کدنویسی متدهای مربوط به hookهای جاوا اسکریپتی
- تکمیل انیمیشن جاوا اسکریپتی + کامپوننتهای پویا
- ساخت یک لیست برای انیمیشنهای گروهی
- اضافهکردن انیمیشن به لیست ساختهشده
- مینی پروژه فصل – سوالات ریاضی
- تکمیل پروژه و اضافهکردن انیمیشن
- فصل جدید، درخواستهای HTTP
- ارسال اطلاعات به Firebase
- دریافت دادهها از Firebase
- آشنایی با Interceptorها در Vue-Resource
- آشنایی با مفهوم Resource در Vue-Resource
- جزئیات تکمیلی Resourceها
- فصل جدید، آشنایی با Routing
- آشنایی با Routing Modes و اضافهکردن لینکها
- استایلدهی لینک فعال
- ایجاد Navigation با کد و پارامترهای URL
- واکنش به تغییرات URL و پارامترهای آن
- ساخت URLهای پویاتر با Named Routes
- مباحث Query Parameter و Redirection
- مبحث Redirect و اضافهکردن انیمیشن
- پاسدادن # و کنترل عملیات اسکرول
- محافظت از Routeها با استفاده از Gaurdها (قسمت اول)
- محافظت از Routeها با استفاده از Gaurdها (قسمت دوم)
- بارگذاری Routeها به صورت lazy
- فصل جدید، آشنایی با VueX
- نحوهی پیادهسازی اولیهی پکیج VueX
- آشنایی با Getterها در VueX
- اتصال خودکار Getterها به خصوصیات
- حل مشکل ترکیب Getterها و Computed Props
- آشنایی با مبحث Mutation در VueX
- آشنایی با Actionها در Mutations
- درک عملیاتهای پشت صحنه در mapActions
- خلاصهی جلسات قبل + معرفی مشکلی جدید
- اعمال two-way-binding در VueX
- ماژولار کردن مدیریت State در VueX
- استفاده از Namespaceها در VueX
- فصل جدید، پروژهی نهایی دوره
- پیادهسازی Header یا Navigation سایت
- ایجاد ساختار برای قسمت سهام (stocks)
- اضافهکردن منطق دکمهی Buy
- پیادهسازی VueX روی پروژه
- تعریف Mutationهای ماژول Portfolio در VueX
- پیادهسازی Getters برای ماژول Portfolio در VueX
- تکمیل کامپوننت Portfolio و نمایش سهام
- اعتبارسنجی برای فروش سهام و استفاده از فیلترها
- نمایش Funds و اعتبارسنجی برای خرید سهام
- پایان دادن به روز + اضافه کردن انیمیشن به صفحات
- پیادهسازی drop-down و راهاندازی Firebase
- ذخیره و دریافت قیمتها با درخواستهای PUT و GET
- تکمیل دکمهی Load Data و کار با Vue dev Tools
- خروجیگرفتن نهایی از برنامه برای قرارگیری روی سرور
- فصل پیوست ۱: استفاده از axios به جای vue-resource
- فصل پیوست ۱: درخواست GET در axios
- فصل پیوست ۱: استفاده از Interceptorها در Axios
- فصل پیوست ۲: احراز هویت در برنامههای SPA
- فصل پیوست ۲: ساخت کاربر جدید با ایمیل و رمز عبور
- فصل پیوست ۲: دریافت توکن احراز هویت در مرورگر
- فصل پیوست ۲: تکمیل منطق برنامه و کدهای باقیمانده
- فصل پیوست ۲: پیوست توکن به درخواستهای خروجی
- فصل پیوست ۲: بهینهسازی برنامه و Path Guard
- فصل پیوست ۲: اضافهکردن مکانیسم logout از حساب
- فصل پیوست ۲: پیادهسازی logout خودکار از حساب
- فصل پیوست ۲: ذخیرهی دادهها در localStorage
- فصل پیوست ۲: پیادهسازی فرآیند login خودکار
- فصل پیوست ۳: فصل جدید، اعتبارسنجی دادههای کاربر
- فصل پیوست ۳: ارائهی فیدبک اعتبارسنجی در UI
- فصل پیوست ۳: آشنایی با Validatorهای عددی
- فصل پیوست ۳: آشنایی با Validatorهای رمز عبور
- فصل پیوست ۳: آشنایی با requiredUnless
- فصل پیوست ۳: اعتبارسنجی آرایههای پویا
- فصل پیوست ۳: ثبت فرم و اعتبارسنجیهای ناهمگام
- فصل پیوست ۴: نسخهی 3 از Vue CLI
- فصل پیوست ۴: آشنایی با پروژه در CLI جدید
- فصل پیوست ۴: استفاده و کار با پلاگینها در CLI جدید
- فصل پیوست ۴: آشنایی با Environment Variables
- فصل پیوست ۴: خروجی گرفتن از برنامه نهایی
- فصل پیوست ۴: شخصیسازی بیشتر Build
- فصل پیوست ۴: استفاده از GUI