Nuxt.js 基础语法


我们把自己,用终将灰飞烟灭的纸币,寂寞地捆绑起来
我搜寻着记忆
给我留下长久回味的时刻
让我难以忘怀的分分秒秒,他们统统不是来自金钱或者财富


在这里插入图片描述


一、概述

1. Nuxt.js是什么


在这里插入图片描述


2. NuxtJS 使用方式

  • 初始项目,从零开始的方式
  • 已有的 Node.js 服务端项目的方式
    • 直接把 Nuxt 当作一个中间件集成到 Node Web Server 中
  • 现有的 Vue.js 项目基础上增加Nuxt的方式
    • 非常熟悉 Nuxt.js
    • 至少百分之 10 的代码改动




二、初始化 NuxtJS

Nuxt 提供了两种方式用来创建项目: 使用 create-nuxt-app 脚手架工具、手动创建,下面以手动创建为例:

1. 创建项目目录

# 创建项目
mkdir nuxt-app-demo
​
# 进入项目
cd nuxt-app-demo
​
# 初始化 package.json 文件
npm init -y
​
# 安装 nuxt
npm install nuxt


2. 配置项目启动命令

package.json文件的 scripts 中新增:

"scripts": {
  "dev": "nuxt"
}


3. 创建入口文件

根路径创建 pages 目录:

mkdir pages

创建第一个页面的 pages/index.vue

<template>
  <h1>Hello world!</h1>
</template>


4. 启动项目

npm run dev
  • 注意:Nuxt.js 会监听 pages 目录中的文件更改,因此在添加新页面时无需重新启动应用程序。



5. git托管

新建 .gitignore 文件:

# 排除不需要用git托管的文件
node_modules
.nuxt


6. git 分支

git branch  
# 看本地当前所在分支,并且在当前分支前面加“*”号标记
git branch -r
# 查看远程分支,r是remote的简写
git  branch  _分支名
# 创建一个新的本地分支
git checkout 分支名
# 切换分支
git checkout -b 分支名
# 创建并切换分支





三、路由

Nuxt.JS 官方文档

1. 基本路由

⑴. 文档说明

在这里插入图片描述

⑵. 项目代码:

新建 pages/user/one 文件:

<template>
  <h1>one</h1>
</template>

⑶. 预览:

在这里插入图片描述



2. 路由导航

  • a 标签: 会刷新整个页面,走服务端渲染,不要使用
  • nuxt-link: <nuxt-link to="/"> 主页 </nuxt-link>
  • 编程式导航: this.$router.push

编辑 pages/user/one 文件:

<template>
  <div>
    <h1>About page</h1>
    <!-- a 链接,刷新导航,走服务端渲染 -->
    <h2>a 链接</h2>
    <a href="/">首页</a><!-- router-link 导航链接组件 -->
    <h2>router-link</h2>
    <router-link to="/">首页</router-link><!-- 编程式导航 -->
    <h2>编程式导航</h2>
    <button @click="onClick">首页</button>
  </div>
</template><script>
export default {
  name: 'AboutPage',
  methods: {
    onClick () {
      this.$router.push('/')
    }
  }
}
</script>


3. 动态路由

动态路由指的是路径时动态的,路径中的某一部分是动态变化的,
需要用 : 进行表征,使用 表示是否必要


在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。

在这里插入图片描述

名称为 users-id 的路由路径带有 :id? 参数,表示该路由是可选的。如果你想将它设置为必选的路由,需要在 users/_id 目录内创建一个 index.vue 文件。

新建 pages/user/_id.vue 文件:

<template>
  <div>
    <h1>User Pages</h1>
    <!-- 路由参数 id 能够通过 $route.params.xx 的形式来获取 -->
    <h2>{{ $route.params.id }}</h2>
  </div>
</template>

<script>
export default {
  name: 'UserPage'
}
</script>


4. 嵌套路由

  • 创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件
  • 在父组件(.vue文件) 内增加 用于显示子视图内容

在这里插入图片描述



5. 自定义路由配置

新增一个 nuxt.config.js 文件进行配置:

/**
 * Nuxt.js 配置文件
 */

module.exports = {
  router: {
    base: '/abc'   
  }
}

// 注意,这样配置后路由地址都应该以/abc开头:http://localhost:3000/abc/...
// 要是访问首页的话就是abc/,末尾的/不能省略

也可以使用 extendRoutes 方法

module.exports = {
  router: {
    base: '/abc',
    // routes: 一个数组,路由配置表
    // resolve: 解析路由组件路径
    extendRoutes(routes, resolve) {
      routes.push({
        name: 'hello',
        path: '/hello',
        component: resolve(__dirname, 'pages/about.vue')
      })
    }
  }
}




四、视图

1. 结构

在这里插入图片描述


在 NuxtJS 中页面结构一般由三部分组成:

  • 第一部分是最外层的文档页面,也就是单页面或者说服务端渲染的HTML页面。
  • 在HTML 页面里面包裹着 Layout布局组件(可选),相当于所有页面的父路由。
  • 再往里面是页面组件,每个页面组件有自己额外的成员方法,包括页面的子组件之类的可选内容。


2. 模板

定制化默认的 html 模板,只需要在根目录(或者 src)创建一个 app.html 的文件:

<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head {{ HEAD_ATTRS }}>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}  <!-- 这body里就是渲染视图的位置,这个app就是根组件 -->
  </body>
</html>


3. 布局 (Layout)

可通过添加 layouts/default.vue 文件来扩展应用的默认布局:

<template>
  <div>
    <h2>layouts/default.vue</h2>
    <!-- 页面出口,类似子路由 -->
    <nuxt />
  </div>
</template>

然后其他页面 (即 pages/index.vue ) 使用自定义布局:

<template>
  <h1>Hello world!</h1>
</template>

<script>
export default {
  name: 'HomePage',
  // 在别的组件使用时指定layout:'foo' 也就是指定别的组件作为布局组件,也就是foo会代替default
  layout: 'default'   // 表示使用默认布局使用的是 layouts文件夹下面的default组件
}
</script>




五、异步数据

1. asyncData 方法

asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你可以利用 asyncData方法来获取数据,Nuxt.js 会将 asyncData 返回的数据融合组件 data 方法返回的数据一并返回给当前组件。

  • 基本用法

    • 它会将asyncData返回的数据融合组件data方法返回数据一并给组件
    • 调用时机:服务端渲染期间和客户端路由更新之前(保证了服务端和客户端都要运行处理数据)

  • 注意事项

    • 只能在页面组件中使用,非页面组件中不会调用asyncData方法,如果子组件中需要数据,可以通过props方式传递数据
    • 没有this,因为它是在组件初始化之前被调用的

当你想用的动态页面内容有利于SEO或者是提升首屏渲染速度的时候,就在asyncData中发送请求数据。如果是非异步数据或者普通数据,则正常的初始化到data中即可。



2. 代码演示


⑴. 添加数据

新建数据文件 static/data.json

{
  "posts": [
    {
      "id": 1,
      "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
      "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
    },
    {
      "id": 2,
      "title": "qui est esse",
      "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
    },
    {
      "id": 3,
      "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
      "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
    },
    {
      "id": 4,
      "title": "eum et est occaecati",
      "body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit"
    },
    {
      "id": 5,
      "title": "nesciunt quas odio",
      "body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque"
    }
  ],
  "title": "文章数据"
}

⑵. 获取数据

安装 axios

npm i axios

在首页直接获取数据(服务端获取异步数据):

<template>
  <div>
    <h1>{{ title }}</h1>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'HomePage',
  layout: 'default',
  async asyncData () {
    console.log('asyncData')
    console.log(this)
    const res = await axios({
      method: 'GET',
      url: 'http://localhost:3000/data.json'
    })
    return res.data
  },
  data () {
    return {
      foo: 'bar'
    }
  }
}
</script>

如果我们尝试在asyncData里面进行console.log(‘xxx’)时,会发现在服务端的控制台输出xxx的同时,nuxt为了方便调试和更加直观,会让客户端也会输出xxx,并且客户端的xxx是包裹在Nuxt SSR对象中的,如果尝试打印this会发现是undefined,因为服务端渲染时组件还没初始化。


⑶. 客户端路由导航
// pages/index.vue

<template>
  <div>
    <h1>{{ title }}</h1>
    <nuxt-link to="/about">About</nuxt-link>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'HomePage',
  layout: 'default',
  async asyncData () {
    console.log('xxx')
    const res = await axios({
      method: 'GET',
      url: 'http://localhost:3000/data.json'
    })
    return res.data
  },
  data () {
    return {
      foo: 'bar'
    }
  }
}
</script>

先通过地址访问首页,会发现客户端控制台打印Nuxt SSR下面输出了xxx,说明首屏是在服务端渲染的,然后输出了xxx。紧接着通过about路由导航链接跳转到about页面,然后about页面中也有个导航链接可以跳转到首页,此时跳转回首页时也会调用首页组件index.vue中的asyncData方法,此时也会打印xxx,但是这时候的xxx外层没有Nuxt SSR对象了,原因是这次导航跳转引起的调用是在客户端执行的
首屏服务端渲染数据好理解,直接拿到数据返回并返回了SPA页面脚本,但是如果客户端执行SPA程序时,不执行asyncData的话,将会导致数据无法更新,所以当我们通过导航链接进行跳转时也会在客户端进行一次调用asyncData


⑷. 子组件调用 asyncData 方法

注意: asyncData只能在页面组件中使用,不能在非页面组件(比如页面组件的子组件)中使用,非页面组件中不会调用asyncData函数如果想在子组件使用服务端渲染时的数据,只能通过页面组件进行获取,然后再利用父子组件中的传值方法来传递给页面组件的子组件


页面组件的子组件:

// components/Foo.vue

<template>
  <div>
    <h1>FooPage</h1>
    <ul>
      <li
        v-for="item in posts"
        :key="item.id"
      >
      {{ item.title }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'FooPage',
  props: ['posts'],
  // asyncData 只能在页面组件中使用
  // async asyncData () {
  //   console.log('foo asyncData')
  //   return {
  //     foo: 'bar'
  //   }
  // }
}
</script>

页面组件:

// pages/index.vue

<template>
  <div>
    <h1>{{ title }}</h1>
    <nuxt-link to="/about">About</nuxt-link>
    <br>
    <foo :posts="posts" />    
  </div>
</template>

<script>
import axios from 'axios'
import Foo from '@/components/Foo'

export default {
  name: 'HomePage',
  layout: 'default',
  components: {
    Foo
  },
  // 当你想要动态页面内容有利于 SEO
  // 或者是提升首屏渲染速度的时候,
  // 就在 asyncData 中发请求拿数据
  async asyncData () {
    console.log('asyncData')
    console.log(this)
    const res = await axios({
      method: 'GET',
      url: 'http://localhost:3000/abc/data.json'
    })
    return res.data
  },

  // 如果是非异步数据或者普通数据,则正常的初始化到 data 中即可
  data () {
    return {
      foo: 'bar'
    }
  }
}
</script>


3. 上下文对象

比如:http:// localhost:3000/artical/5 这个路径就应该对应第五篇文章,那么问题是怎么获取这个5呢
首先我们容易想到路由对象 this.$route.params ,但是 asyncData 在服务端执行时是没有 this 的,也就是说 this 不指向当前 Vue 实例
所以我们需要使用 asyncData 中的上下文对象参数来获取,上下文对象中可以获取动态路由中的参数


// pages/article/_id.vue
// 根据路径中的最后一位id值的不同来拿到不同的对象,然后渲染页面中的不同内容

<template>
  <div>
    <!-- <h1>article page</h1> -->
    <h1>{{ article.title }}</h1>
    <div>{{ article.body }}</div>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: 'ArticlePage',
  // asyncData 上下文对象
  async asyncData (context) {
    // 这里有我们需要的数据
    console.log(context)
    const { data } = await axios({
      method: 'GET',
      url: 'http://localhost:3000/data.json'
    })
    // asyncData 里面没有 this, 不能通过这种方式获取 id
    // console.log(this.$route.params)

    // 可以通过上下文对象的 params.id 或者 router.params.id
    // 拿到后将字符串类型转换为数字类型
    // 根据路径中的最后一位id值的不同来拿到不同的对象,然后渲染页面中的不同内容
    const id = Number.parseInt(context.params.id)
    return {
      article: data.posts.find(item => item.id === id)
    }
  }
}
</script>


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后海 0_o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值