创建nuxt项目
英文官网地址:https://zh.nuxtjs.org/
中文官网地址:https://www.nuxtjs.cn/
github上的一个基于nuxt的服务端渲染项目:https://github.com/Sandop/NuxtPC
创建一个nuxt项目:确保安装了npx(npx在NPM版本5.2.0默认安装了):
npx create-nuxt-app nuxtDemo
之后会让选择ui框架,服务器什么的,我选择的element-ui和express服务器,我喜欢做spa项目,就选择了搭建一个spa项目(后面才发现,用nuxt的目的是解决seo的问题,就不要用spa模式了,用这个框架就用那个universal模式就行)
安装之后,生成项目目录如下,无选择的spa页面
和vue-cli相似
cd到创建好的项目,npm run dev 运行项目
assets:资源目录:放置用于组织未编译的静态资源如 LESS
、SASS
或 JavaScript
。
components:组件目录
layouts:布局目录,刚创建项目自带一个default.vue的自定义目录,什么内容都没有,就放了个<nuxt/>视图容器,这是所有组件页面都默认的布局,当然可以自定义布局,可以在具体页面通过layout指定页面使用的布局
middleware:中间件目录
pages:页面目录,nuxt会根据这个文件目录自动生成路由!!
plugins:插件目录,根vue.js应用
实例化之前需要运行的 Javascript 插件。
static:静态文件目录,用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。 服务器启动的时候,该目录下的文件会映射至应用的根路径 /
下
store:Store目录,用于组织应用的 Vuex 状态树 文件。 Nuxt.js 框架集成了 Vuex 状态树 的相关功能配置,在 store
目录下创建一个 index.js
文件可激活这些配置。
nuxt.config.js :用于组织Nuxt.js 应用的个性化配置,以便覆盖默认配置。
package.json:用于描述应用的依赖关系和对外暴露的脚本接口。
配置:
Nuxt.js 默认的配置涵盖了大部分使用情形,可通过 nuxt.config.js 来覆盖默认的配置。
配置文档:https://zh.nuxtjs.org/guide/configuration
路由:
文档地址:https://zh.nuxtjs.org/guide/routing
Nuxt.js 依据 pages
目录结构自动生成 vue-router 模块的路由配置。
要在页面之间使用路由,我们建议使用<nuxt-link>
标签。
视图:
模板
定制化默认的 html 模板,只需要在应用根目录下创建一个 app.html
的文件。
默认模板为:可以在模板中添加ie条件表达式
<!DOCTYPE html> <html {{ HTML_ATTRS }}> <head {{ HEAD_ATTRS }}> {{ HEAD }} </head> <body {{ BODY_ATTRS }}> {{ APP }} </body> </html>
布局
默认布局是创建项目时自动生成的layouts/default.vue
layouts
目录中的每个文件 (顶级) 都将创建一个可通过页面组件中的 layout
属性访问的自定义布局。
错误页面:
你可以通过编辑
layouts/error.vue
文件来定制化错误页面.
这个布局文件不需要包含 <nuxt/>
标签。你可以把这个布局文件当成是显示应用错误(404,500等)的组件。
举一个个性化错误页面的例子 layouts/error.vue
:
<template> <div class="container"> <h1 v-if="error.statusCode === 404">页面不存在</h1> <h1 v-else>应用发生错误异常</h1> <nuxt-link to="/">首 页</nuxt-link> </div> </template> <script> export default { props: ['error'], layout: 'blog' // 你可以为错误页面指定自定义的布局 } </script>
页面:
页面组件实际上是 Vue 组件,只不过 Nuxt.js 为这些组件添加了一些特殊的配置项(对应 Nuxt.js 提供的功能特性)以便你能快速开发通用应用。
HTML 头部:
Nuxt.js 使用了 vue-meta
更新应用的 头部标签(Head)
and html 属性
。
Nuxt.js 允许你在 nuxt.config.js
里定义应用所需的所有默认 meta 标签,在 head
字段里配置就可以了:
一个使用自定义 viewport
和 谷歌字体
的配置示例:
head: { meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' } ], link: [ { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto' } ] }
当然也可以引入jquery、bootstrap等第三方库
引入第三方库,有npm引入方式和CDN引入方式两种,可以自己选择,我一般用CDN引入第三方库,有利于减少项目体积;
异步数据
Nuxt.js 扩展了 Vue.js,增加了一个叫 asyncData
的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据。
asyncData 方法:
https://zh.nuxtjs.org/guide/async-data/
asyncData
方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。 在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你可以利用 asyncData
方法来获取数据,Nuxt.js 会将 asyncData
返回的数据融合组件 data
方法返回的数据一并返回给当前组件。
注意:由于asyncData
方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this
来引用组件的实例对象。
此方法是服务端渲染的关键之一,它是在组件初始化之前调用的,方法的第一个参数是上下文对象,里面包括好多对象,如store,res,req,params,query,isDev,route,redirect,error等很有用的信息供我们使用;在这个方法内,要return出一个对象,这个对象会和data合并,能够直接绑定到模板中,作用方面和data是一样的;记住,这里面的有数据完成后才会初始化组件,这个很重要,一些DOM操作就不要在这个方法中进行了,因为这个方法进行的时候,还没有DOM,主要用于拿到初始数据就行。
资源文件
默认情况下 Nuxt 使用 vue-loader、file-loader 以及 url-loader 这几个 Webpack 加载器来处理文件的加载和引用。对于不需要通过 Webpack 处理的静态资源文件,可以放置在 static
目录中。
静态文件
如果你的静态资源文件需要 Webpack 做构建编译处理,可以放到 assets
目录,否则可以放到 static
目录中去。
Nuxt 服务器启动的时候,该目录下的文件会映射至应用的根路径 /
下,像 robots.txt
或 sitemap.xml
这种类型的文件就很适合放到 static
目录中。
你可以在代码中使用根路径 /
结合资源相对路径来引用静态资源:
<!-- 引用 static 目录下的图片 --> <img src="/my-image.png"/> <!-- 引用 assets 目录下经过 webpack 构建处理后的图片 --> <img src="~/assets/my-image-2.png"/>
插件
https://zh.nuxtjs.org/guide/plugins
Nuxt.js允许您在运行Vue.js应用程序之前执行js插件。这在您需要使用自己的库或第三方模块时特别有用。
使用第三方模块
我们可以在应用中使用第三方模块,一个典型的例子是在客户端和服务端使用 axios 做 HTTP 请求。略
使用 Vue 插件
假如我们想使用 vue-notifications 显示应用的通知信息,我们需要在程序运行前配置好这个插件。
安装:npm install --save vue-notification
首先增加文件 plugins/vue-notifications.js
:
import Vue from 'vue' import VueNotifications from 'vue-notification' Vue.use(VueNotifications)
然后, 在 nuxt.config.js
内配置 plugins
如下:
module.exports = { plugins: ['~/plugins/vue-notifications'] }
使用:
在vue文件中:
<notifications group="foo" />
this.$notify({ group: 'foo', title: 'Important message', text: 'Hello user! This is a notification!' });
效果:
ES6 插件
如果插件位于node_modules
并导出模块,需要将其添加到transpile
构建选项:
module.exports = { build: { transpile: ['vue-notifications'] } }
注入 $root 和 context
有时您希望在整个应用程序中使用某个函数或属性值,此时,你需要将它们注入到Vue实例(客户端),context(服务器端)甚至 store(Vuex)。按照惯例,新增的属性或方法名使用$
作为前缀。
注入 Vue 实例
plugins/vue-inject.js
:
import Vue from 'vue'
Vue.prototype.$myInjectedFunction = string => console.log('This is an example', string)
nuxt.config.js
:
export default { plugins: ['~/plugins/vue-inject.js'] }
这样,您就可以在所有Vue组件中使用该函数。
这样,您就可以在所有Vue组件中使用该函数。
export default { mounted () { this.$myInjectedFunction('test') } }
注入 context
context注入方式和在其它vue应用程序中注入类似。
plugins/ctx-inject.js
:
export default ({ app }, inject) => { // Set the function directly on the context.app object app.myInjectedFunction = string => console.log('Okay, another function', string) }
nuxt.config.js
:
export default { plugins: ['~/plugins/ctx-inject.js'] }
现在,只要您获得context,你就可以使用该函数(例如在asyncData
和fetch
中)。 ctx-example-component.vue
:
export default { asyncData (context) { context.app.myInjectedFunction('ctx!') } }
同时注入
如果您需要同时在context
,Vue
实例,甚至Vuex
中同时注入,您可以使用inject
方法,它是plugin导出函数的第二个参数。 将内容注入Vue实例的方式与在Vue应用程序中进行注入类似。系统会自动将$
添加到方法名的前面。
plugins/combined-inject.js
:
export default ({ app }, inject) => { inject('myInjectedFunction', string => console.log('That was easy!', string)) }
nuxt.config.js
:
export default { plugins: ['~/plugins/combined-inject.js'] }
现在您就可以在context
,或者Vue
实例中的this
,或者Vuex
的actions/mutations
方法中的this
来调用myInjectedFunction
方法。 ctx-example-component.vue
:
export default { mounted () { this.$myInjectedFunction('works in mounted') }, asyncData (context) { context.app.$myInjectedFunction('works with context') } }
store/index.js
:
export const state = () => ({ someValue: '' }) export const mutations = { changeSomeValue (state, newValue) { this.$myInjectedFunction('accessible in mutations') state.someValue = newValue } } export const actions = { setSomeValueToWhatever ({ commit }) { this.$myInjectedFunction('accessible in actions') const newValue = 'whatever' commit('changeSomeValue', newValue) } }
只在客户端使用的插件
不支持ssr的系统,插件只在浏览器里使用,这种情况下下,你可以用 ssr: false
,使得插件只会在客户端运行。
举个例子:
nuxt.config.js
:
module.exports = { plugins: [ { src: '~/plugins/vue-notifications', ssr: false } ] }
plugins/vue-notifications.js
:
import Vue from 'vue' import VueNotifications from 'vue-notification' Vue.use(VueNotifications)
例子:
nuxt.config.js
:
export default { plugins: [ { src: '~/plugins/both-sides.js' }, { src: '~/plugins/client-only.js', mode: 'client' }, { src: '~/plugins/server-only.js', mode: 'server' } ] }
传统命名插件
如果假设插件仅在 客户端 或 服务器端 运行,则 .client.js
或 .server.js
可以作为插件文件的扩展名应用,该文件将自动包含在相应客户端或者服务端上。
例子:
nuxt.config.js
:
export default { plugins: [ '~/plugins/foo.client.js', // only in client side '~/plugins/bar.server.js', // only in server side '~/plugins/baz.js' // both client & server ] }
模块
https://zh.nuxtjs.org/guide/modules
模块是Nuxt.js扩展,可以扩展其核心功能并添加无限的集成。
模块列表: https://github.com/topics/nuxt-module
有兴趣可以看一下,比较深奥,不适合初级开发者
Vuex 状态树
对于每个大项目来说,使用状态树 (store) 管理状态 (state) 十分有必要。这就是为什么 Nuxt.js 内核实现了 Vuex。
普通方式
Nuxt.js允许您拥有一个
store
目录,其中包含与模块对应的每个文件。
首先,只需将状态导出为 函数,将变量和操作作为 store/index.js
中的对象导出:
export const state = () => ({ counter: 0 }) export const mutations = { increment (state) { state.counter++ } }
然后,您可以拥有 store/todos.js
文件:
export const state = () => ({ list: [] }) export const mutations = { add (state, text) { state.list.push({ text, done: false }) }, remove (state, { todo }) { state.list.splice(state.list.indexOf(todo), 1) }, toggle (state, todo) { todo.done = !todo.done } }
Vuex将如下创建:
new Vuex.Store({ state: () => ({ counter: 0 }), mutations: { increment (state) { state.counter++ } }, modules: { todos: { namespaced: true, state: () => ({ list: [] }), mutations: { add (state, { text }) { state.list.push({ text, done: false }) }, remove (state, { todo }) { state.list.splice(state.list.indexOf(todo), 1) }, toggle (state, { todo }) { todo.done = !todo.done } } } } })
在您的 pages/todos.vue
中,使用 todos
模块:
。