Javascript 全局混合多次激发-Vue
我使用Javascript 全局混合多次激发-Vue,javascript,typescript,vue.js,Javascript,Typescript,Vue.js,我使用document.title和全局mixin创建了一个mixin来更改页面标题 我的混音文件(title.ts): 然后我在main.ts中全局注册了这个mixin: import titleMixin from '@/mixins/title' Vue.mixin(titleMixin) 然后在Vue组件中设置标题: @Component export default class Login extends Vue { public title: string = 'New tit
document.title
和全局mixin创建了一个mixin来更改页面标题
我的混音文件(title.ts):
然后我在main.ts中全局注册了这个mixin:
import titleMixin from '@/mixins/title'
Vue.mixin(titleMixin)
然后在Vue组件中设置标题:
@Component
export default class Login extends Vue {
public title: string = 'New title'
}
我的项目中有5个组件,如果我在mixin中使用console.log
,我可以看到它在每个组件中一步一步地启动,因此document.title
由最后一个组件created()
hook设置
如何正确设置当前页面的标题?您应该只在页面的父组件(保存所有页面本身的组件)中使用mixin 使用
vue属性装饰器时,应采用以下方式:
import { Vue, Component, Mixins } from 'vue-property-decorator';
@Component
export default class Login extends Mixins(titleMixin) {
public title: string = 'New title'
}
并且不要使用Vue.mixin(titleMixin)
全局导入它。通过这种方式,它将为所有组件导入。正如您所说,全局混合将影响Vue应用程序中的每个组件,这意味着设置文档的逻辑。title
将在应用程序中每个组件的创建的钩子中触发
我认为您需要的是VueRouter的beforeRouteEnter
hook,它是库提供给您的任何组件的。组件的beforeRouteEnter
钩子在路由更改为与其关联的路由之前立即触发
在您的情况下,它将如下所示:
@Component
export default class TitleMixin extends Vue {
public beforeRouteEnter(to, from, next): void {
next(vm => {
const title: string = getTitle(vm)
if (title) {
document.title = title
}
})
}
}
您会注意到,next
函数(需要调用该函数才能解析路由)被传递一个回调,该回调包含对组件实例(vm
)的引用,我们将其传递给getTitle
,而不是this
。这是必需的,因为beforeRouteEnter
钩子没有对此
的引用。您可以阅读我链接到的文档以了解更多信息。不要创建全局混合,请尝试使用
首先,我们将首先向/router/routes.ts
文件中的每个RouteConfig
添加一个元字段:
import { RouteConfig } from 'vue-router'
export default [
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: 'login-view' */ '@views/Login.vue'),
meta: {
title: 'Login', // Set the view title
},
},
// ... Add the title meta field to each `RouteConfig`
] as RouteConfig[]
import Vue from 'vue'
import Router, { Route } from 'vue-router'
import routes from './routes'
Vue.use(Router)
const router = new Router({
// ... RouterOptions
})
// Before each route resolves...
// Resolve guards will be called right before the navigation is confirmed,
// after all in-component guards and async route components are resolved.
router.beforeResolve((routeTo, routeFrom, next) => {
const documentTitle = getRouteTitle(routeTo)
// If the `Route` being navigated to has a meta property and a title meta field,
// change the document title
if (documentTitle ) {
document.title = documentTitle
}
// Call `next` to continue...
next()
function getRouteTitle(route: Route): string {
const title: string = route.meta && route.meta.title
if (title) {
return `${title} | site.com`
}
return 'Admin panel | site.com'
}
})
export default router
然后,我们将在/router/index.ts
文件中创建一个全局解析卫士,将标题元字段设置为文档标题:
import { RouteConfig } from 'vue-router'
export default [
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: 'login-view' */ '@views/Login.vue'),
meta: {
title: 'Login', // Set the view title
},
},
// ... Add the title meta field to each `RouteConfig`
] as RouteConfig[]
import Vue from 'vue'
import Router, { Route } from 'vue-router'
import routes from './routes'
Vue.use(Router)
const router = new Router({
// ... RouterOptions
})
// Before each route resolves...
// Resolve guards will be called right before the navigation is confirmed,
// after all in-component guards and async route components are resolved.
router.beforeResolve((routeTo, routeFrom, next) => {
const documentTitle = getRouteTitle(routeTo)
// If the `Route` being navigated to has a meta property and a title meta field,
// change the document title
if (documentTitle ) {
document.title = documentTitle
}
// Call `next` to continue...
next()
function getRouteTitle(route: Route): string {
const title: string = route.meta && route.meta.title
if (title) {
return `${title} | site.com`
}
return 'Admin panel | site.com'
}
})
export default router
关于您的问题,您应该看一看,很可能您并不是懒散地加载视图,因此在每个视图中调用创建的生命周期挂钩,这就是为什么最后一个要设置document.title
。试着用挂载的
钩子代替。@Ricky,问题是,我实际上在项目中使用了延迟加载:组件:()=>导入('@/views/Login.vue')
。我仍然不明白,为什么created()
会为每个组件触发,而不是只为当前组件触发?顺便说一下,你是对的,在mounted()
中,它只发射了一次。再次阅读生命周期。我需要在所有组件中导入它,这就是为什么我在主文件中使用Vue.mixin()
。正如@ricky指出的,问题在于created()
hook,即使使用惰性加载,它似乎也会被触发。您的变体也是可行的,但它涉及到一个组件。registerHooks
在类中使用beforeRouterner
,因此在我的例子中它更多的是不必要的代码:D您能解释一下,为什么我的例子中每个组件都会触发created()
,是的,无论组件是否延迟加载,在创建组件时总是触发created
钩子。问题在于,您正在使用全局mixin来指定在创建应用程序中的每个组件时,它应该运行您的逻辑来设置文档标题。我希望@ricky建议使用mounted
也会面临同样的问题,尽管我不确定您是如何初始化路由器视图的。实际上mounted()
只触发了一次。我的路由器是Vue CLI 3 generator的标准配置。有什么想法吗?你可以在一个干净的项目上测试自己,如果你使用全局混合和created()
生命周期,它实际上会在每个组件上激发。如果你说你现在使用全局混合为每个组件指定一个要在mounted
钩子中运行的函数,并且该函数只运行一次,那就意味着你在你的应用程序中只安装了一个组件。我希望当您更改路由时,关联组件的挂载的
钩子将再次调用该函数。如果看不到您的代码,很难判断。嗯,mounted()
是在实际安装组件时触发的,例如,在我的情况下,当我访问页面时,Login.vue
。因此,当我访问Login.vue
时,我的标题更改为“Login”,当我离开此组件时,它被销毁()
,新组件仪表板.vue
已装入()。现在逻辑上是正确的。但是我想,created()
hooks的工作方式也是一样的。真奇怪。