什么是服务端渲染
前端渲染流程:
前端请求服务器,把html文件以资源的形式返回前端,浏览器拿到html文件解析。
服务器渲染:返回html之前,会先将一些数据填充好到特定区域后再返回给前端,在SPA场景下,服务端渲染都是针对第一次get请求,它会完整的html给浏览器,浏览器直接渲染出首屏,用不着浏览器端多一个AJAX请求去获取数据再渲染。
优点
- 更好的 SEO,因为传统的搜索引擎只会从 HTML 中抓取数据,这会导致前端渲染的页面无法被抓取。
- 更快的内容到达时间(time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备 。
- 页面首屏时间大概有80%消耗在网络上,剩下的时间在后端读取数据以及浏览器渲染,显然要优化后面的20%是比较困难的,优化网络时间是效果最明显的手段。
- 传统的Ajax请求是先请求js再由js发起数据请求,两项时间再加上浏览器渲染时间才是首屏时间。而SSR能将两个请求合并为一个。
缺点
- 更多的服务器端负载。
- 服务器端和浏览器环境差异带来的问题,例如document等对象找不到的问题。
如何选择
建议:如果注重SEO的新闻站点,非强交互的页面,建议用SSR;像后台管理页面这类强交互的应用,建议使用前端渲染。
静态化:把vue文件变成html文件
什么是Nuxt.js
Nuxt.js 是一个基于 Vue.js 的通用应用框架。
第一个Nuxt应用程序
npm i
create-nuxt-app -g
create-nuxt-app my-nuxt-demo
cd my-nuxt-demo
npm run dev
文件结构分析
└─my-nuxt-demo
├─.nuxt // Nuxt自动生成,临时的用于编辑的文件,build
├─assets // 用于组织未编译的静态资源如LESS、SASS或JavaScript,对于不需要通过 Webpack 处理的静态资源文件,可以放置在 static 目录中
├─components // 用于自己编写的Vue组件,比如日历组件、分页组件
├─layouts // 布局目录,用于组织应用的布局组件,不可更改
├─middleware // 用于存放中间件
├─node_modules
├─pages // 用于组织应用的路由及视图,Nuxt.js根据该目录结构自动生成对应的路由配置,文件名不可更改
├─plugins // 用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。
├─static // 用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。 服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。文件夹名不可更改。
└─store // 用于组织应用的Vuex 状态管理。文件夹名不可更改。
├─.editorconfig // 开发工具格式配置
├─.eslintrc.js // ESLint的配置文件,用于检查代码格式
├─.gitignore // 配置git忽略文件
├─nuxt.config.js // 用于组织Nuxt.js 应用的个性化配置,以便覆盖默认配置。文件名不可更改。
├─package-lock.json // npm自动生成,用于帮助package的统一设置的,yarn也有相同的操作
├─package.json // npm 包管理配置文件
├─README.md
页面和路由
nuxt的路由是自动生成的,例如再pages下创建demo.vue,浏览器输入http://localhost:3000/demo即可发文到demo.vue文件。
└─pages
├─index.vue
└─user
├─index.vue
├─demo.vue
Nuxt.js自动生成的路由配置如下
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'user',
path: '/user',
component: 'pages/user/index.vue'
},
{
name: 'demo',
path: '/user/demo',
component: 'pages/user/demo.vue'
}
]
}
页面跳转
- 不要写成a标签,因为是重新获取一个新的页面,并不是SPA
<nuxt-link to="/users"></nuxt-link>
- this.$router.push(’/users’)
- 不能写a标签,a标签相当刷新页面
动态路由
在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录(例如新建_id文件夹,里面再创建一个index.vue),建议目录形式,文件容易出错,文件名可以自定义,但vue文件必须用index不然没效果。
获取动态参数{{$route.params.id}}
路由参数校验
Nuxt.js 可以让你在动态路由对应的页面组件中配置一个validate方法用于校验动态路由参数的有效性。该函数有一个布尔类型的返回值,如果返回true则表示校验通过,如果返回false则表示校验未通过。
注意1,这个validate要写在_id文件夹下面的index.vue文件里而且不能写在methods里,和methods同级即可。返回false就会找不到页面。
注意2,validate这个方法拿不到this 可以用它自带的参数obj解决(可以打印这个obj,但是要在命令行里看不是浏览器)。
export default {
// nuxt中使用validate方法进行路由参数校验,这个方法必须返回一个布尔值,为true表示校验通过,为false表示校验失败。注意validate不能写到methods属性中。
validate(obj) {
// console.log(obj);
// return true
return /^\d+$/.test(obj.params.id)
}
}
嵌套路由
- 添加一个Vue文件,作为父组件
- 添加一个与父组件同名的文件夹来存放子视图组件
- 在父文件中,添加组件,用于展示匹配到的子视图
pages文件夹下创建test.vue 然后创建一个test文件夹,创建_id文件,再创建test.vue
以下是pages文件夹下的test.vue
<template>
<div class=''>
<nuxt-link :to="`/test/${3}`">
<button>todemo</button>
</nuxt-link>
<nuxt-child></nuxt-child>
</div>
</template>
layouts-pages-components
创建layout
- 去layouts文件夹下面新建一个新的layout组件,例如test.vue,并在这个组件中添加组件,这样,所有和test相关的页面都会有公共的layout
- 给需要用到test.vue的组件添加layout属性,并指定需要使用的layout,例如:layout: ‘test’
<script>
import Mynav from '~/components/Mynav'
export default {
// 通过layout属性,指定当前页面使用的布局组件,相当于本组件多了一个header
layout: 'headerlayout',
components: {
Mynav
},
data () {
return {
teacherList: [
{name: 'jack1', id: 1},
{name: 'jack2', id: 2},
{name: 'jack3', id: 3}
]
}
}
}
</script>
名字就是路由名称。
组件nuxt表示显示的页面。因为的组件名是movie,那么它会自动找到pages目录下的moive.vue展示
点击link就会跳转到movie type文件夹的index.vue。
如果路由后还有参数就继续创建文件夹
创建特殊layout-error
layouts文件夹下面新建error.vue,error是关键字,error.vue相当于自定义的404页面。
创建一个组件
在components文件夹下面新建一个Header.vue组件
引入组件,注意路径的~符号,表示根目录
layout中也能使用组件
配置样式
nuxt.config.js中设置设置全局样式文件路径
css: [//~表示当前目录
'~/assets/styles/index.ccs'
],
ElementUI使用
下载npm i element-ui -S
在plugins文件夹下面,创建ElementUI.js文件
import Vue from 'vue'
import ElementUI from 'element-ui'
Vue.use(ElementUI)
在nuxt.config.js中添加配置
css: [ /* 配置全局样式 */
'element-ui/lib/theme-chalk/index.css'
],
plugins: [
/*ssr: true表示这个插件只在服务端起作用*/
{src: '~/plugins/ElementUI', ssr: true }
],
build: {/*防止element-ui被多次打包*/
vendor: ['element-ui', 'axios']
}
异步数据
注意: 在nuxt中,生命周期只有created以及beforeCreate这两个函数能够在服务端正常使用, 在nuxt中发异步请求不能在created生命周期函数中去发,因为它会在前端执行。
Nuxt.js 扩展了 Vue.js,增加了一个叫 asyncData 的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据。asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。所以需要注意这个函数中不能使用this 可以使用asyncData(context, callback)callback获取,注意asyncData(context, callback)是和methods平级的函数。
/*发送异步请求,在asyncData函数中发送*/
asyncData(context, callback) {
console.log(context);
setTimeout(() => {
// callback有两个参数,第一个是错误对象,第二个是数据对象
callback(null, {
movieList: [
{title: 'test1', id: 1},
{title: 'test11', id: 2},
{title: 'test131', id: 3}
]
})
}, 1000);
}
注意:常规写法如果在created钩子中写异步,是在客户端渲染的而不是在服务端
使用方法:asyncData(context, callback) {callback(null, data)}
context.route.params.xxx获取参数
callback(new Error(), data)渲染出错的页面
注意:这个方法在服务器端执行和在客户端执行的区别
axios的使用
安装npm install --save axios
import axios from 'axios'
asyncData(context, callback) {
axios.get('http://localhost:3302/in_test')
.then(res => {
console.log(res);
callback(null, {list: res.data})
})
}
为防止重复打包,在nuxt.config.js中配置
module.exports = {
build: {
vendor: ['axios']
}
}
可以用json-server模拟假数据
- 下载json-server工具:npm i json-server -g
- 可能会报错,用管理员身份运行powershell执行就解决了。
json-server --watch --port 3302 db.json
{
"in_test": [
{
"id": 1,
"title": "黄金兄弟",
"rating": 5.3,
"genres": ["动作", "犯罪"],
"img": "https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2535191502.jpg"
}],
}
SEO优化
SEO优化有俩中,全局和局部
全局
在nuxt.config.js配置文件中修改
head: {
title: pkg.name,
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: pkg.description }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
}
局部
在指定页面加入
<template>
<div class="movie">
<h1>欢迎访问本网站!</h1>
</div>
</template>
<script>
export default {
layout: 'movie',
head() {
return {
title: '电影',
meta: [
{name: 'keywords', content: '电影、经典电影、热映、电视剧、美剧、影评、电影院'}
]
}
}
}
</script>
这些keywords会被搜索引擎抓取到。
最后打包部署
npm run build
把本地文件的.nuxt、static,package.json、nuxt.config.js,这四个文件夹放到服务器目录文件下
npm install
npm start
Nginx配置
server {
listen 80;
server_name 你的域名 你的域名;
location ~ / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Nginx-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_pass http://nodenuxt; #反向代理
}
}
upstream nodenuxt {
server 127.0.0.1:3000; #nuxt项目 监听端口
keepalive 64;
}
pm2开启进程守护
pm2 start npm --name “bigstu” – run start
最后这个域名就能正常访问啦:你的域名
pm2 stop 1 // 先停止
pm2 restart 1 // 再重启