۲۸ اوت ۲۰۲۳

پنجره‌های بازشو و متدهای پنجره

یک popup window یکی از قدیمی‌ترین روش‌ها برای نشان دادن document اضافی به کاربر است.

اساسا شما فقط اجرا می‌کنید:

window.open('https://javascript.info/')

… و آن یک پنجره‌ی جدید با URL داده شده باز می‌کند. اکثر مرورگرهای مدرن به گونه‌ای پیکربندی شده‌اند که به جای پنجره‌های جداگانه، آدرس اینترنتی را در پنجره‌های جدید باز کنند.

از زمان‌های بسیار قدیم،‌ Popupها وجود دارند. ایده‌ی اولیه این بود که بتوان یک محتوای دیگر را بدون بستن پنجره‌ی اصلی نمایش داد. در حال حاضر، راه‌های دیگری برای این کار وجود دارد: می‌توانیم داده را به صورت پویا با fetch بارگیری کنیم و آن را در یک <div> که به صورت پویا ایجاد شده است نمایش دهیم. بنابراین، popupها چیزهایی نیستند که ما هر روز از آن‌ها استفاده کنیم.

همچنین، popupها در دستگاه‌های موبایل که چند پنجره را به صورت همزمان نشان نمی‌دهند کمی مشکل هستند.

با این حال، کارهایی وجود دارند که popupها هنوز در آن‌ها استفاده می‌شوند. برای مثال، برای مجوز OAuth (lgin با Google/Facebook/…) چون که:

  1. یک popup پنجره‌ای جدا است که محیط JavaScript جداگانه‌ی خود را دارد. بنابراین باز کردن یک popup از یک سایت سوم غیر قابل اطمینان، امن است.
  2. باز کردن یک popup بسیار ساده است.
  3. یک popup می‌تواند پیمایش کند (آدرس سایت را تغییر دهد)‌ و به پنجره‌ی بازکننده پیام بفرستد.

مسدود کردن popup

در گذشته، سایت‌های خبیث بسیار از popup سواستفاده می‌کردند. یک صفحه می‌توانست تعداد زیادی popup با تبلیغات باز کند. بنابراین امروزه، اکثر مرورگرها تلاش می‌‌کنند که popup را مسدود کنند و از کاربر در برابر آن‌ها محافظت کنند.

اکثر مرورگرها، اگر فراخوانی popupها خارج از event handlerهای ایجاد شده توسط کاربر صورت بگیرد، آن‌ها را مسدود می‌کنند.

برای مثال:

// popup مسدود شده است
window.open('https://javascript.info');

// popup اجازه داده شده است
button.onclick = () => {
  window.open('https://javascript.info');
};

به این ترتیب، کاربرها تا حدودی از popupهای ناخواسته محافظت می‌شوند، اما عملکرد به طور کامل غیرفعال نمی‌شود.

window.open

برای باز کردن یک popup از syntax روبه‌رو استفاده می‌شود: window.open(url, name, params):

url
یک URL برای بارگیری در پنجره جدید.
name
یک name پنجره‌ی جدید. هر پنجره یک window.name دارد و اینجا می‌توانیم مشخص کنیم که از کدام پنجره به عنوان popup استفاده کنیم. اگر قبلا پنجره‌ای با این نام وجود داشته باشد، – URL داده شده در آن باز می‌شود، در غیر این صورت، یک پنجره‌ی جدید باز می‌شود.
params
رشته‌ی configuration برای پنجره‌ی جدید. این شامل تنظیماتی است که با comma مشخص می‌شوند. هیچ spaceای نباید در params وجود داشته باشد،‌ برای مثال: width=200,height=100

تنظیمات برای params:

  • Position:
    • چپ/بالا(عددی) – مختصات گوشه‌ی سمت چپ بالای پنجره در صفحه. یک محدودیت وجود دارد: یک پنجره‌ی جدید را نمی‌توان خارج صفحه قرار داد.
    • عرض/ارتفاع(عددی) – عرض و ارتفاع یک پنجره‌ی جدید. در حداقل عرض/ارتفاع یک محدودیت وجود دارد. بنابرین غیرممکن است که یک پنجره‌ی غیرقابل دیدن ایجاد کرد.
  • ویژگی‌های پنجره:
    • menubar (بله/خیر) – .منوی مرورگر را در پنجره جدید نشان می‌دهد یا پنهان می‌کند
    • toolbar (بله/خیر) – .نوار پیمایش مرورگر (به عقب، جلو، بارگذاری مجدد و …) را در پنجره جدید نشان می‌دهد یا پنهان می‌کند
    • location (بله/خیر) – .به طور پیش فرض اجازه مخفی کردن آن را نمی‌دهند IE و FF را در پنجره‌ی جدید نشان می‌دهد یا پنهان می‌کند URL فیلد
    • status (بله/خیر) – .را نشان می‌دهد یا پنهان می‌کند. باز هم، اکثر مرورگرها آن را مجبور به نمایش می‌کنند status bar
    • resizable (بله/خیر) – .اجازه می‌دهد تا تغییر اندازه را برای پنجره جدید غیرفعال کنید. توصیه نمی‌شود
    • scrollbars (بله/خیر) – .اجازه می‌دهد تا نوارهای اسکرول را برای پنجره جدید غیرفعال کنید. توصیه نمی‌شود.

همجنین، تعدادی ویژگی خاص مرورگر وجود دارند که کمتر پشتیبانی می‌شوند که معمولا از آن‌ها استفاده نمی‌شود. برای مثال، window.open در MDN را بررسی کنید.

مثال: یک پنجره‌ی minimalistic

بیایید یک پنجره با حداقل مجموعه‌ای ویژگی‌ها باز کنیم،‌ فقط برای آن که ببینیم مرورگر کدام یکی از آن‌ها را غیرفعال می‌کند:

let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=0,height=0,left=-1000,top=-1000`;

open('/', 'test', params);

اینجا اکثر “ویژگی‌های پنجره” غیرفعال شده‌اند و پنجره خارج صفحه قرار می‌گیرد. آن را اجرا کنید و ببینید واقعا چه اتفاقی می‌افتد. اکثر مرورگرها موارد عجیب و غریب مثل width/height صفر و left/top خارج از صفحه را درست می‌کنند. برای مثال، chrome همچین پنجره‌ای را با عرض/ارتفاع کامل باز می‌کند تا تمام صفحه را اشغال کند.

بیایید گزینه‌های موقعیت‌یابی عادی و مختصات عرض، ارتفاع، چپ، بالا را اضافه کنیم:

let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=600,height=300,left=100,top=100`;

open('/', 'test', params);

اکثر مرورگرها مثال بالا را در صورت لزوم نشان می دهند.

قوانین مربوط به تنظیمات حذف شده:

  • اگر هیچ آرگومان سومی در فراخوانی open نیست یا خالی است، آنگاه پارامترهای پیش‌فرض پنجره استفاده می‌شوند.
  • اگر رشته‌ای از params وجود دارد اما بعضی از ویژگی‌های yes/no حذف شده‌اند،‌ آنگاه فرض می‌شود که ویژگی‌های حذف‌شده مقدار no را دارند. اگر پارامترها را مشخص می‌کنید،‌مطمئن شوید که تمام ویژگی‌های مورد نیاز به صراحت روی yes تنظیم شده‌اند.
  • اگر هیچ left/topای در params وجود ندارد، مرورگر تلاش می‌کند که پنجره‌ای جدید را نزدیک آخرین پنجره‌ی باز شده، باز کند.
  • اگر هیچ width/heightای وجود ندارد، پنجره‌ی جدید همان اندازه‌ی آخرین پنجره‌ی باز شده را خواهد داشت.

دسترسی به popup از طریق پنجره

فراخوانی open ارجاعی به پنجره‌ی جدید را برمی‌گرداند. از آن می‌توان برای دستکاری کردن propertyها، تغییر دادن location و حتی بیشتر استفاده کرد.

در این مثال، ما از JavaScript محتوای popup را تولید می‌کنیم.

let newWin = window.open("about:blank", "hello", "width=200,height=200");

newWin.document.write("Hello, world!");

و اینجا بعد از load کردن، محتوا را دستکاری می‌کنیم.

let newWindow = open('/', 'example', 'width=300,height=300')
newWindow.focus();

alert(newWindow.location.href); // (*) about:blank,  هنوز شروع نشده است loading

newWindow.onload = function() {
  let html = `<div style="font-size:30px">Welcome!</div>`;
  newWindow.document.body.insertAdjacentHTML('afterbegin', html);
};

لطفا توجه داشته باشید: بلافاصله بعد از window.open پنجره‌ی جدید هنوز load نشده است. آن، در خط (*) با alert نشان داده می‌شود. پس صبر می‌کنیم تا onload آن را اصلاح کند. همچنین برای newWin.document می‌توانیم از DOMContentLoaded handler استفاده کنیم.

سیاست مبدا یکسان

.می‌توانند به صورت آزادانه به محتوای یکدیگر دسترسی داشته باشند (همان پروتکل://domain:port) پنجره‌ها فقط در صورتی که از یک مبدا باشند

.را ببینید ارتباط بین پنجره‌ای این برای دلایل امنیتی غیرممکن است. برای جزئیات، بخش gmail.com از popup باشد و site.com در غیر این صورت، برای مثال اگر پنجره‌ی اصلی از

دسترسی به پنجره از طریق popup

یک popup علاوه بر استفاده از ارجاع window.opener می‌تواند به “opener” هم دسترسی داشته باشد. این برای تمام پنجره‌ها به جز popupها null است.

اگر کد زیر را اجرا کنید، محتوای openr window (در حال حاضر) را با “Test” جایگزین می‌کند.

let newWin = window.open("about:blank", "hello", "width=200,height=200");

newWin.document.write(
  "<script>window.opener.document.body.innerHTML = 'Test'<\/script>"
);

بنابراین، ارتباط میان پنجره‌ها دوطرفه است: پنجره‌ی اصلی و popup ارجاعی به یکدیگر دارند.

بستن یک popup

برای بستن یک پنجره: win.close().

برای اینکه چک کنیم که یه پنجره بسته است یا نه: win.closed.

از نظر فنی، close() method برای هر window قابل دسترسی است اما اگر window با window.open() ایجاد شده باشد، window.close() توسط اکثر مرورگرها نادیده گرفته می‌شود. پس آن فقط روی یک popup کار خواهد کرد.

اگر پنجره بسته باشد، closed property برابر true می‌شود. این برای بررسی اینکه popup (یا پنجره‌ی اصلی) هنوز باز هستند یا نه مفید است. یک کاربر می‌تواند هر وقتی ببندد و کد ما باید امکان آن را در نظر بگیرد.

این کد پنجره را load می‌کند و سپس می‌بندد.

let newWindow = open('/', 'example', 'width=300,height=300');

newWindow.onload = function() {
  newWindow.close();
  alert(newWindow.closed); // true
};

حرکت دادن و تغییر اندازه

راه‌هایی برای جابه‌جایی/تغییر اندازه‌ی یک پنجره وجود دارد:

win.moveBy(x,y)
پنجره را نسبت به موقعیت فعلی، x پیکسل به سمت راست و y پیکسل به سمت پایین حرکت می‌دهد. مقادیر منفی هم مجاز هستند (برای حرکت دادن به چپ/بالا)
win.moveTo(x,y)
پنجره را به مختصات (x,y) در صفحه می‌برد.
win.resizeBy(width,height)
پنجره را با اندازه‌های width/height داده شده نسبت به اندازه‌ی فعلی تغییر سایز می‌دهد. مقادیر منفی مجاز هستند.
win.resizeTo(width,height)
پنجره را به اندازه‌ی داده شده تغییر اندازه می‌دهد.

همچنین یک window.onresize event نیز وجود دارد.

فقط popups

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

No minification/maximization

.پنهان هستند Frontend-developers هیچ راهی برای به حداقل رساندن یا به حداکثر رساندن یک پنجره نیست. این متدها که در سطح سیستم‌عامل هستند از دید JavaScript در

.روش‌های جابجایی/تغییر اندازه برای پنجره‌های حداکثر/حداقل شده کار نمی‌کنند

پیمایش یک پنجره

ما قبلا در مورد scroll کردن یک پنجره در بخش Window sizes and scrolling صحبت کرده‌ایم.

win.scrollBy(x,y)
پنجره را نسبت به scroll فعلی، x پیکسل به راست و y پیکسل به پایین scroll می‌کند. مقادیر منفی مجاز هستند.
win.scrollTo(x,y)
پنجره را به مختصات داده شده (x,y) scroll می‌کند.
elem.scrollIntoView(top = true)
پنجره را scroll می‌کند که elem را در بالا (پیش فرض) یا پایین برای elem.scrollIntoView(false) نمایش دهد.

همچنین یک window.onscroll event نیز هست.

Focus/blur روی یک پنجره

از نظر تئوری برای focus/unfocus کردن روی یک پنجره، دو متد window.focus() و window.blur() وجود دارند. و همچنین focus/blur events هستند که که اجازه می‌دهند که لحظه‌ای که بازدیدکننده روی یک پنجره focus/unfocus می‌کند و به جای دیگری تغییر می‌دهد را ثبت کنید.

اگرچه، در عمل آنها به شدت محدود هستند، زیرا در گذشته صفحات بد از آنها سوء استفاده می‌کردند.

برای مثال به این کد نگاه کنید:

window.onblur = () => window.focus();

وقتی یک کاربر تلاش می‌کند که از پنجره بیرون برود (window.onblur)، این، پنجره را به focus برمی‌گرداند. هدف این است که کاربر را در window قفل کنیم.

در نتیجه مرورگرها مجبور بودند تعدادی محدودیت معرفی کنند تا کدی مثل آن را ممنوع کند و کاربر را از تبلیغات و صفحات بد محافظت کنند. آن‌ها به مرورگر بستگی دارند.

برای مثال، یک مرورگر موبایل معمولا window.focus() را به طور کامل نادیده می‌گیرد. همچنین وقتی که یک popup در یک صفحه‌ی جدا به جای یک پنجره‌ی جدبد باز می‌شود، فوکوس کردن کار نمی‌کند.

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

برای مثال:

  • وقتی یک popup باز می‌کنیم، ممکن است ایده‌ی خوبی باشد که newWindow.focus() را روی آن اجرا کنیم. در هر صورت، برای برخی ترکیبات سیستم‌عامل/مرورگر، تضمین می‌کند که کاربر اکنون در پنجره‌ی جدید است.
  • گر بخواهیم ردیابی کنیم که چه زمانی بازدیدکننده واقعاً از برنامه‌ی وب ما استفاده می کند، می توانیم window.onfocus/onblur را ردیابی کنیم. این به ما امکان می‌دهد فعالیت‌های درون صفحه، انیمیشن‌ها و… را تعلیق/ازسرگیری کنیم. اما لطفا توجه داشته باشید که blur event به این معنی است که بازدیدکننده از پنجره خارج شده است، اما همچنان ممکن است آن را مشاهده کند. پنجره در پس‌زمینه است، اما همچنان ممکن است قابل مشاهده باشد.

خلاصه

پنجره‌های popup به ندرت استفاده می‌شوند. چون گزینه‌های دیگری وجود دارند: load کردن و نمایش دادن اطلاعات در صفحه یا در iframe.

اگر می‌خواهیم یک popup باز کنیم، یک تمرین خوب این است که به کاربر درباره‌ی آن اطلاعات بدهیم. یک نماد “opening window” نزدیک یک لینک یا دکمه به بازدیدکننده اجازه می‌دهد تا از تغییر فوکوس جان سالم به در ببرد و هر دو پنجره را در ذهن نگه دارد.

  • یک popup می‌تواند با فراخوانی open(url, name, params) باز شود. آن ارجاع را به پنجره‌ی تازه بازشده بازمی‌گرداند.
  • مرورگرها فراخوانی‌های open از خارج کنش‌های کاربر را مسدود می‌کنند. معمولا یک اعلان ظاهر می‌شود که کاربر ممکن است به آن‌ها اجازه بدهد.
  • مرورگرها به صورت پیش‌فرض یک tab جدید باز می‌کنند اما اگر اندازه‌ها ارائه شده باشند، آنگاه یک پنجره‌ی popup خواهد بود.
  • پنجره‌ی popup ممکن است با استفاده از window.opener property به پنجره‌ی بازکننده دسترسی داشته باشد.
  • اگر popup و پنجره‌ی اصلی از یک مبدا باشند، می‌توانند به صورت آزادانه یکدیگر را بخوانند یا تغییر دهند. در غیر این صورت، می‌توانند مکان یکدیگر را تغییر دهند و پیام رد و بدل کنند.

برای بستن popup: از فراخوانی close() استفاده کنید. همچنین کاربر ممکن است آن‌ها را ببندد (دقیقا شبیه هر پنجره‌ی دیگری). بعد از آن مقدار window.closed برابر true است.

  • متدهای focus() و blur() اجازه می‌دهند که روی یک پنجره focus/unfocus کنیم. اما آن‌ها همیشه کار نمی‌کنند.
  • با focus and blur events امکان ردیابی جابه‌جایی در داخل و خارج صفحه فراهم می‌شود/ اما لطفا توجه داشته باشید که بعد از blur یک پنجره ممکن است همچنان در وضعیت پس‌زمینه قابل مشاهده باشد.
نقشه آموزش