تطبيق الصفحة الواحدة (بالإنجليزية: Single-page application) اختصاراٌ (SPA)، هو تطبيق أو موقع ويب، يميزه عن غيره من التطبيقات طريقة تفاعل الصفحة مع نشاط المستخدم
**تطبيق الصفحة الواحدة** (بالإنجليزية: Single-page application)‏ اختصاراٌ (SPA)، هو تطبيق أو موقع ويب، يميزه عن غيره من التطبيقات طريقة تفاعل الصفحة مع نشاط المستخدم، فعندما يقوم المستخدم بنشاط معين على الصفحة يستدعي على أثره حدوث بعض التغييرات، يقوم تطبيق الصفحة الواحدة بتعديل محتوى الصفحة دون الحاجة إلى تحميل صفحة جديدة من الخادم، ما يميّز هذه الطريقة أنها مريحة للمستخدم ولا تزعجه بتحميل صفحات ويب متتالية، مما يجعل التطبيق أشبه ما يكون بتطبيقات سطح المكتب، أو حتى تطبيقات الأجهزة الذكية.

آلية العمل
----------

أما عن الآلية التي يتم بها تعديل محتوى الصفحة، فهي تتم بناءاً على النشاطات التي يقوم بها المستخدم، فمع كل نشاط جديد يتم إضافة المحتوى المناسب للصفحة، سواءا أكان محتوى HTML أو CSS أو حتى Javascript، ويمكن أن يتم ذلك كتحميل صفحة مرّة واحدة (كل المحتوى) ، أو يُضاف المحتوى بشكل متفاعل مع المستخدم وبحسب ما هو ضروري، لكن خلال هذه العملية لا يتم إطلاقا إعادة تحميل الصفحة أو ينتقل التحكم بالمحتوى إلى صفحة أخرى، من ناحية أخرى، يمكن استعمال ما يُسمّى خاصية موقع التجزئة Location Hash أو خاصية History API المدعومة من HTML5 والتي تُستخدم لتوفير تصوّر عن الصفحات المنفصلة داخل التطبيق وطريقة الوصول إليها.

يجدر الإشارة إلى أنه أحيانا أثناء تفاعل المستخدم مع تطبيق الصفحة الواحدة فإنه يجري تواصل مستمر ومتفاعل مع خادم الويب لكن كما يقال *خلف الكواليس*.

التاريخ
-------

أصل مصطلح *single-page application* غير واضح، وعلى الأرجح أن المفهوم تم مناقشنته في وقت مبكر آوئل الآلفية الجديدة مطلع 2003.

التقنيات والآليات المستعملة
---------------------------

في الغالب ما تستعمل بعض التنيكات والإعدادات، والآدوات كأطارات العمل، لبرمجة تطبيقات ويب الصفحة الواحدة.

### هاش الموقع (Location hash)

#### التعريف

Location Hash **هاش الموقع** أو **هاش التجزئة**، ترمز إلى **علامة المربع #** التي تكون في رابط الصفحة URL على سبيل المثال: 

وتُعرف بشكل رسمي بـfragment identifier of the URL أي (جزء معرف الـ URL)

الرابط أعلاه يحتوي على مسار مؤدي إلى صفحة `شبكة\_عنكبوتية\_عالمية` في ويكيبيديا وفي نهايته هناك **علامة #** تحوي بعدها كلمة **تعريف**، ولو قمت بزيارة هذا الرابط سيقوم المتصفح بشكل تلقائي بالنزول والتركيزعلى قسم التعريف. تساعد هذه الخاصية على التصفح الداخلي لملفات HTML، حيث يتم إضافة ارتباط تشعبي في ملف الـ HTML يُشير إلى **مُعرف ID** معين في لأحد العناصر في الصفحة، وسيقوم المتصفح بشكل تلقائي بالتركيز إلى ذلك الجزء، تستخدم هذه الميزة في الكثير من المواقع منها ويكيبيديا لتسهيل الوصول إلى أجزاء معينة في الصفحة.

مثال:

```
<a href="#something">Go To Something Section</a>
            ...
       <section id="something">
           <p>Some Content Here</p>
       </section>

```
حين الضغط على **Go To Something Section** سيقوم المتصفح بنقلك إلى مكان العنصر نفسه بالصفحة ذاتها ويقوم بالتركيز عليه، يمكن استخدام pseudo-class `:target` في CSS لتنسيق العنصر بطريقة معينة في حال تم الانتقال إليه باستخدام **Location hash**.

#### الاستخدام في تطبيقات الويب ذات الصفحة الواحدة

تستخدم هذا الخاصية كتكنيك لعمل روابط تؤدي إلى محتويات أخرى تحاكي الروابط العادية بدون قيام المتصفح بتحديث الصفحة لأن المتصفح سوف يظن أنها مجرد تنقلات داخلية.

مثال: 

في هذه الحالة سيكون المتصفح في الصفحة الرئيسية أي / ولكن من خلال كود جافاسكربت، يمكن برمجة الصفحة أن تقوم بتحميل أو عرض مُحتوى آخر بحسب الجزئية التي تلي ما بعد **علامة المربع** #.

#### العيوب

لو تم استخدام هذا المفهوم في الموقع، قد لا يتم فهرسة روابط وصفحات موقعك بشكل جيد في محركات البحث، على سبيل المثال محرك بحث قوقل ومع أنه يفهم ويحلل أكواد جافاسكربت إلا أنه قد لا يقوم بفهرسة الإرتباطات التشعبية للصفحات وقد لا تظهر صفحات الموقع ضمن ناتج البحث وذلك لأن الهاش في الرابط لا يُعد صفحة صالحة بحد ذاتها، وينصح عوضًا عن ذلك استخدام History API، وكذلك حلول من جانب الخادم لضمان عرض الصفحة نفسها مهما تغير المسار في الرابط، بحيث تتمكن جافاسكربت من تحليل المسار بشكل صحيح، ويكون الموقع مناسب للفهرسة بواسطة محركات البحث.

مثال على إعدادات لسيرفر أباتشي يُرسل نفس الصفحة مهما تغير المسار في الرابط:

```
<IfModule mod\_rewrite.c>
 RewriteEngine On
 RewriteBase /
 RewriteRule ^index\.html$ - [L]
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule. /index.html [L]
</IfModule>

```
مثال على إعدادات لسيرفر http على NodeJS يرسل نفس الصفحة مهما تغير المسار في الرابط:

```
const http = require('http')
const fs = require('fs')
const httpPort = 80

http.createServer((req, res) => {
 fs.readFile('index.html', 'utf-8', (err, content) => {
 if (err) {
 console.log('We cannot open "index.html" file.')
 }

 res.writeHead(200, {
 'Content-Type': 'text/html; charset=utf-8'
 })

 res.end(content)
 })
}).listen(httpPort, () => {
 console.log('Server listening on: http://localhost:%s', httpPort)
})

```

مراجع
-----

1. ↑  Flanagan, David, "JavaScript - The Definitive Guide", 5th ed. *O'Reilly, Sebastopol, CA, 2006*, p.497
2. ↑  "Fixing the Back Button: SPA Behavior using Location Hash". *Falafel Software Blog* (بالإنجليزية الأمريكية). Archived from the original on 2018-06-30. Retrieved 2016-01-18.
3. ↑  "Inner-browsing extending the browser navigation paradigm - Archive of obsolete content | MDN". *developer.mozilla.org* (بالإنجليزية الأمريكية). Archived from the original on 2021-03-02. Retrieved 2021-06-23.
4. ↑  *Essential JavaScript SEO tips - JavaScript SEO*، مؤرشف من الأصل في 2021-05-20، اطلع عليه بتاريخ 2021-06-23
5. ↑  "HTML5 History Mode | Vue Router". *router.vuejs.org*. مؤرشف من الأصل في 2021-05-07. اطلع عليه بتاريخ 2021-06-23.
6. ↑  "HTML5 History Mode | Vue Router". *router.vuejs.org*. مؤرشف من الأصل في 2021-05-07. اطلع عليه بتاريخ 2021-06-23.

* أيقونة بوابةبوابة برمجيات
* أيقونة بوابةبوابة إنترنت
* أيقونة بوابةبوابة تقانة المعلومات