1_EWDEUt0fqsmRgpYGFOOMew.pngNuxt.js是一个基于Vue.js的通用应用架构, 它预设了服务端渲染(SSR, Server Side Render)应用所需要的相关配置, 同时也支持生成静态站点.
1. 背景 & Nuxt简介
Nuxt
其一目的是为了解决单页面应用的SEO
问题, 相比于我们平常的SPA
页面. 在搜索引擎中由于无法从网页中被抓取内容信息(SPA页面的信息都是被打包到JS文件中,动态加载到页面中), 从而无法被用户所搜索到.
其二是服务端渲染相比于SPA页面渲染,在网络环境较差或者客户端运行在没有JavaScript的引擎上, 这时基于SSR渲染
的页面能更好的展现原有的页面的内容,而单页面应用可能就会有很长的空白时间, 从而影响到用户的体验.
2. Nuxt应用架构
ujs-architecture.jpg- 客户端向服务器请求数据
- 服务器端获取数据从API服务器
- 服务端返回完整HTML页面给客户端
- 客户端页面渲染使用SPA
- 客户端直接请求API服务器
3. 项目创建
为了更加方便快速的创建项目, Nuxt.js 团队提供了一个脚手架工具 create-nuxt-app.确保你已经安装 npx
(npx 已经被内置自 NPM 5.2.0)
$ npx create-nuxt-app <project-name>
它会让你进行一些选择:
- 在集成的服务器端框架之间进行选择:
- None(默认服务器)
- Express
- Koa
- Hapi
- Feathers
- Micro
- Adonis
- 选择您喜欢的UI框架:
- None
- Bootstrap
- Vuetify
- Bulma
- Tailwind
- Element UI
- Ant Design Vue
- Buefy
- 选择你想要的Nuxt模式(universal or SPA)
- 选择axios module
- 选择 Eslint
- 选择 Prettier
当运行完成时,它将安装所有依赖项,完成后启动项目:
$ npm run dev
应用现在会运行在 http://localhost:3000
4. 项目开发
4.1 目录结构
WX20181218-115512.png- api: api接口
- assets:静态资源
- components:组件
- layouts: 布局目录
- logs: 日志
- middleware:中间件
- pages: 页面目录
- plugins:插件
- nuxt.config.js: nuxt 配置文件
4.2 配置
Nuxt.js默认的配置涵盖了大部分的使用情形, 也可以通过修改 nuxt.config.js
来进行自定义配置.
- plugins: 全局引入的插件
- css: 全局引入的css, scss 等
- head: 可以设置pages的头部信息, 如titile, meta信息等
- loading:页面切换的时候加载组件显示的进度条
- build: 自定义webpack的构建配置
- env: 配置客户端和服务端共享的环境变量
- cache:是否允许缓存
- router:自定义配置vue-router的信息
4.3 路由
WX20181218-151044@2x.pngNuxt.js 会根据
pages
的目录结构, 自动生成vue-router
模块的路由配置. 如上图, 会生成 /dashboard/h5/:h5
, /dashboard/mws/:mws
, ...可以看出路径根据目录结构自动生成了, 动态路径需要在名字前添加下划线( _ )
4.4 布局
nuxt-views-schema.png上图是Nuxt.js的布局架构. 最外层依旧是Document
, 往里一层是一个layout
层,在 Nuxt里面对应目录中的layouts文件夹,默认的pages下的页面都会套用 layouts/default.vue
的布局样式. 其中 <nuxt/> 相当于Vue
中的 slot
插槽的概念,
pages/**.vue的内容都会被填入<nuxt/>,其他的内容嵌套和平时的Vue单页面应用开发是一样的.
4.5 Vuex
在根目录创建 store 目录,就会默认引用 vuex 模块,除此之外,还进行了以下的操作:1)将 vuex 模块 加到 vendors 构建配置中去;2)设置 Vue 根实例的 store 配置项.
Nuxt.js 支持两种使用 store 的方式:
- 普通方式:
store/index.js
返回一个Vuex.Store
实例 - 模块方式:store 目录下的每个 .js 文件会被转换成为状态树指定命名的子模块 (当然,index 是根模块,相当于设置了namespaced: true)
Nuxt.js提供了模块方式的简单写法:使用状态树模块化的方式,store/index.js 不需要返回 Vuex.Store
实例,直接将 state
、mutations
和 actions
暴露出来即可。示例如下:
export const state = () => ({
accesstoken: ''
})
export const mutations = {
setAccesstoken (state, accesstoken) {
state.accesstoken = accesstoken
}
}
4.6 异步数据 asyncData
Nuxt.js 增加了一个 asyncData
方法,用于 在设置组件数据 之前 能够异步获取 或 处理数据。
由于asyncData
是在组件 初始化 之前被调用的,所以不能通过 this
引用组件的实例对象,可以使用上下文对象来实现某些功能,具体的上下文context
4.7 fetch 方法
与 asyncData
方法类似,不同的是它不会设置组件的数据,作用是设置store
数据。
5. Nuxt 渲染流程
nuxt-schema.png上图是nuxt整个的渲染流程,在render
之前的几个阶段, 都可以拿到context
去做一些相应操作.
-
nuxtServerInit
是Nuxt.js在服务端初始化的时候定义在store中.这个对我们想要直接传递值给服务端非常有用,比如session, user. -
middleware
是一个自定义的方法,在每次渲染页面之前被调用.它可以注册到全局下(nuxt.config.js
)也可以注册在单个页面或框架上. -
validate
允许在动态路由组件中定义一个过滤器方法. -
asyncDate,fetch
asyncData可以让我们在页面绘制前调用方法获取需要的数据源;第一次时在服务端会被调用,之后客户端也会在页面之前被调用.fetch
和asyncData
非常相似,区别只在于fetch
只会用来改变store
的状态,不能填充数据. *需要的一点.如果在方法中调用this
会报错.因为asyncData & fetch
在服务端会被调用所以this
的当前组件并没有实例化 -
Render
被渲染
6. 一些遇到的坑
-
Window 或 Document 对象未定义?
这是因为一些只兼容客户端的脚本被打包进了服务端的执行脚本中去。 对于只适合在客户端运行的脚本,需要通过使用 process.browser 变量来判断导入.
-
服务端渲染v-for 列表
当页面有列表内容在客户端渲染,刷新页面服务端会重复渲染列表结构,生成两份. 需要用
<no-ssr/>
组件进行设置,从而不在无武器渲染中呈现
网友评论