Skip to content

11. مثال [nuxt-08]: برامج وسيطة للتوجيه

في هذا المثال، نقدم مفهوم برامج التوجيه الوسيطة، وهي نصوص برمجية يتم تنفيذها عند كل تغيير في المسار.

يتم الحصول على المثال [nuxt-08] في البداية عن طريق نسخ المشروع [nuxt-01]:

Image

يجب أن تكون برامج التوجيه الوسيطة في مجلد يسمى [middleware] [2]. قد يكون هناك توجيه على مستويين:

  • توجيه مطبق على كل عملية تنقل. ويكون هذا التوجيه موضوع إعلان في الملف [nuxt.config.js
  • توجيه مطبق على صفحة معينة، عندما تكون هذه الصفحة هي هدف التوجيه. يتم الإعلان عن هذا التوجيه في هذه الصفحة المستهدفة؛

11.1. التوجيه العام

سيتولى الملف [middleware / routing.js] التوجيه العام. ويخضع للإعلان التالي في الملف [nuxt.config.js]:


  router: {
    base: '/nuxt-08/',
    middleware: ['routing']
},

تعد برامج الوسيطة للتوجيه العام خاصية للموجه (السطر 1). قد يكون هناك العديد من برامج الوسيطة للتوجيه. ولهذا السبب، في السطر 3، تكون قيمة الخاصية [middleware] عبارة عن مصفوفة. نلاحظ أنه لا يتم استخدام مسار لتعيين البرمجيات الوسيطة. سيتم البحث عنها تلقائيًا في مجلد [middleware] الخاص بالمشروع؛

لا تقوم البرمجية الوسيطة [routing] هنا سوى بتسجيل السجلات:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // من الذي ينفذ هذا الكود؟
  console.log('[routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const routing = '[routing ' + who + ']'
  // عدد الحجج
  console.log(routing + ', il y a', args.length, 'argument(s)')

  // الحجة الأولى
  const context = args[0]
  // مفاتيح السياق
  dumpkeys(routing + ', context', context)
  // التطبيق
  dumpkeys(routing + ', context.app', context.app)
  // الطريق
  dumpkeys(routing + ', context.route', context.route)
  console.log(routing + ', context.route=', context.route)
  // الموجه
  dumpkeys(routing + ', context.app.router', context.app.router)
  // router.options.routes
  dumpkeys(routing + ', context.app.router.options.routes', context.app.router.options.routes)
  console.log(routing + ', context.app.router.options.routes=', context.app.router.options.routes)
}

function dumpkeys(message, object) {
  // قائمة مفاتيح [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // قائمة المفاتيح
  if (object) {
    console.log(Object.keys(object))
  }
}
  • السطر 3: سنكتشف أن البرمجية الوسيطة تتلقى حجة: سياق المنفذ (الخادم أو العميل)؛
  • الأسطر 4-25: نعرض خصائص كائنات مختلفة لمعرفة ما هو قابل للاستخدام. سنكتشف أن سياق البرمجيات الوسيطة مطابق تقريبًا لسياق المكون الإضافي؛

11.2. التوجيه لصفحة معينة

نريد التحكم في الطريقة التي نصل بها إلى الصفحة [index]. للقيام بذلك، نحتاج إلى إدخال الخاصية [middleware] في هذه الصفحة [index]:


<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Home',
  // المكونات المستخدمة
  components: {
    Layout,
    Navigation
  },
  // دورة الحياة
  beforeCreate() {
    // العميل والخادم
    console.log('[home beforeCreate]')
  },
  created() {
    // العميل والخادم
    console.log('[home created]')
  },
  beforeMount() {
    // العميل فقط
    console.log('[home beforeMount]')
  },
  mounted() {
    // العميل فقط
    console.log('[home mounted]')
  },
  // التوجيه
  middleware: ['index-routing']
}
</script>
  • السطر 34: تسرد الخاصية [middleware] البرامج النصية التي يجب تنفيذها في كل مرة يتم فيها عرض الصفحة التالية وهي الصفحة [index]. وهنا أيضًا، سيتم البحث عن هذه البرامج النصية في المجلد [middleware] الخاص بالمشروع؛

البرنامج الوسيط [index-routing] هو التالي:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // من الذي ينفذ هذا الكود؟
  console.log('[index-routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const indexRouting = '[index-routing ' + who + ']'
  // عدد الحجج
  console.log(indexRouting + ', il y a', args.length, 'argument(s)')

  // الحجة الأولى
  const context = args[0]
  // مفاتيح السياق
  dumpkeys(indexRouting + ', context', context)
  // التطبيق
  dumpkeys(indexRouting + ', context.app', context.app)
  // المسار
  dumpkeys(indexRouting + ', context.route', context.route)
  console.log(indexRouting + ', context.route=', context.route)
  // الموجه
  dumpkeys(indexRouting + ', context.app.router', context.app.router)
  // router.options.routes
  dumpkeys(indexRouting + ', context.app.router.options.routes', context.app.router.options.routes)
  console.log(indexRouting + ', context.app.router.options.routes=', context.app.router.options.routes)
  // من أين أتينا؟
  if (context.from) {
    console.log('from=', context.from)
  }
}

function dumpkeys(message, object) {
  // قائمة مفاتيح [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // قائمة المفاتيح
  if (object) {
    console.log(Object.keys(object))
  }
}

رمز [index-routing] مطابق لرمز [routing] ويُنتج نفس النتائج. ما يهمنا هو معرفة متى يتم تنفيذ هذين البرنامجين الوسيطين.

11.3. تنفيذ المشروع

نقوم بتنفيذ المشروع. وتكون السجلات كما يلي:

يتم تنفيذ البرنامج النصي [routing] أولاً بواسطة الخادم:

[routing], process.server= true process.client= false
[routing server], il y a 1 argument(s)
Liste des clés [[routing server], context]
[ 'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios' ]
Liste des clés [[routing server], context.app]
[ 'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
   '$axios' ]
Liste des clés [[routing server], context.route]
[ 'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
  'matched' ]
[routing server], context.route= { name: 'index',
  meta: [ {} ],
  path: '/',
  hash: '',
  query: {},
  params: {},
  fullPath: '/',
  matched:
   [ { path: '',
       regex: /^(?:\/(?=$))?$/i,
       components: [Object],
       instances: {},
       name: 'index',
       parent: undefined,
       matchAs: undefined,
       redirect: undefined,
       beforeEnter: undefined,
       meta: {},
       props: {} } ] }
Liste des clés [[routing server], context.app.router]
[ 'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
  'history' ]
Liste des clés [[routing server], context.app.router.options.routes]
[ '0', '1', '2' ]
[routing server], context.app.router.options.routes= [ { path: '/page1',
    component: [Function: _61cefe10],
    name: 'page1' },
  { path: '/page2',
    component: [Function: _61dd1591],
    name: 'page2' },
  { path: '/', component: [Function: _00d5e140], name: 'index' } ]

نجد هنا ما حصلنا عليه مع المكونات الإضافية.

  • السطر 15: غالبًا ما تُستخدم الخاصية [redirect] في برامج الوسيطة: فهي تسمح بتغيير هدف التوجيه الحالي؛

ثم، نظرًا لأن الصفحة التي سيتم عرضها هي الصفحة [index]، يقوم الخادم بتنفيذ البرنامج النصي [index-routing] ويعرض السجلات التالية:

[index-routing], process.server= true process.client= false
[index-routing server], il y a 1 argument(s)
Liste des clés [[index-routing server], context]
[ 'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios' ]
Liste des clés [[index-routing server], context.app]
[ 'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
   '$axios' ]
Liste des clés [[index-routing server], context.route]
[ 'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
  'matched' ]
[index-routing server], context.route= { name: 'index',
  meta: [ {} ],
  path: '/',
  hash: '',
  query: {},
  params: {},
  fullPath: '/',
  matched:
   [ { path: '',
       regex: /^(?:\/(?=$))?$/i,
       components: [Object],
       instances: {},
       name: 'index',
       parent: undefined,
       matchAs: undefined,
       redirect: undefined,
       beforeEnter: undefined,
       meta: {},
       props: {} } ] }
Liste des clés [[index-routing server], context.app.router]
[ 'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
  'history' ]
Liste des clés [[index-routing server], context.app.router.options.routes]
[ '0', '1', '2' ]
[index-routing server], context.app.router.options.routes= [ { path: '/page1',
    component: [Function: _61cefe10],
    name: 'page1' },
  { path: '/page2',
    component: [Function: _61dd1591],
    name: 'page2' },
  { path: '/', component: [Function: _00d5e140], name: 'index' } ]

النتائج التي تم الحصول عليها باستخدام البرنامج النصي [index-routing] مماثلة لتلك التي تم الحصول عليها باستخدام البرنامج النصي [routing].

بمجرد استلام المتصفح العميل للصفحة [index]، تتولى البرامج النصية للعميل زمام الأمور. وتصبح السجلات كما يلي:

1
2
3
4
[home beforeCreate]
[home created]
[home beforeMount]
[home mounted]

من الواضح إذن أن العميل لا يقوم بتنفيذ أي برامج وسيطة عند بدء تشغيل التطبيق. وهذا يعني أن ذلك سيحدث في كل مرة يقوم فيها المستخدم بإجبار الخادم على الاستجابة. ولا يتم تنفيذ البرامج الوسيطة من قِبل العميل إلا أثناء التنقل داخل التطبيق. لننتقل على سبيل المثال إلى الصفحة [page1] (نحن الآن على الصفحة [index]) باستخدام الرابط [Page 1]. تكون السجلات عندئذٍ كما يلي:

[routing], process.server= false process.client= true
[routing client], il y a 1 argument(s)
Liste des clés [[routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[routing client], context.route= {name: "page1", meta: Array(1), path: "/page1", hash: "", query: {}, }
Liste des clés [[routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
[page1 beforeCreate]
[page1 created]
[page1 beforeMount]
[page1 mounted]
  • السطر 2: يتم تنفيذ البرمجيات الوسيطة [routing] بواسطة العميل؛
  • السطر 4: لاحظ الخاصية [from]: هذا هو المسار الذي أتينا منه؛
  • السطر 9: [context.route] هو المسار الذي نتجه إليه؛
  • الأسطر 15-18: عرض الصفحة [page1

الآن لنعد إلى الصفحة [index] باستخدام الرابط [Home]. تكون السجلات عندئذٍ كما يلي:

[routing], process.server= false process.client= true
[routing client], il y a 1 argument(s)
Liste des clés [[routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[routing client], context.route= {name: "index", meta: Array(1), path: "/", hash: "", query: {}, }
Liste des clés [[routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
[index-routing], process.server= false process.client= true
[index-routing client], il y a 1 argument(s)
Liste des clés [[index-routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[index-routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[index-routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[index-routing client], context.route= {name: "index", meta: Array(1), path: "/", hash: "", query: {}, }
Liste des clés [[index-routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[index-routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[index-routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
from= {name: "page1", meta: Array(1), path: "/page1", hash: "", query: {}, }
[home beforeCreate]
[home created]
[home beforeMount]
[home mounted]
  • الأسطر 1-15: يقوم العميل بتنفيذ البرمجيات الوسيطة [routing]. وهذا أمر طبيعي. يتم تنفيذه عند كل تغيير في المسار؛
  • الأسطر 16-29: يقوم العميل بتنفيذ البرنامج الوسيط [index-routing]، وذلك لأن:
    • [index] هي هدف المسار الحالي (انظر السطر 23)؛
    • الصفحة [index] قد حددت برنامج وسيط، باسم [index-routing

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