WebNuxt工程中,如何实现子域名绑定子路由?nuxt子域名
如你所见,当前所在的域名前缀为ask
,当您跳转到会员中心时,域名前缀变成了uni
,然而,它们其实都是同一个Nuxt
工程,不相信你可以访问 https://uni.buildadmin.com/ask 一样可以打开本社区,我们将uni.buildadmin.com/ask
简化为了ask.buildadmin.com
,这就是本贴要讲的子域名绑定子路由,建议先收藏再细看~
- 本方案纯前端代码实现,域名解析过来即可正常显示,无需配置反向代理等
- 理解实现原理后,本方案同时适用于普通的
vue
项目 - 以下示例代码,只适用于BuildAdmin的
WebNuxt
工程,且因侵入较多,无法以模块或系统内置实现,同时示例代码在你的项目中,需做出一定调整
实现原理
获取当前子域名 -> 修改路由。对的,核心原理就这么简单!
打个比方,假设我们已经有以下静态路由:
{
// 首页
path: '/',
name: '/',
component: () => import('/@/views/frontend/index.vue'),
meta: {
title: pageTitle('home'),
},
},
{
// 社区首页
path: '/ask',
name: 'ask',
component: () => import('/@/views/frontend/ask.vue'),
meta: {
title: pageTitle('ask'),
},
},
用户访问的URL为:ask.buildadmin.com,获取到前缀ask
,修改原有的静态路由/ask
改为/
即可。
实现
静态路由
在Nuxt
工程中,静态路由是由Nuxt自动分析目录结构并注册的,但是它为我们提供了app/router.options.ts
// app/router.options.ts 文件,没有请自行建立
import type { RouterOptions } from '@nuxt/schema'
// https://router.vuejs.org/api/interfaces/routeroptions.html
export default <RouterOptions>{
routes: (routes) => {
console.log(routes)
}
}
这样就拿到我们需要修改的静态路由数据了~
当前域名
我们还需要拿到当前用户访问的域名。Nuxt中,用户的请求是先到node的渲染服务器上,我们需要在此时就拿到静态路由,并完成修改,这样才能保证服务端渲染和前台激活的一致,好在,这也不难。
// 从nuxt实例内取到ssr上下文数据
// 域名是不带协议,同时有端口号的,所以我们直接以:号切割,并只取域名部分
const { ssrContext } = useNuxtApp()
const domain = ssrContext!.event.node.req.headers.host!.split(':')[0]
这种方式可以正确取到用户访问的域名,但是页面被发送给用户浏览器激活期间,值会发生改变(或丢失),所以,我们需要使用一种能够在服务端渲染后,前端激活期间能够保留变量值的方式来存储域名信息,以免到了前端,用户还是自动跳转到原本的/
路由,你想到了什么?
// 建立 stores/subDomain.ts 文件
// 用于保存完整域名
export const useNodeReqHost = () => useState<string>('nodeReqHost', () => '')
// 用于保存匹配到的子域名部分
export const useSubDomain = () => useState<string>('subDomain', () => '')
修改路由
// 回到之前建立的 app/router.options.ts 文件
import { cloneDeep } from 'lodash-es'
import type { RouterOptions } from '@nuxt/schema'
import { RouteRecordRaw } from 'vue-router'
// 定义一个可将只读属性去掉的 Writeable
type Writeable<T> = { -readonly [P in keyof T]: T[P] }
/**
* 修改路由 path,建议先看本函数之下的实现
*
* /ask => /
* /ask/info => /info
*
*/
const editPath = (routes: RouteRecordRaw[], subDomainPath: string) => {
for (const key in routes) {
if (routes[key].path.includes(subDomainPath)) {
if (routes[key].path === subDomainPath) {
routes[key].path = '/'
routes[key].name = '/'
} else {
routes[key].path = routes[key].path.replace(subDomainPath + '/', '/')
}
}
if (routes[key].children?.length) {
routes[key].children = editPath(routes[key].children!, subDomainPath)
}
}
return routes
}
export default <RouterOptions>{
routes: (routes) => {
// routes 是只读的,通过 Writeable 将其改为可写,并且进行深克隆,避免影响到原始数据(渲染->激活过程的数据可能受影响)
let routesTemp = cloneDeep(routes as Writeable<RouteRecordRaw[]>)
// 记录当前域名 - 只服务端记录,客户端直接访问就行
const nodeReqHost = useNodeReqHost()
if (process.server) {
const { ssrContext } = useNuxtApp()
nodeReqHost.value = ssrContext!.event.node.req.headers.host!.split(':')[0]
}
// 根据子域名完成路由的修改
if (nodeReqHost.value == 'ask.buildadmin.com') {
// 修改原本的首页路由
const oldIndex = getArrayKey(routesTemp, 'path', '/')
routesTemp[oldIndex].path = '/home'
routesTemp[oldIndex].name = '/home'
// 修改 /ask 路由为首页
routesTemp = editPath(routesTemp, '/ask')
// 记录下当前已经通过子域名访问
const subDomain = useSubDomain()
subDomain.value = 'ask'
}
return routesTemp
}
}
至此,通过ask.buildadmin.com
访问,已经可以自动将/ask
作为首页了~
2个回答默认排序 投票数排序
YANG001
这家伙很懒,什么也没写~
1年前
消灭0回答~
elwlb
这家伙很懒,什么也没写~
7月前
这很实用
请先登录
点赞学习了