Vue/Nuxt 异步元标记生成

Mer*_*erc 5 javascript meta vue.js vuejs2 nuxt.js

我们有一个使用 vue.js 和 nuxt 构建的网页。我们nuxt generate用来生成静态 html 文件,其中还应该包含 SEO 和 og 标签。这就是我们使用nuxthead ()生成元信息的原因。

到目前为止,一切都很好。但现在我们有一个页面可以将帖子异步加载到嵌套路由中。如果您转到该页面,它会通过 ajax 调用加载帖子的数据。然后它将使用帖子的元来填充<head>.

一段时间后(加载帖子后)元信息会正确更新,但是当我们使用nuxt generate帖子的数据时,因此当我们使用 生成元信息时,它的元信息不存在head ()。

这就是为什么我们的静态 html 不包含必要的元信息。对此可能有哪些解决方案?理想的情况是生成过程等待帖子加载。能用承诺来解决吗?或者还有其他一些想法吗?

这里this.post先设置为false。我们的辅助函数generateMetaInfo被调用,但显然没有正确的数据。

head () {
  this.log('this.post: ', this.post)
  if (this.post) {
   return generateMetaInfo(this.post)
  }
}
Run Code Online (Sandbox Code Playgroud)

当调用 url 时,我们像这样加载帖子:

getPost () {
  // Only if postSlug is present
  if (this.$route.params.postSlug) {
    // If postslug > try to get it from store
    if (this.getCompletePostBySlug(this.$route.params.postSlug)) {
      this.activePost = this.getCompletePostBySlug(this.$route.params.postSlug)
    }
    // if it is not in store get it via axios
    else {
      const ax = axios.create({
        baseURL: `${window.location.origin}/${this._checkRouteByString('programm') ? 'events' : 'posts'}`
      })
      ax.get(`posts.${this.$i18n.locale}.${this.$route.params.postSlug}.json`)
      .then((response) => {
        const newActivePost = response.data && response.data.items ? response.data.items.find(p => p.slug === this.$route.params.postSlug) : false
        if (newActivePost) {
          this.post = newActivePost
          this.$store.dispatch('data/saveCompletePosts', this.activePost)
        } else {
          this.post = '404'
        }
      })
      .catch((error) => {
        // console.log(error.response)
      })
    }
  } else {
    this.setActivePost()
  }
},
Run Code Online (Sandbox Code Playgroud)

所以我们必须等待 ajax 调用完成。

任何可以帮助我们找到解决方案的想法都非常感激。

干杯

===========================

编辑:

使用承诺也不起作用:

methods: {
  getPostMeta: async function () {
    let promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        const result = {
          title: 'Promise Title Test',
          meta: [
            { charset: 'utf-8' },
            { name: 'viewport', content: 'width=device-width, initial-scale=1' },
            { name: 'keywords', content: 'keyword 1, keyword 2'},
            { hid: 'description', name: 'description', content: 'PROMISE. This is the generic promise descr.'}
          ]
        }
        resolve(result)
      }, 1000)
    })

    let result = await promise
    console.log('result: ', result)

    return result
  }
},
head () {
  return this.getPostMeta()
}
Run Code Online (Sandbox Code Playgroud)

这不会等到承诺得到解决...:((当然这只是一个超时的例子,在现实世界中,这必须与 ajax 调用进行交换,获取帖子的数据)

小智 3

Nuxt 是一个很棒的框架,但是 SEO 和在动态路由上分配元标记非常困难。这可能是它不太好的极少数原因之一。

我认为这里的主要问题是您尝试从仅在承诺或函数解决后调用的方法加载元数据,这意味着在页面渲染之前它永远不会获取元数据。我不会为此使用函数或承诺。

本质上,我发现解决这个问题的方法是您需要以以下格式加载所有元数据(加上您的帖子名称作为 id 或其他内容)

posts: [
    {
        slug: 'some_id',
        meta: [
            {
                name: 'title',
                content: 'some_title'
            },
            {
                ...
        ]
    },
    {
        ...
Run Code Online (Sandbox Code Playgroud)

将您的动态页面放入一个数组中 - 例如,我正在使用 VueX Store 来执行此操作 - 然后您可以使用以下语句

this.$store.state.array.find(p => p.slug === this.$route.params.postSlug).meta
Run Code Online (Sandbox Code Playgroud)

在 .vue 文件中,其中 id 是您想要与路由参数进行比较的任何值。这将返回元数据数组。

我意识到这有点低效,大多数人可能会一想到它就感到畏缩,但它似乎对于动态路线非常有效。

我的 head() 方法如下所示

head() {
    return {
        title: "Title " + this.$route.params.id,
        meta: this.$store.state.results.find((result) => result.id === this.$route.params.id).meta
    }
}
Run Code Online (Sandbox Code Playgroud)

这对我来说非常有效。如果你尝试这样做,我很想听听它是如何进行的。

干杯