كتابة موجه JavaScript حديث

يوم جيد يا اصدقاء!

تحيط بنا تطبيقات بسيطة من صفحة واحدة تستند إلى React أو Vue أو JavaScript خالص في كل مكان. "صفحة واحدة" جيدة تفترض آلية توجيه مناسبة.

إن المكتبات مثل "navigo" أو "response-router" مفيدة جدًا. ولكن كيف تعمل؟ هل نحن بحاجة إلى استيراد المكتبة بأكملها؟ أم أنها تكفي لجزء ما ، على سبيل المثال ، 10٪؟ في الواقع ، يمكنك بسهولة كتابة جهاز توجيه سريع ومفيد بنفسك ، وسوف يستغرق الأمر بعض الوقت ، وسيتألف البرنامج من أقل من 100 سطر من التعليمات البرمجية.

المتطلبات


يجب أن يكون جهاز التوجيه الخاص بنا:

  • مكتوب في ES6 +
  • متوافق مع التاريخ والتجزئة
  • مكتبة قابلة لإعادة الاستخدام

عادةً ما يستخدم تطبيق الويب مثيلًا واحدًا من جهاز التوجيه ، ولكن في كثير من الحالات نحتاج إلى عدة حالات ، لذلك لن نتمكن من استخدام Singleton كقالب. للعمل ، يتطلب جهاز التوجيه الخاص بنا الخصائص التالية:

  • الموجهات: قائمة الموجهات المسجلة
  • الوضع: التجزئة أو التاريخ
  • العنصر الجذر: العنصر الجذر للتطبيق ، إذا كنا في وضع استخدام التاريخ
  • المُنشئ: الوظيفة الرئيسية لإنشاء مثيل جهاز توجيه جديد

class Router {
    routes = []
    mode = null
    root = '/'

    constructor(options) {
        this.mode = window.history.pushState ? 'history' : 'hash'
        if (options.mode) this.mode = options.mode
        if (options.root) this.root = options.root
    }
}

export default Router

إضافة وإزالة أجهزة التوجيه


تتم إضافة أجهزة التوجيه وإزالتها عن طريق إضافة عناصر الصفيف وإزالتها:

class Router {
    routes = []
    mode = null
    root = '/'

    constructor(options) {
        this.mode = window.history.pushState ? 'history' : 'hash'
        if (options.mode) this.mode = options.mode
        if (options.root) this.root = options.root
    }

    add = (path, cb) => {
        this.routes.push({
            path,
            cb
        })
        return this
    }

    remove = path => {
        for (let i = 0; i < this.routes.length; i += 1) {
            if (this.routes[i].path === path) {
                this.routes.slice(i, 1)
                return this
            }
        }
        return this
    }

    flush = () => {
        this.routes = []
        return this
    }
}

export default Router

الحصول على المسار الحالي


نحتاج إلى معرفة مكاننا في التطبيق في وقت معين.

لهذا ، نحن بحاجة إلى معالجة كلا الوضعين (التاريخ والتجزئة). في الحالة الأولى ، نحتاج إلى إزالة المسار إلى العنصر الجذر من window.location ، في الحالة الثانية - "#". نحتاج أيضًا إلى وظيفة (clearSlash) لإزالة جميع أجهزة التوجيه (الخطوط من البداية إلى النهاية):

[...]

    clearSlashes = path =>
        path
        .toString()
        .replace(/\/$/, '')
        .replace(/^\//, '')

    getFragment = () => {
        let fragment = ''

        if (this.mode === 'history') {
            fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search))
            fragment = fragment.replace(/\?(.*)$/, '')
            fragment = this.root !== '/' ? fragment.replace(this.root, '') : fragment
        } else {
            const match = window.location.href.match(/#(.*)$/)
            fragment = match ? match[1] : ''
        }
        return this.clearSlashes(fragment)
    }
}

export default Router

التنقل


حسنًا ، لدينا واجهة برمجة تطبيقات لإضافة عناوين URL وإزالتها. لدينا أيضًا فرصة للحصول على العنوان الحالي. الخطوة التالية هي التنقل في جهاز التوجيه. نحن نعمل مع خاصية "الوضع":

[...]

    getFragment = () => {
        let fragment = ''

        if (this.mode === 'history') {
            fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search))
            fragment = fragment.replace(/\?(.*)$/, '')
            fragment = this.root !== '/' ? fragment.replace(this.root, '') : fragment
        } else {
            const match = window.location.href.match(/#(.*)$/)
            fragment = match ? match[1] : ''
        }
        return this.clearSlashes(fragment)
    }

    navigate = (path = '') => {
        if (this.mode === 'history') {
            window.history.pushState(null, null, this.root + this.clearSlashes(path))
        } else {
            window.location.href = `${window.location.href.replace(/#(.*)$/, '')}#${path}`
        }
        return this
    }
}

export default Router

مشاهدة التغييرات


نحتاج الآن إلى منطق لتتبع تغييرات العنوان ، إما باستخدام رابط أو باستخدام طريقة "التنقل" التي أنشأناها. نحتاج أيضًا إلى التأكد من عرض الصفحة الصحيحة في الزيارة الأولى. يمكننا استخدام حالة التطبيق لتسجيل التغييرات ، ومع ذلك ، لغرض الدراسة ، سنقوم بذلك باستخدام setInterval:

class Router {
    routes = [];
    mode = null;
    root = "/";

    constructor(options) {
        this.mode = window.history.pushState ? "history" : "hash";
        if (options.mode) this.mode = options.mode;
        if (options.root) this.root = options.root;

        this.listen();
    }

    [...]

    listen = () => {
        clearInterval(this.interval)
        this.interval = setInterval(this.interval, 50)
    }

    interval = () => {
        if (this.current === this.getFragment()) return
        this.current = this.getFragment()

        this.routes.some(route => {
            const match = this.current.match(route.path)

            if (match) {
                match.shift()
                route.cb.apply({}, match)
                return match
            }
            return false
        })
    }
}

export default Router

استنتاج


مكتبتنا جاهزة للاستخدام. يتكون من 84 سطرًا فقط من التعليمات البرمجية!

رمز ومثال على جيثب .

شكرآ لك على أهتمامك.

All Articles