Udemy - Nuxt JS with Laravel API - Building SSR Vue JS Apps 笔记5 Project - A simple Nuxt app
Making Api Request The Vue Way
新建pages/posts/index.vue文件:
<template> <div> <h2>Making API request - the Vue way</h2> <div v-for="post in posts" :key="post.id"> <span> {{post.title}} </span> </div> </div> </template> <script> import axios from 'axios'; export default { name: "index.vue", data() { return { posts: [], } }, mounted() { axios.get('https://jsonplaceholder.typicode.com/todos') .then(response => { console.log(response); this.posts = response.data; }) .catch(function (error) { console.log(error); }) }, } </script> <style scoped> </style>
或者:
<template> <div> <h2>Making API request - the Vue way</h2> <div v-for="post in posts" :key="post.id"> <span> {{post.title}} </span> </div> </div> </template> <script> import axios from 'axios'; export default { name: "index.vue", data() { return { posts: [], } }, mounted() { let that = this; axios.get('https://jsonplaceholder.typicode.com/todos') .then(function (response) { console.log(response); that.posts = response.data; }) .catch(function (error) { console.log(error); }) }, } </script> <style scoped> </style>
因为要用到axios,前期未安装:
看package.json:
执行安装axios:
npm i axios
或者
npm install axios
i是install的简写;
这里提供一个在线的REST API测试服务,https://jsonplaceholder.typicode.com/
修改components/Nav.vue:
<template> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <a class="navbar-brand" href="#">Nuxt App</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> <nuxt-link to="/" class="nav-link">Home</nuxt-link> </li> <li class="nav-item"> <nuxt-link to="/users" class="nav-link">Users</nuxt-link> </li> <li class="nav-item"> <nuxt-link to="/posts" class="nav-link">Posts</nuxt-link> </li> </ul> </div> </nav> </template> <script> export default { name: "Nav" } </script> <style scoped> </style>
打开 http://localhost:3000/posts 结果:
但是注意,这个并不是SSR 服务端渲染的,可以右键查看 view pagesource:
源代码中并无页面内容元素。
而要服务端渲染又能处理这种axios异步请求的,请看下面的AsyncData
Nuxt AsyncData Method
AsyncData method runs on both client and server side
posts/index.vue修改如下:
<template> <div> <h2>Making API request - the Vue way</h2> <div v-for="post in posts" :key="post.id"> <span> {{post.title}} </span> </div> </div> </template> <script> import axios from 'axios'; export default { name: "index.vue", data() { return { posts: [], } }, // mounted() { // axios.get('https://jsonplaceholder.typicode.com/todos') // .then(response => { // console.log(response); // this.posts = response.data; // }) // .catch(function (error) { // console.log(error); // }) // }, asyncData(context) { console.log(context); }, } </script> <style scoped> </style>
刷新http://localhost:3000/posts 页面,查看terminal中:
console.log结果出现在了server side,
当从 http://localhost:3000/ 点击 导航按钮 posts 后,浏览器控制台出现:
console.log结果出现在了client side 而server side没有新结果。
也就是说,asyncData方法会在client side 和 server side 运行。
初次刷新页面的时候,会在服务器端执行,而后期跳转页面的时候,会在客户端执行。
Using AsyncData Method
修改posts/index.vue:
<template> <div> <h2>Making API request - the Vue way</h2> <div v-for="post in posts" :key="post.id"> <span> {{post.title}} </span> </div> </div> </template> <script> import axios from 'axios'; export default { name: "index.vue", data() { return { posts: [], } }, // mounted() { // axios.get('https://jsonplaceholder.typicode.com/todos') // .then(response => { // console.log(response); // this.posts = response.data; // }) // .catch(function (error) { // console.log(error); // }) // }, asyncData(context) { return { posts: [ {id: 1, title: 'a'}, {id: 2, title: 'b'}, {id: 3, title: 'c'}, ] } }, } </script> <style scoped> </style>
http://localhost:3000/posts 结果如下:
修改posts/index.vue:
<template> <div> <h2>Making API request - the Vue way</h2> <div v-for="post in posts" :key="post.id"> <span> {{post.title}} </span> </div> </div> </template> <script> import axios from 'axios'; export default { name: "index.vue", data() { return { posts: [], } }, // mounted() { // axios.get('https://jsonplaceholder.typicode.com/todos') // .then(response => { // console.log(response); // this.posts = response.data; // }) // .catch(function (error) { // console.log(error); // }) // }, asyncData(context) { return axios.get('https://jsonplaceholder.typicode.com/todos') .then(response => { return { posts: response.data }; }) .catch(error => { }); }, } </script> <style scoped> </style>
打开 http://localhost:3000/posts 结果:
查看页面源代码结果:
嗯,相比直接vue,对SEO更友好了。
我们来看看搜索引擎会看到什么结果:
关键词 html5 outliner 找一个工具站,我这里用 https://gsnedders.html5.org/outliner/
把上面页面的源代码全部复制然后粘贴到 工具站中:
点击Outline this! 结果如下:
如果把span换成h4后结果如下:
Async Await to make API Request
修改posts/index.vue如下:
<template> <div> <h2>Making API request - the Vue way</h2> <div v-for="post in posts" :key="post.id"> <span> {{post.title}} </span> </div> </div> </template> <script> import axios from 'axios'; export default { name: "index.vue", data() { return { posts: [], } }, // mounted() { // axios.get('https://jsonplaceholder.typicode.com/todos') // .then(response => { // console.log(response); // this.posts = response.data; // }) // .catch(function (error) { // console.log(error); // }) // }, async asyncData(context) { let res = await axios.get('https://jsonplaceholder.typicode.com/todos'); return {posts: res.data}; }, } </script> <style scoped> </style>
或修改asyncData为:
async asyncData(context) {
let {data} = await axios.get('https://jsonplaceholder.typicode.com/todos');
return {posts: data};
},
如果需要修改页面的title:
默认定义在nuxt.config.js中:
不过我们可以给每一个Page都定义:
修改pages/posts/index.vue如下:
<template> <div> <h2>Making API request - the Vue way</h2> <div v-for="post in posts" :key="post.id"> <span> {{post.title}} </span> </div> </div> </template> <script> import axios from 'axios'; export default { name: "index.vue", data() { return { posts: [], } }, // mounted() { // axios.get('https://jsonplaceholder.typicode.com/todos') // .then(response => { // console.log(response); // this.posts = response.data; // }) // .catch(function (error) { // console.log(error); // }) // }, async asyncData(context) { let {data} = await axios.get('https://jsonplaceholder.typicode.com/todos'); return {posts: data}; }, head: { title: 'List of posts', } } </script> <style scoped> </style>
即增加:
打开 http://localhost:3000/posts 结果:
fetch方法可以查看官方文档。
https://nuxtjs.org/api/pages-fetch#__layout
Vue Component
新建components/Card.vue文件:
<template> <div> <div class="card bg-light mb-3" style="max-width: 18rem;"> <div class="card-header">{{post.id}}</div> <div class="card-body"> <h5 class="card-title">{{post.title}}</h5> </div> </div> </div> </template> <script> export default { name: "Card", props: { post: Object, } } </script> <style scoped> </style>
pages/posts/index.vue文件修改如下:
<template> <div> <h2>Making API request - the Vue way</h2> <Card v-for="post in posts" :key="post.id" :post="post"></Card> </div> </template> <script> import axios from 'axios'; import Card from "../../components/Card"; export default { name: "index.vue", components: { Card, }, data() { return { posts: [], } }, // mounted() { // axios.get('https://jsonplaceholder.typicode.com/todos') // .then(response => { // console.log(response); // this.posts = response.data; // }) // .catch(function (error) { // console.log(error); // }) // }, async asyncData(context) { let {data} = await axios.get('https://jsonplaceholder.typicode.com/todos'); return {posts: data}; }, head: { title: 'List of posts', } } </script> <style scoped> </style>
打开 http://localhost:3000/posts 结果如下:
Show Post by ID
新建pages.posts/_id/index.vue文件:
<template> <div> {{$route.params.id}} </div> </template> <script> export default { name: "index.vue" } </script> <style scoped> </style>
修改components/Card.vue文件:
<template> <div> <div class="card bg-light mb-3" style="max-width: 18rem;"> <div class="card-header">{{post.id}}</div> <div class="card-body"> <h5 class="card-title"> <nuxt-link :to="{name:'posts-id',params:{id:post.id}}">{{post.title}}</nuxt-link> </h5> </div> </div> </div> </template> <script> export default { name: "Card", props: { post: Object, } } </script> <style scoped> </style>
至于:to参数设置name:’post-id’因为:
现在 http://localhost:3000/posts 页面:
点击打卡后:
Getting Individual Post
修改posts/_id/index.vue文件:
<template> <div class="container"> <h1>{{post.title}}</h1> <pre>{{post.body}}</pre> <nuxt-link to="/posts">Back to posts page</nuxt-link> </div> </template> <script> import axios from "axios"; export default { name: "index.vue", async asyncData(context) { let {data} = await axios.get(`https://jsonplaceholder.typicode.com/todos/${context.params.id}`); return {post: data}; }, } </script> <style scoped> </style>
设置每个post的title 使用动态设置
head(){
return{
title:…
}
}pages/posts/_id/index.vue:
<template> <div class="container"> <h1>{{post.title}}</h1> <pre>{{post.body}}</pre> <nuxt-link to="/posts">Back to posts page</nuxt-link> </div> </template> <script> import axios from "axios"; export default { name: "index.vue", // async asyncData(context) { // let {data} = await axios.get(`https://jsonplaceholder.typicode.com/posts/${context.params.id}`); // return {post: data}; // }, async asyncData({params}) { let {data} = await axios.get(`https://jsonplaceholder.typicode.com/posts/${params.id}`); return {post: data}; }, // head: { // title: this.post.title, // } head() { //动态设置title return { title: this.post.title, } } } </script> <style scoped> </style>
pages/posts/index.vue:
<template> <div> <h2>Making API request - the Vue way</h2> <div class="container row"> <Card class="ml-auto mr-auto" v-for="post in posts" :key="post.id" :post="post"></Card> </div> </div> </template> <script> import axios from 'axios'; import Card from "../../components/Card"; export default { name: "index.vue", components: { Card, }, data() { return { posts: [], } }, // mounted() { // axios.get('https://jsonplaceholder.typicode.com/todos') // .then(response => { // console.log(response); // this.posts = response.data; // }) // .catch(function (error) { // console.log(error); // }) // }, async asyncData(context) { let {data} = await axios.get('https://jsonplaceholder.typicode.com/posts'); return {posts: data}; }, head: { title: 'List of posts', } } </script> <style scoped> </style>





















浙公网安备 33010602011771号