Nuxt.js 基础入门教程
Vue 开发一个单页面应用,相信很多前端工程师都已经学会了,但是单页面应用有一个致命的缺点,就是 SEO 极不友好。除非,vue 能在服务端渲染(ssr)并直接返回已经渲染好的页面,而并非只是一个单纯的 <div id="app"></div>。
Nuxt.js 就是一个极简的 vue 版的 ssr 框架。基于它,我们可以快速开发一个基于 vue 的 ssr 单页面应用。
安装
Nuxt.js 官方提供了一个模板,可以使用 vue-cli 直接安装。
```$ vue init nuxt-community/starter-template <project-name>
```
目录结构
.
├── README.md
├── assets
├── components
├── layouts
├── middleware
├── node_modules
├── nuxt.config.js
├── package.json
├── pages
├── plugins
├── static
├── store
└── yarn.lock
其中:
- assets: 资源文件。放置需要经过 webpack 打包处理的资源文件,如 scss,图片,字体等。
- components: 组件。这里存放在页面中,可以复用的组件。
- layouts: 布局。页面都需要有一个布局,默认为 default。它规定了一个页面如何布局页面。所有页面都会加载在布局页面中的
<nuxt />标签中。如果需要在普通页面中使用下级路由,则需要在页面中添加<nuxt-child />。该目录名为Nuxt.js保留的,不可更改。 - middleware: 中间件。存放中间件。可以在页面中调用:
middleware: 'middlewareName'。 pages: 页面。一个 vue 文件即为一个页面。index.vue 为根页面。
- 若需要二级页面,则添加文件夹即可。
- 如果页面的名称类似于
_id.vue(以_开头),则为动态路由页面,_后为匹配的变量(params)。 - 若变量是必须的,则在文件夹下建立空文件
index.vue。更多的配置请移步至 官网 。
- plugin: 插件。用于组织那些需要在
根vue.js应用实例化之前需要运行的 Javascript 插件。需要注意的是,在任何 Vue 组件的生命周期内, 只有beforeCreate和created这两个钩子方法会在 客户端和服务端均被调用。其他钩子方法仅在客户端被调用。 - static: 静态文件。放置不需要经过 webpack 打包的静态资源。如一些 js, css 库。
- store: 状态管理。具体使用请移步至 官网。
- nuxt.config.js:
nuxt.config.js文件用于组织Nuxt.js 应用的个性化配置,以便覆盖默认配置。具体配置请移步至 官网。
Nuxt 特有函数
首先,了解一下在 nuxt 的页面中独有的函数/变量:
asyncData(context)
asyncData方法使得你能够在渲染组件之前异步获取数据。该方法在服务端中执行的,所以,请求数据时,不存在跨域问题。返回的数据将与 data() 返回的数据进行合并。由于asyncData方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象。
context 变量的可用属性一览:
| 属性字段 | 类型 | 可用 | 描述 |
|---|---|---|---|
isClient |
Boolean | 客户端 & 服务端 | 是否来自客户端渲染 |
isServer |
Boolean | 客户端 & 服务端 | 是否来自服务端渲染 |
isDev |
Boolean | 客户端 & 服务端 | 是否是开发(dev) 模式,在生产环境的数据缓存中用到 |
route |
vue-router 路由 | 客户端 & 服务端 |
vue-router 路由实例。 |
store |
vuex 数据流 | 客户端 & 服务端 |
Vuex.Store 实例。只有vuex 数据流存在相关配置时可用。
|
env |
Object | 客户端 & 服务端 |
nuxt.config.js 中配置的环境变量, 见 环境变量 api
|
params |
Object | 客户端 & 服务端 | route.params 的别名 |
query |
Object | 客户端 & 服务端 | route.query 的别名 |
req |
http.Request | 服务端 | Node.js API 的 Request 对象。如果 nuxt 以中间件形式使用的话,这个对象就根据你所使用的框架而定。nuxt generate 不可用。 |
res |
http.Response | 服务端 | Node.js API 的 Response 对象。如果 nuxt 以中间件形式使用的话,这个对象就根据你所使用的框架而定。nuxt generate 不可用。 |
redirect |
Function | 客户端 & 服务端 | 用这个方法重定向用户请求到另一个路由。状态码在服务端被使用,默认 302。redirect([status,] path [, query])
|
error |
Function | 客户端 & 服务端 | 用这个方法展示错误页:error(params)。params 参数应该包含 statusCode 和 message 字段。 |
fetch(context)
fetch 方法用于在渲染页面前填充应用的状态树(store)数据, 与 asyncData 方法类似,不同的是它不会设置组件的数据。为了让获取过程可以异步,你需要返回一个 Promise,Nuxt.js 会等这个 promise 完成后再渲染组件。
fetch 会在组件每次加载前被调用(在服务端或切换至目标路由之前)。
head
Nuxt.js 使用了 vue-meta 更新应用的 头部标签(Head) 和 html 属性。
用于更新 头部信息。如 title,descripe 等。在 head 方法里可通过 this 关键字来获取组件的数据。
layout
指定该页面使用哪个布局文件。默认值为 default。
middleware
需要执行的中间件,如鉴权的 auth等。
transition
指定页面切换时的动画效果。支持传入 String, Object, Function。具体配置请移步至 官网 。
validate
Nuxt.js 可以让你在动态路由对应的页面组件中配置一个校验方法用于校验动态路由参数的有效性。
返回 true 说明路由有效,则进入路由页面。返回不是 true 则显示 404 页面。
Begin Coding
前置工作
API
在这里,我们使用 CNode API 进行开发 Demo.
axios
请求数据,我们使用 Nuxt 官方提供的 @nuxtjs/axios 安装后,在 nuxt.config.js 中加上:
export default {
...
modules: [
'@nuxtjs/axios'
],
axios: {
baseURL: 'https://cnodejs.org/api/v1',
// or other axios configs.
}
...
}
就可以在页面中通过 this.$axios.$get 来获取数据,不需要在每个页面都单独引入 axios.
scss
需要先安装 sass-loader 和 node-sass
```$ yarn add sass-loader node-sass --dev
```
如果需要在项目中全局使用某个 scss 文件(如 mixins, vars 等),需要借助 sass-resources-loader : yarn add sass-resources-loader —dev, 还需要在 nuxt.config.js 的 build 配置中调整导出的 loader 配置:
export default {
...
build: {
extend(config, { isDev, isClient }) {
const sassResourcesLoader = {
loader: 'sass-resources-loader',
options: {
resources: [
// 填写需要全局注入 scss 的文件。引入后,所有页面均有效。
'assets/styles/mixins.scss'
]
}
}
// 修改 scss sass 引用的 loader。
config.module.rules.forEach((rule) => {
if (rule.test.toString() === '/\\.vue$/') {
rule.options.loaders.sass.push(sassResourcesLoader)
rule.options.loaders.scss.push(sassResourcesLoader)
}
if (['/\\.sass$/', '/\\.scss$/'].indexOf(rule.test.toString()) !== -1) {
rule.use.push(sassResourcesLoader)
}
})
}
}
...
}
首页
首页一般只需要简单的获取首页数据并渲染即可。
主要 代码:
asyncData({app, query}) {
console.log(query)
// 根据不用的标签获取不同的数据,最后返回话题列表。
return app.$axios.$get(`topics?tab=${query.tab || ''}`).then(res => {
// console.log(res)
// console.log(JSON.parse(res))
return {list: res.data}
})
}
当进入首页时,该函数会被执行, nuxt 会等到获取数据后再和组件的 data 合并,进而渲染数据。在模板中,可以直接使用 list 变量获取数据。
<div class="card fluid topic" v-for="topic in list" :key="topic.id" >
<div class="section">
<h2><nuxt-link :to="{name: 'topic-id', params: {id: topic.id}}" class="topic-title">{{topic.title}}</nuxt-link></h2>
<p class="topic-info">
<mark v-if="topic.top" class="tertiary">精华</mark>
<mark v-else>{{tabsObj[topic.tab]}}</mark>
<span class="avatar">
<img :src="topic.author.avatar_url" alt="">
</span>
<span class="username">
{{topic.author.loginname}}
</span>
</p>
</div>
</div>
在这里提及一下, <nuxt-link /> 和 <a /> 的区别是: nuxt-link 走的是 vue-router 的路由,即网页已为单页面,并且浏览器不会重定向。而 a 标签走的是 window.location.href,每一次点击 a 标签后的页面,都会进行一次服务端渲染,和普通的 PHP 混合开发没有太大的区别。
在这里使用了 nuxt-link 是因为 CNode 的 API 不存在跨域问题,因此可以作为一个单页面应用,体验更好。
因为列表页数据类型有多种,该页面可能会被复用,所以当路由对象发生变化时,需要重新获取数据,这时可以监听路由的变化以做出响应:
watch: {
'$route': function() {
console.log('$route has changed.')
this.getData()
}
}
配置 seo 优化(这里只是单纯的复制罢了,demo 使用,侵删):
head() {
return {
title: '首页' + (this.$route.query.tab ? `- ${this.tabsObj[this.$route.query.tab]}` : ''),
meta: [{
hid: 'description',
name: 'description',
content: 'CNode:Node.js专业中文社区'
}]
}
}
话题详情
同样的,使用 asyncData 函数进行获取数据,再渲染页面。
asyncData({app, params}) {
console.log(params)
return app.$axios.$get('topic/' + params.id).then(res => {
// let data = res.data instanceof String ? JSON.parse(res.data) : res.data
let data = res.data
// console.log(res)
// let div = document.createElement('div')
// div.innerHTML = res.data.data.content
// res.data.summary = div.innerText.substr(0, 120)
data.summary = data.content.replace(/<[^>]+>/g,"").substr(0, 120).replace(/\s+/g, '')
return {detail: data}
}).catch(err => {
console.log('axios.get failed.')
console.error(err)
})
}
在这里,踩过坑。想使用 div 的 innerText 来过滤掉正文中的 HTML 标签,但是,如果用户是直接进入这个页面的时候,执行 asyncData 时,document 对象是不存在的,从而会报错。也就是说,当 asyncData 在服务端执行时,是没有 document 和 window 对象的,请大家注意一下。
作为一个社区,seo 尤为重要,倘若每个页面都需要写一大堆的 head 对象,就会显得尤其的繁琐。所以可以借助 nuxt 的 plugin 机制,将其封装成一个函数,并注入到每一个页面当中:
// plugins/global.js
import Vue from 'vue'
Vue.mixin({
methods: {
// 必传 标题,描述。其他的 meta 标签通过 payload 注入,其中,每个 meta 的 hid 需要是唯一的。
$seo(title, content, payload = []) {
return {
title,
meta: [{
hid: 'description',
name: 'description',
content
}].concat(payload)
}
}
}
})
在 nuxt.config.js 中加上:
export default {
plugins: [
'~plugins/global.js'
]
}
这样,只需要在页面的 head 的函数中,返回该函数即可:
head() {
return this.$seo(this.detail.title, this.detail.summary)
}

可见,详情页已经成功的设置了部分 seo 的标签。
以上是 Nuxt 的一些基础配置及应用。
我再去研究一下, fetch 和 store 的结合,将该 demo 继续完善。
Nuxt.js 基础入门教程的更多相关文章
- ECMAScript 6.0基础入门教程
ECMAScript 6.0基础入门教程 转:https://blog.csdn.net/hexinyu_1022/article/details/80778727 https://blog.csdn ...
- Vue-Router 基础入门教程
Vue-Router 基础入门教程 前言 这周的计划是用VUE将之前的小demo的前端给重构了,并且做成前后端分离的样式,因为之前的那个聊天室的demo几乎都是在一个路由上完成的,所以学习Vue-ro ...
- [置顶] IOS 基础入门教程
IOS 基础入门教程 教程列表: IOS 简介 IOS环境搭建 Objective C 基础知识 创建第一款iPhone应用程序 IOS操作(action)和输出口(Outlet) iOS - 委托( ...
- Python基础入门教程
Python基础入门教程 Python基础教程 Python 简介 Python环境搭建 Python 基础语法 Python 变量类型 Python 运算符 Python 条件语句 Python 循 ...
- React Native基础&入门教程:初步使用Flexbox布局
在上篇中,笔者分享了部分安装并调试React Native应用过程里的一点经验,如果还没有看过的同学请点击<React Native基础&入门教程:调试React Native应用的一小 ...
- Linux基础入门教程
Linux基础入门教程 --------- Linux学习路径 Linux学习者,常常不知道自己改怎么学习linux:Linux初级,也就是入门linux前提是需要有一些计算机硬件相关的知识或是有一下 ...
- Mongodb最基础入门教程
Mongodb最基础入门教程 如果想了解一下redis的入门教程,可以去看一下我的上一篇博客 Mongodb的安装大家可以参考一下其他博主的博客,这里我就不做介绍了.不过值得注意的是,在Linux ...
- 1.0 Android基础入门教程
1.0 Android基础入门教程 分类 Android 基础入门教程 本教程于2015年7月开始撰写,耗时半年,总共148节,涵盖了Android基础入门的大部分知识,由于当时能力局限,虽已竭尽全力 ...
- JS基础入门篇(三十五)—面向对象(二)
如果没有面向对象这种抽象概念的小伙伴,建议先看一下我写的JS基础入门篇(三十四)-面向对象(一)
随机推荐
- Java中只有按值传递,没有按引用传递!(两种参数情况下都是值传递)
今天,我在一本面试书上看到了关于java的一个参数传递的问题: 写道 java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? 我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这 ...
- 让最新的 Android Q Beta 3 强制重启的 Project Mainline,到底是什么?
一. 序 最新的 Android 版本 Q,已经发布了 Android Q Beta 3,虽然没有正式发布,但是不少用户已经加入了测试计划,抢先体验 Android Q 的新功能. 近期不少体验用户反 ...
- asp.net web 开发中配置web.config
一.配置数据库连接字符串 <connectionStrings> <add name="CaoLPractise" connectionString=" ...
- shell脚本之前的基础知识
日常的linux系统管理工作中必不可少的就是shell脚本,如果不会写shell脚本,那么你就不算一个合格的管理员.目前很多单位在招聘linux系统管理员时,shell脚本的编写是必考的项目.有的单位 ...
- JSTL截取字符串以及格式化时间
fn函数里面有很多好用的方法 <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions& ...
- TX Text Control X10独家揭秘之使用对象作为数据源
文档处理控件TX Text Control即将发布的X10版本,将升级重点还是放到了其比较优势的流式布局报表设计和生成上.慧都获得了来自其开发商Text Control GmbH公司的一手资料,迫不及 ...
- JS案例练习 — 给div添加样式选择功能
附加效果图: CSS内容: <style> ; padding:0px} li{list-style:none} body{font:24px 'Microsoft YaHei'; col ...
- 【MFC】0xC0000005: 读取位置 0x00000020 时发生访问冲突
原因:使用GetDlgItem()函数时需要先判断指针然后才可以使用. 错误代码: //重新建一个线程,查询帧同步 DWORD WINAPI SCsync_Thread(LPVOID Lparam) ...
- Reduce侧连接
1.reduce side join 在reduce端进行表的连接,该方法的特点就是操作简单,缺点是map端shffule后传递给reduce端的数据量过大,极大的降低了性能 连接方法: (1)map ...
- python3应用例子01(进度条)
#!/usr/bin/env python# -*- coding:utf-8 -*- import sysimport time def bar(num, total): rate = num / ...