Nuxt3_2_SEO and Meta+Transitions

1. SEO and Meta

使用强大的head配置、可组合组件和组件来改善nuxt应用的SEO。

  • nuxt开箱即用,提供了相同的默认值,如果需要,你可以覆盖这些默认值。
    • charset: utf-8
    • viewport: width=device-width, initial-scale=1

可以在nuxt.config.ts中进行使用:

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  app: {
    head: {
      charset: 'utf-8',
      viewport: 'width=device-width, initial-scale=1'
    }
  }
})

在nuxt.config.js中提供app.head属性可以让你自定义整个应用的头部,这个方法不允许提供响应数据,建议在app.vue中使用useHead()方法。

1.1 useHead()

useHead可组合功能允许以编程式、响应式的方式管理head标记,由Unhead提供支持。
与所有组合式一样,他只能用于script setup中使用像生命周期hooks用法那样

index.vue

<script setup lang="ts">
useHead({
    title: '首页-感受nuxt魅力',
    meta: [
        {
            name: 'description',
            content: 'My nuxt meta use useHead'
        }
    ],
    bodyAttrs: {
        class: 'usehead_style'
    },
    script: [{
        innerHTML: 'console.log(\'Hello useHead nuxt page\')'
    }]
})
</script>
 
<style>
.usehead_style {
    background: #0189ff;
}
</style>
  • 我们之前在开发PC/M站时,在不同的页面总要展示不同的title等meta信息,此功能刚好适用。

1.2 useHeadSafe()

useHeadSafe事故useHead外部再进行一次包装,将输入限制为只允许安全的值输入。

useHeadSafe({
  script: [
    { id: 'xss-script', innerHTML: 'alert("xss")' }
  ],
  meta: [
    { 'http-equiv': 'refresh', content: '0;javascript:alert(1)' }
  ]
})

// Will safely generate
// <script id="xss-script"></script>
// <meta content="0;javascript:alert(1)">

但同样的代码放在useHead中,就可以完整的被执行,会有风险。

1.3 useSeoMeta 和 useServerSeoMeta

useSeoMeta和useServerSeoMeta组合式函数可以让你将网站的SEO 元标签定义成一个平面对象,并具有完整的typescript支持。这样可以避免拼写错误和常见错误,例如使用name 而不是 property。

  • 官方示例
<script setup lang="ts">
useSeoMeta({
  title: 'My Amazing Site',
  ogTitle: 'My Amazing Site',
  description: 'This is my amazing site, let me tell you all about it.',
  ogDescription: 'This is my amazing site, let me tell you all about it.',
  ogImage: 'https://example.com/image.png',
  twitterCard: 'summary_large_image',
})
</script>
  • 业务场景示例:若你有一个商品详情页面,不同的商品meta title是商品的名称,那么可以如下操作:
<script setup>
const route = useRoute();
const id = route?.params?.id || 0
const name = route?.query?.name || ''

const title = ref('')

onMounted(() => {
    title.value = name
})

useSeoMeta({
    title,
    description: () => `description: ${title.value}`
})
</script>

这样我们可以看到的效果是:当我们跳转至对应商品页面时,就会展示对应的title和description。

  • 像useSeoMeta一样,useServerSeoMeta让网站的SEO标签定义为具有完整typescript支持的平面对象。在大多数情况下,meta不需要响应,因为机器人只会扫描初始负载。因为,建议使用useServerSeoMeta作为一个以性能为重点的应用程序,它不会在客户机上做任何事情(或返回一个head对象),参数与useSeoMeta完全相同。

1.4 Components

1.4.1 介绍

  • nuxt提供了<Title>, <Base>, <NoScript>, <Style>, <Meta>, <Link>, <Body>, <Html>,<Head>组件,这样就可以直接与组件模板中的元数据进行交互。
  • 因为这些组件名与原生HTML元素相匹配,所以在模板中非常重要的第一点就是要记住大写。
  • <Head>和<Body>可以接受嵌套的元标签(出于美观的原因),但这对嵌套元标签在最终HTML中的呈现位置没有影响。

1.4.2 代码示例

<template>
    <div>
        <Head>
            <Title>{{ title }}</Title>
            <Meta name="description" :content="content"/>
            <Style type="text/css" children="body { background-color: green; }" ></Style>
        </Head>
    
        this is about pages
    </div>
</template>
<script setup lang="ts">
const title = ref('About 自定义title')
const content = ref('作者: Ably')
</script>

此时在about页面上,我们可以看到对应标签生效后的全部内容。例如:网页title变为了我们设置的’About 自定义title’,页面的整体背景颜色变为了绿色。

1.4.3 使用场景

在业务场景中的应用,我们可以全局设置整个应用的meta数据,形成一个整体的风格,但是在一些活动页面/介绍页面,可以有所不同,此时就可以在活动/介绍组件中,通过上述方式,对meta元数据进行自定义设置。

1.5 Types

下面是用于useHead、app.head和组件的非响应式类型。

interface MetaObject {
  title?: string
  titleTemplate?: string | ((title?: string) => string)
  templateParams?: Record<string, string | Record<string, string>>
  base?: Base
  link?: Link[]
  meta?: Meta[]
  style?: Style[]
  script?: Script[]
  noscript?: Noscript[];
  htmlAttrs?: HtmlAttributes;
  bodyAttrs?: BodyAttributes;
}

1.6 特性(Features)

1.6.1 响应式(Reactivity)

  • 所有属性都支持响应式,例如computed、getter和reactive方式。
  • 建议使用getter (() => value)而不是computed(computed(() => value))。
<script setup lang="ts">
const description = ref('My amazing site.')

useHead({
  meta: [
    { name: 'description', content: description }
  ],
})
</script>

1.6.2 Title Template

  • 可以使用titleTemplate选项提供一个动态模板,用于自定义网站的标题。例如,将网站名称添加到每个页面标题中。
  • titleTemplate可以是字符串(其中%s)会被标题替换,也可以是函数
  • 如果你想使用一个函数(用于完全控制), 就不能再nuxt.config中设置,需要在app.vue中进行设置,这样会应用到网站上的所有页面。

app.vue中对于整个项目title的设置

<script setup lang="ts">
useHead({
    titleTemplate: (titleChunk) => {
        return titleChunk ? `${titleChunk} - Ably App` : 'Ably App'
    }
})
</script>

如果在页面中设置过title,那么会在这个后面拼接上 Ably App, 否则直接展示 Ably App

在这里插入图片描述

1.6.3 Body Tags

可以在标签上使用tagPosition: 'bodyClose'选项,将他们附加到<body>标签的末尾

<script setup lang="ts">
useHead({
    titleTemplate: (titleChunk) => {
        return titleChunk ? `${titleChunk} - Ably App` : 'Ably App'
    },
    script: [
    {
      src: 'https://third-party-script.com',
      // valid options are: 'head' | 'bodyClose' | 'bodyOpen'
      tagPosition: 'bodyClose'
    }
  ]
})
</script>

例如,我们可以通过这种方式引入第三方库,或者插件。
在这里插入图片描述

1.7 Examples 官方示例

1.7.1 With definePageMeta

  • 在您的pages/目录中,您可以使用definePageMeta和useHead来基于当前路由设置元数据。
  • 例如,你可以首先设置当前页面标题(这是在构建时通过宏提取的,所以它不能动态设置):
<script setup lang="ts">
	definePageMeta({
	  title: 'Some Page'
	})
</script>
  • 之后在你的布局文件中,你可能会使用之前设置的路由元数据
<script setup lang="ts">
const route = useRoute()

useHead({
  meta: [{ property: 'og:title', content: `App Name - ${route.meta.title}` }]
})
</script>

1.7.2 动态标题(Dynamic Title)

在下面的例子中,titleTemplate要么被设置为带有%s占位符的字符串,要么被设置为一个函数,这样可以更灵活地为nuxt应用的每个路由动态设置页面标题

<script setup lang="ts">
useHead({
  // as a string,
  // where `%s` is replaced with the title
  titleTemplate: '%s - Site Title',
  // ... or as a function
  titleTemplate: (productCategory) => {
    return productCategory
      ? `${productCategory} - Site Title`
      : 'Site Title'
  }
})
</script>

1.7.3 内部CSS(External CSS)

下面的例子展示了如何使用useHead的link属性或使用< link >组件来启用Google Fonts:

- 方式一:Components方式

<template>
  <div>
    <Link rel="preconnect" href="https://fonts.googleapis.com" />
    <Link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" crossorigin="" />
  </div>
</template>





- 方式二:useHead 方式

<script setup lang="ts">
useHead({
  link: [
    {
      rel: 'preconnect',
      href: 'https://fonts.googleapis.com'
    },
    {
      rel: 'stylesheet',
      href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap',
      crossorigin: ''
    }
  ]
})
</script>

2. Transitions

nuxt利用Vue的transition组件在页面和布局之间应用过渡动画

2.1 Page Transitions

可以启用页面转换对所有页面应用自动进行过渡

2.1.1 全局动画

  • 在nuxt.config.ts中配置过渡动画选项
export default defineNuxtConfig({
  app: {
    pageTransition: { name: 'page', mode: 'out-in' }
  },
})
  • 在app.vue中配置选项执行的动画效果
<style>
.page-enter-active,
.page-leave-active {
  transition: all 0.4s;
}
.page-enter-from,
.page-leave-to {
  opacity: 0;
  filter: blur(1rem);
}
</style>
  • 这样再次切换页面时,我们就可以看到生动的动画效果啦

效果视频审核中

2.1.2 局部动画

  • 要为页面设置不同的过渡,可以在页面的definePageMeta中设置pageTransition 键
  • 例如在About.vue中设置单独的页面效果
<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'rotate'   
  }
})
</script>

此时在app.vue中定义rotate动画效果

.rotate-enter-active,
.rotate-leave-active {
  transition: all 0.4s;
}
.rotate-enter-from,
.rotate-leave-to {
  opacity: 0;
  transform: rotate3d(1, 1, 1, 15deg);
}

这样去about页面,我们就可以看到最新的效果啦

2.1.3 动画设置

我们在定义动画时可以看到,无论是在nuxt.config.ts中定义pageTransition,还是在definePageMeta中定义pageTransition,都有一个name,是这个动画的名称。在定义动画时,与vue一样

  • [name]-enter-active、[name]-leave-active 设置动画属性及持续时间
  • [name]-enter-from、[name]-leave-to 设置动画变化效果

2.2 Layout transitions

2.2.1 全局layout动画

  • 参考官方示例,讲解layout布局使用,以及切换布局时的动画效果
  • layouts/default.vue 默认布局效果,与pages同级
<template>
    <div>
      <pre>default layout</pre>
      <slot />
    </div>
  </template>
  
  <style scoped>
  div {
    background-color: lightgreen;
  }
  </style>
  • layouts/orange.vue 橙色布局效果
<template>
    <div>
      <pre>orange layout</pre>
      <slot />
    </div>
  </template>
  
  <style scoped>
  div {
    background-color: #eebb90;
    padding: 20px;
    height: 100vh;
  }
  </style>
  • app.vue中,定义layout动画效果,以及在nuxtpage标签外包一层nuxtlayout
<template>
    <div>
        <NuxtLayout>
            <NuxtPage />
        </NuxtLayout>
    </div>
</template>

<style>
	.layout-enter-active,
	.layout-leave-active {
	  transition: all 0.4s;
	}
	.layout-enter-from,
	.layout-leave-to {
	  filter: grayscale(1);
	}
</style>
  • nuxt.config.ts中配置 layout动画
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  app: {
    head: {
      title: '默认标题',
      charset: 'utf-8',
      viewport: 'width=device-width, initial-scale=1'
    },
    pageTransition: { // page动画效果
      name: 'page',
      mode: 'out-in'
    },
    layoutTransition: { // layout动画效果
      name: 'layout',
      mode: 'out-in'
     }
  }
})

2.2.2 局部layout动画

  • 当我们需要某个页面,例如about.vue页面使用orange布局时,可以在about.vue页面中设置
definePageMeta({
  layout: 'orange'
})

这样,在切换页面时,使用不同布局的页面,就会有不同的动画效果,可以通过这种方式设置切换整体app风格。

2.2.3 动画设置

  • 全局动画效果配置,可以在nuxt.config.ts中app下面进行配置pageTransition、layoutTransition,全部生效
  • 当有自定义动画时,可以在页面中通过definePageMeta下面进行配置pageTransition、layoutTransition,局部页面生效
  • pageTransition、layoutTransition 参数
    • mode 动画进出方式: out-in
    • name 动画名称,用于在css中定义动画
  • 动画可以关闭,若配置,那么pageTransition、layoutTransition是上述定义的对象,若关闭,这两个值为false即可禁用

2.3 JavaScript Hooks

对于高级用例,可以使用JavaScript hooks钩子为nuxt页面创建高度动态和自定义的过渡动画。这种方式为JavaScript动画库(GSAP或Tween.js)提供了完美的用例。

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'custom-flip',
    mode: 'out-in',
    onBeforeEnter: (el) => {
      console.log('Before enter...')
    },
    onEnter: (el, done) => {},
    onAfterEnter: (el) => {}
  }
})
</script>

2.4 动态过渡动画

  • 定义layouts/default.vue页面及内容:
<script setup lang="ts">
const route = useRoute()
const id = computed(() => Number(route.params.id || 1))
const prev = computed(() => '/' + (id.value - 1))
const next = computed(() => '/' + (id.value + 1))
</script>

<template>
  <div>
    <slot />
    <div v-if="$route.params.id">
      <NuxtLink :to="prev">⬅️</NuxtLink> |
      <NuxtLink :to="next">➡️</NuxtLink>
    </div>
  </div>
</template>

点击按钮,切换到前一个page 或 后一个page

  • pages/[id].vue 动态公共页面及相关页面内容
<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'slide-right',
    mode: 'out-in'
  },
  middleware (to, from) {
    to.meta.pageTransition.name = +to.params.id > +from.params.id ? 'slide-left' : 'slide-right'
  }
})
</script>

<template>
  <h1>#{{ $route.params.id }}</h1>
</template>
<style>
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
  transition: all 0.2s;
}
.slide-left-enter-from {
  opacity: 0;
  transform: translate(50px, 0);
}
.slide-left-leave-to {
  opacity: 0;
  transform: translate(-50px, 0);
}
.slide-right-enter-from {
  opacity: 0;
  transform: translate(-50px, 0);
}
.slide-right-leave-to {
  opacity: 0;
  transform: translate(50px, 0);
}
</style>

加上动画效果后,与轮播组件一样流畅完整。

2.5 在<NuxtPage />中增加transition动画

<NuxtPage />在app.vue中使用时,transition-props可以直接作为组件props传递来激活全局转换。

<template>
  <div>
    <NuxtLayout>
      <NuxtPage :transition="{
        name: 'bounce',
        mode: 'out-in'
      }" />
    </NuxtLayout>
  </div>
</template>

如果有用,点个赞呗~

总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~

官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值