Route Matching Syntax | Vue Router - Advanced URL Patterns ๐ฏ โ
Powerful URL pattern matching - Create flexible, dynamic routes with advanced matching capabilities!
๐ฏ Overview โ
Vue Router's route matching syntax provides powerful tools for defining URL patterns that can handle complex routing scenarios. From simple parameter matching to advanced regex patterns, these features enable you to create robust and flexible routing systems.
๐ Key Benefits โ
- Flexible URL Patterns: Handle various URL structures
- Parameter Validation: Ensure route parameters meet specific criteria
- Complex Routing: Support advanced application requirements
- Clean URL Design: Create user-friendly and SEO-optimized URLs
๐ก When to Use Advanced Matching โ
๐ง Complex Application Requirements โ
Dynamic Content Systems
- CMS with flexible content URLs
- E-commerce with complex product hierarchies
- Multi-tenant applications with custom URL patterns
API and Data-Driven Routes
- RESTful API URL patterns
- Data validation through route parameters
- Complex filtering and search systems
๐ง Basic Parameter Matching โ
const routes = [
// Basic parameter
{
path: '/user/:userId',
component: UserProfile
},
// Optional parameter
{
path: '/product/:productId?',
component: ProductDetail
},
// Multiple parameters
{
path: '/category/:categoryId/product/:productId',
component: ProductPage
}
]๐ Basic Configuration โ
Parameter Modifiers โ
const routes = [
// Required parameter (default)
{
path: '/user/:userId',
component: UserProfile
},
// Optional parameter with ?
{
path: '/search/:query?',
component: SearchResults
},
// Zero or more parameters with *
{
path: '/files/*',
component: FileBrowser
},
// One or more parameters with +
{
path: '/blog/:year/:month+',
component: BlogArchive
}
]Custom Regex Patterns โ
const routes = [
// Numeric ID validation
{
path: '/user/:userId(\\d+)',
component: UserProfile
},
// Slug pattern validation
{
path: '/article/:slug([a-z0-9-]+)',
component: ArticleDetail
},
// Complex pattern matching
{
path: '/date/:year(\\d{4})/:month(\\d{2})/:day(\\d{2})',
component: DatePage
}
]๐ง Advanced Techniques โ
Example 1: E-commerce URL Pattern System โ
// router/ecommerce.js
const ecommerceRoutes = [
// Product hierarchy with validation
{
path: '/:categorySlug([a-z-]+)/:productSlug([a-z0-9-]+)',
component: ProductDetail,
props: route => ({
categorySlug: route.params.categorySlug,
productSlug: route.params.productSlug,
variant: route.query.variant || 'default'
})
},
// Category browsing with filters
{
path: '/:categorySlug([a-z-]+)',
component: CategoryPage,
props: route => ({
categorySlug: route.params.categorySlug,
// Parse filter parameters from query
filters: parseCategoryFilters(route.query),
sort: route.query.sort || 'popular',
page: parseInt(route.query.page) || 1
})
},
// Search with complex pattern
{
path: '/search/:query(.+)', // Match everything after /search/
component: SearchResults,
props: route => ({
query: decodeURIComponent(route.params.query),
// Additional search parameters
category: route.query.category,
priceRange: parsePriceRange(route.query.price),
inStock: route.query.stock !== 'false'
})
},
// Brand and product combination
{
path: '/brand/:brandSlug([a-z-]+)/:productSlug([a-z0-9-]+)',
component: BrandProductDetail,
props: true
}
]
function parseCategoryFilters(query) {
const filters = {}
if (query.price_min) filters.priceMin = parseFloat(query.price_min)
if (query.price_max) filters.priceMax = parseFloat(query.price_max)
if (query.brand) filters.brands = Array.isArray(query.brand) ? query.brand : [query.brand]
if (query.color) filters.colors = Array.isArray(query.color) ? query.color : [query.color]
return filters
}
function parsePriceRange(priceString) {
if (!priceString) return null
const [min, max] = priceString.split('-').map(Number)
return { min, max }
}Example 2: CMS with Flexible Content URLs โ
// router/cms.js
const cmsRoutes = [
// Basic content pages
{
path: '/:contentType(pages|articles|news)/:slug([a-z0-9-]+)',
component: ContentPage,
props: route => ({
contentType: route.params.contentType,
slug: route.params.slug,
// Additional content parameters
version: route.query.v || 'published',
language: route.query.lang || 'en'
})
},
// Hierarchical content structure
{
path: '/:section([a-z-]+)/:subsection([a-z-]+)/:contentSlug([a-z0-9-]+)',
component: HierarchicalContent,
props: route => ({
section: route.params.section,
subsection: route.params.subsection,
contentSlug: route.params.contentSlug,
breadcrumb: generateBreadcrumb(route.params)
})
},
// Archive pages with date patterns
{
path: '/archive/:year(\\d{4})/:month(\\d{2})?/:day(\\d{2})?',
component: ArchivePage,
props: route => ({
year: parseInt(route.params.year),
month: route.params.month ? parseInt(route.params.month) : null,
day: route.params.day ? parseInt(route.params.day) : null,
// Archive type detection
archiveType: route.params.day ? 'daily' :
route.params.month ? 'monthly' : 'yearly'
})
},
// Tag and category filtering
{
path: '/:contentType(posts|articles)/tag/:tagSlug([a-z-]+)',
component: TagPage,
props: route => ({
contentType: route.params.contentType,
tagSlug: route.params.tagSlug,
sort: route.query.sort || 'recent',
page: parseInt(route.query.page) || 1
})
}
]
function generateBreadcrumb(params) {
const breadcrumb = []
if (params.section) breadcrumb.push({ name: params.section, path: `/${params.section}` })
if (params.subsection) breadcrumb.push({
name: params.subsection,
path: `/${params.section}/${params.subsection}`
})
return breadcrumb
}๐ ๏ธ Practical Examples โ
Example 3: Multi-Tenant Application with Custom Domains โ
// router/multi-tenant.js
const multiTenantRoutes = [
// Tenant-specific URL patterns
{
path: '/:tenantSlug([a-z0-9-]+)/:pageType(pages|products|services)/:itemSlug([a-z0-9-]+)',
component: TenantItemPage,
props: route => ({
tenantSlug: route.params.tenantSlug,
pageType: route.params.pageType,
itemSlug: route.params.itemSlug,
// Tenant context
tenant: getTenantBySlug(route.params.tenantSlug),
// Item context
item: getItemBySlug(route.params.tenantSlug, route.params.itemSlug)
})
},
// Tenant category structure
{
path: '/:tenantSlug([a-z0-9-]+)/category/:categoryPath(.+)',
component: TenantCategoryPage,
props: route => {
const categoryPath = route.params.categoryPath.split('/')
return {
tenantSlug: route.params.tenantSlug,
categoryPath,
// Current category is the last segment
currentCategory: categoryPath[categoryPath.length - 1],
// Parent categories
parentCategories: categoryPath.slice(0, -1),
// Filter parameters
filters: parseTenantFilters(route.query)
}
}
},
// Tenant search with complex patterns
{
path: '/:tenantSlug([a-z0-9-]+)/search/:searchQuery(.+)?',
component: TenantSearchResults,
props: route => ({
tenantSlug: route.params.tenantSlug,
searchQuery: route.params.searchQuery ?
decodeURIComponent(route.params.searchQuery) : '',
// Search parameters
searchType: route.query.type || 'all',
sort: route.query.sort || 'relevance',
page: parseInt(route.query.page) || 1,
// Advanced search options
advanced: parseAdvancedSearch(route.query)
})
}
]
function parseTenantFilters(query) {
const filters = {}
// Parse tenant-specific filter structure
Object.keys(query).forEach(key => {
if (key.startsWith('filter_')) {
const filterName = key.replace('filter_', '')
filters[filterName] = Array.isArray(query[key]) ? query[key] : [query[key]]
}
})
return filters
}
function parseAdvancedSearch(query) {
return {
includeDescription: query.include_desc !== 'false',
matchAllTerms: query.match_all === 'true',
searchTitlesOnly: query.titles_only === 'true'
}
}Example 4: API Documentation with Versioning โ
// router/api-docs.js
const apiDocRoutes = [
// Versioned API documentation
{
path: '/api/:version(v\\d+\\.\\d+)/:resourceType(endpoints|models|errors)/:resourceName([a-zA-Z0-9-]+)',
component: ApiResourcePage,
props: route => ({
version: route.params.version,
resourceType: route.params.resourceType,
resourceName: route.params.resourceName,
// API context
apiVersion: parseApiVersion(route.params.version),
// Resource context
resource: getApiResource(route.params.version, route.params.resourceType, route.params.resourceName),
// Documentation settings
showExamples: route.query.examples !== 'false',
showSchema: route.query.schema !== 'false'
})
},
// API method-specific routes
{
path: '/api/:version(v\\d+\\.\\d+)/endpoints/:endpointName([a-zA-Z0-9-]+)/:httpMethod(GET|POST|PUT|DELETE|PATCH)',
component: ApiMethodPage,
props: route => ({
version: route.params.version,
endpointName: route.params.endpointName,
httpMethod: route.params.httpMethod,
// Method details
method: getApiMethod(route.params.version, route.params.endpointName, route.params.httpMethod),
// Request/response examples
exampleType: route.query.example || 'basic',
language: route.query.lang || 'javascript'
})
},
// API search and navigation
{
path: '/api/:version(v\\d+\\.\\d+)?/search/:searchTerm(.+)?',
component: ApiSearchPage,
props: route => ({
version: route.params.version || 'latest',
searchTerm: route.params.searchTerm ?
decodeURIComponent(route.params.searchTerm) : '',
// Search options
searchIn: route.query.in ? route.query.in.split(',') : ['endpoints', 'models'],
matchCase: route.query.case === 'true',
// Pagination
page: parseInt(route.query.page) || 1,
resultsPerPage: parseInt(route.query.limit) || 20
})
}
]
function parseApiVersion(versionString) {
const match = versionString.match(/v(\d+)\.(\d+)/)
return match ? { major: parseInt(match[1]), minor: parseInt(match[2]) } : null
}๐ Advanced Patterns โ
Nested Parameter Validation โ
const routes = [
{
path: '/:entityType(users|products|orders)/:entityId(\\d+)/:action(edit|view|delete)',
component: EntityActionPage,
props: route => ({
entityType: route.params.entityType,
entityId: parseInt(route.params.entityId),
action: route.params.action,
// Additional validation
isValidAction: validateEntityAction(route.params.entityType, route.params.action)
})
}
]
function validateEntityAction(entityType, action) {
const validActions = {
users: ['edit', 'view'],
products: ['edit', 'view', 'delete'],
orders: ['view']
}
return validActions[entityType]?.includes(action) || false
}Dynamic Route Generation โ
function generateDynamicRoutes(contentTypes) {
return contentTypes.map(type => ({
path: `/${type.slug}/:itemSlug([a-z0-9-]+)`,
component: DynamicContentPage,
props: route => ({
contentType: type,
itemSlug: route.params.itemSlug,
// Dynamic content loading
content: loadContent(type.slug, route.params.itemSlug)
})
}))
}๐ Best Practices โ
โ Do โ
- Use Descriptive Parameter Names: Make routes self-documenting
- Validate Important Parameters: Use regex for critical data
- Keep Patterns Simple: Avoid overly complex regex
- Test Edge Cases: Ensure patterns handle various inputs
- Document Complex Patterns: Comment intricate route definitions
โ Don't โ
- Overuse Complex Regex: Keep patterns maintainable
- Ignore Performance: Complex patterns can impact routing performance
- Forget URL Encoding: Handle special characters properly
- Create Ambiguous Patterns: Avoid overlapping route patterns
๐ Related Features โ
- Route Parameters: Basic parameter functionality
- Route Props: Passing parameters as component props
- Navigation Guards: Additional route validation
- Route Meta Fields: Storing route-specific information
๐ก Pro Tip
Combine route matching syntax with Vue Router's navigation guards to create sophisticated validation systems that can handle complex business logic and ensure data integrity throughout your application!
Ready for advanced URL patterns? Start implementing powerful route matching syntax to create flexible, robust routing systems that can handle even the most complex application requirements! ๐ฏ