浏览代码

add $router.is method to check if the route matches the current location

Shaun Li 2 年之前
父节点
当前提交
0b1baf982d
共有 3 个文件被更改,包括 48 次插入12 次删除
  1. 4 0
      README.md
  2. 1 1
      package.json
  3. 43 11
      src/index.js

+ 4 - 0
README.md

@@ -252,6 +252,10 @@ Declare routes by creating a template tag with `x-route` attribute.
 <body x-data x-init="$router.config({ mode: 'hash', base: '/prefix/' })">...</body>
 <!-- Do nothing by default to mode 'web' with no prefix -->
 <body x-data>...</body>
+
+<!-- Check if the route matches the current location -->
+<div x-show="$router.is('/path/to/route')">You can see me</div>
+<template x-if="$router.is('/path/to/route')">You can see me</template>
 ```
 
 ## License

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "@shaun/alpinejs-router",
-  "version": "1.1.2",
+  "version": "1.1.3",
   "description": "Easy to use and flexible router for Alpine.js",
   "main": "dist/module.cjs.js",
   "module": "dist/module.esm.js",

+ 43 - 11
src/index.js

@@ -9,6 +9,10 @@ export default function (Alpine) {
     loading: false
   })
 
+  const route = Alpine.reactive({
+    patterns: {}
+  })
+
   const router = {
     get path () {
       return state.path
@@ -40,6 +44,30 @@ export default function (Alpine) {
         ...Object.fromEntries(new URLSearchParams(r || '').entries()),
         ...query
       }).toString()
+    },
+
+    is (...paths) {
+      const url = new URL(state.href)
+      const [pathname,] = (state.mode === 'hash')
+        ? url.hash.slice(1).split('?')
+        : [url.pathname.replace(state.base, ''),]
+
+      for (const path of paths) {
+        if (path === 'notfound') {
+          return Object.entries(route.patterns).findIndex(e => e[1] instanceof RegExp ? pathname.match(e[1]) : pathname === e[1]) === -1
+        }
+        const pattern = route.patterns[path]
+        if (pattern === undefined) continue
+
+        if (pattern instanceof RegExp && pattern.test(pathname)) {
+          return true
+        }
+        if (pattern === pathname) {
+          return true
+        }
+      }
+
+      return false
     }
   }
 
@@ -88,26 +116,26 @@ export default function (Alpine) {
     return pattern.indexOf('(?') > -1 ? new RegExp(`^${pattern}$`) : pattern
   }
 
-  const routePatterns = {}
   const templateCaches = {}
-  const inProgress = {}
+  const inLoadProgress = {}
+  const inMakeProgress = new Set()
 
   Alpine.directive('route', (el, { modifiers, expression }, { effect, cleanup }) => {
     if (!modifiers.includes('notfound')) {
-      routePatterns[expression] = buildPattern(expression)
+      route.patterns = { ...route.patterns, [expression]: buildPattern(expression) }
     }
 
     const load = url => {
-      if (inProgress[url]) {
-        inProgress[url].then(html => el.innerHTML = html)
+      if (inLoadProgress[url]) {
+        inLoadProgress[url].then(html => el.innerHTML = html)
       } else {
-        inProgress[url] = fetch(url).then(r => r.text()).then(html => {
+        inLoadProgress[url] = fetch(url).then(r => r.text()).then(html => {
           templateCaches[url] = html
           el.innerHTML = html
           return html
         })
       }
-      return inProgress[url]
+      return inLoadProgress[url]
     }
 
     let loading
@@ -120,6 +148,9 @@ export default function (Alpine) {
       if (el._x_currentIfEl) return el._x_currentIfEl
 
       const make = () => {
+        if (inMakeProgress.has(expression)) return
+        inMakeProgress.add(expression)
+
         const clone = el.content.cloneNode(true).firstElementChild
 
         Alpine.addScopeToNode(clone, {}, el)
@@ -136,6 +167,8 @@ export default function (Alpine) {
 
           delete el._x_currentIfEl
         }
+
+        Alpine.nextTick(() => inMakeProgress.delete(expression))
       }
 
       if (el.content.firstElementChild) {
@@ -167,14 +200,13 @@ export default function (Alpine) {
 
     effect(() => {
       const url = new URL(state.href)
-
-      let [pathname, search] = (state.mode === 'hash')
+      const [pathname, search] = (state.mode === 'hash')
         ? url.hash.slice(1).split('?')
         : [url.pathname.replace(state.base, ''), url.search]
 
       if (modifiers.includes('notfound')) {
         // console.time('404')
-        Object.entries(routePatterns).find(e => e[1] instanceof RegExp ? pathname.match(e[1]) : pathname === e[1])
+        Object.entries(route.patterns).findIndex(e => e[1] instanceof RegExp ? pathname.match(e[1]) : pathname === e[1]) > -1
           ? hide()
           : show()
         // console.timeEnd('404')
@@ -182,7 +214,7 @@ export default function (Alpine) {
       }
 
       // console.time('route')
-      const pattern = routePatterns[expression]
+      const pattern = route.patterns[expression]
       if (pattern instanceof RegExp) {
         const m = pathname.match(pattern)
         if (m) {