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,你无须超越谁,只要超越昨天的自己就好~
官方文档

















