参考文档
中文:https://zh.nuxtjs.org/guide/installation
什么是nuxt.js?
Nuxt.js 是一个基于 Vue.js 的通用应用框架。完成 vuejs 项目的服务器端渲染
SSR 和我们 nuxt.js 有什么关系?
nuxt.js 就是完成 vuejs 项目的服务器端渲染。主要是为了解决 vuejs 项目不利于SEO的问题。
为什么要使用 nuxt.js 实现服务器端的渲染?
没有使用 nuxt.js 的时候 vuejs 项目的不能服务器端渲染,使用的是客户端BSR(都是前后端分离,通过api接口获取数据,然后前端渲染,是不利于SEO,因为网页里面的动态添加,对于搜索引擎爬取网站的时候,是看不到内容的,网站很难被搜索引擎收录,网站的流量很小,自然不容易出名)。
nuxt.js的使用
建议使用第三方库nuxt.js ---------https://zh.nuxtjs.org/guide
第一步快速生成一个项目:> $ npx create-nuxt-app <项目名>
(npx在NPM版本5.2.0默认安装了)
------------------或者用yarn:yarn create nuxt-app <项目名>
第二步根据需要选择对应选项
选择完以后会自动生成一个项目,大概长下面这样,我们分析一下每个文件的作用
第三步:实操
1,首先我们先来练习路由,一共有三种路由方式(我们只需要写路由即可,文件会自动生成路由映射)
- 基础路由
- 动态路由、路由参数
- 路由嵌套
** 1,基础路由案例,我们可以在pages下面建一个users文件夹,文件夹下建一个index.vue组件
,代码如下**
<template>
<div>
<!--基本路由:域名:3000/目录/文件-->
<h1>hi users-index!我是静态路由</h1>
</div>
</template>
输入网址:http://localhost:3000/users得到结果如下,
这里要注意一下,因为我的文件叫index.vue,所以可以省略不写index,以后其他indx文件也可以不写
2,动态路由、(路由参数)案例:我们可以在在pages下面建一个news文件夹,文件夹下建一个list.vue组件
<template>
<div>
<nuxt-link to="/news/1">新闻一</nuxt-link>
<nuxt-link to="/news/2">新闻二</nuxt-link>
<nuxt-link to="/news/3">新闻三</nuxt-link>
</div>
</template>
然后再建一个_id.vue文件,这里注意:_id表示变量,文件中的id也是根据路由变化的
<template>
<div>
<h1>hi 我是动态路由(参数路由)</h1>
<h2>我是第{{ $route.params.id }}条新闻</h2>
</div>
</template>
输入网址:http://localhost:3000/news得到结果如下,
点击新闻一:
3, 路由嵌套案例:我们可以在在pages下面建一个goods.vue组件
<template>
<div>
<h1>你好呀,我是嵌套路由的一级路由:goods.vue
</h1>
<!--这是父容器,访问http://localhost:3000/goods/list时,会将子组件中的内容放到父页中-->
<nuxt-child/>
</div>
</template>
在pages下面建一个goods文件夹,文件夹里面建一个list.vue组件,这里随便定义几条路由
<template>
<div>
<nuxt-link to="goods/1">商品1</nuxt-link>
<nuxt-link to="goods/2">商品2</nuxt-link>
<nuxt-link to="goods/3">商品3</nuxt-link>
</div>
</template>
输入网址:http://localhost:3000/goods/list得到结果如下,这个父容器会把子组件中的内容会放到父页中
第四步,layouts/default.vue设置公共头和尾,在每一个页面都有一样的头尾
<template>
<div>
<h1>头部</h1>
<nuxt-link to="/news">新闻</nuxt-link>
<nuxt-link to="/movie/list">电影</nuxt-link>
<nuxt-link to="/maoyan/list">猫眼</nuxt-link>
<hr>
<!--有点类似:vue-router里面的 router-view -->
<!--在nuxt.js里面把所有的pages里面的组件页面全部在这里渲染-->
<nuxt />
<h2>底部</h2>
</div>
</template>
效果是这样的
第五步,向服务器端请求数据,现在真的要操作了
在pages下面建一个movie文件夹,文件夹里面建一个list.vue组件
<template>
<div>
<h1>我是猫眼电影的列表</h1>
<ul v-for="ele in movieData">
<li>序号:{{ ele.id }}</li>
<li>电影名:{{ ele.nm}}</li>
<li>图片:<img :src="ele.img.replace('w.h','200.200')" alt=""></li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: "list.vue",
// 发送网络请求 可以把这个暂且理解为 created 声明周期函数
asyncData:function(context){
// console.log(context.req.url); // 代表请求头信息
// console.log(context.req.method); // 代表请求头信息
// console.log(context.res);// 代表响应头信息
// console.log(process.server);// 可以标识当前运行环境 ssr 为true
// 发送网络请求
//这个地址 是猫眼电影的一个接口
// var url='http://m.maoyan.com/ajax/movieOnInfoList?token='
//这里有一个**注意事项(1)**
//三目运算符,判断当前的执行环境是服务器端还是浏览器端
var url = process.server ? 'http://m.maoyan.com/ajax/movieOnInfoList?token=' : '/ajax/movieOnInfoList'
// 1. nuxt 第一次的请求的时候,是服务器请求 没有跨域 http://m.maoyan.com/ajax/movieOnInfoList?token=
// 2. 以后都是前端请求,存在跨域: /ajax/movieOnInfoList ==> '@nuxtjs/proxy'==> http://m.maoyan.com/ajax/movieOnInfoList?token=
return axios.get(url).then(response => {
console.log(response.data.movieList)
if(response.status == 200 ){
console.log(response)
return { movieData:response.data.movieList }
}
}).catch(error=>{
console.log(error)
})
}
}
</script>
<style scoped>
</style>
注意事项(1):第一次请求url路径是,是服务器端进行api请求,获取数据,然后渲染,当渲染后的数据(html代码 js代码)返回给浏览器后,以后的执行环境都是浏览器环境,以后asyncData函数在浏览器端执行,在浏览器端做页面切换时,发送网络请求给猫眼的服务器都是由浏览器发出的
注意事项(2):如果是浏览器渲染,因为同源政策,则会出现跨域问题,而服务器猫眼同源政策问题所以不会有跨域问题
总结注意事项(1),(2):1. nuxt 第一次的请求的时候,是服务器请求,没有跨域问题;
--------------------以后都是前端请求,存在跨域
如何解决跨域问题?官方给出的解决方案是使用代理解决跨域问题
原理
为出现跨域的请求设置代理服务器,以后对于这个跨域的请求,当前的这个代理就会拦截起来,通过这个代理服务器帮我们向跨域的服务器发送网络请求,然后把响应回来的数据进行返回,从而解决跨域问题。
解决:
1下载这个中间件,专门解决跨域问题;
npm i @nuxtjs/proxy
2在 nuxt.config.js 配置文件中添加对应的模块,并设置代理;
modules: [
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
axios: {
proxy: true
},
proxy: {
// 前端如果遇到 /ajax/movieOnInfoList 请求交给 @nuxtjs/proxy(代理服务器) 向 target 服务发送网络请求
'/ajax/movieOnInfoList': {
target: 'http://m.maoyan.com/ajax/movieOnInfoList?token=',
}
},
3,放在template中,渲染页面,最后结果: