nuxt
安装
vue-init nuxt-community/starter-template dddname
npm install
npm run dev
npm i vue-cli -g
vue init nuxt/starter # 初始化Nuxt.js项目
目录结构
assets资源目录 用于组织未编译的静态资源如LESS/SASS/JScomponents组件目录 用于组织应用的 Vue.js 组件layouts布局目录 用于组织应用的布局组件middleware中间件目录 用于存放应用的中间件pages页面目录 用于组织应用的路由及视图,Nuxt.js框架读取该目录下所有的.vue文件并自动生成对应的路由配置plugins插件目录 用于组织那些需要在根vue.js应用实例化之前需要运行的 js 插件static静态文件目录 用于存放应用的静态文件,此类文件不会被Nuxt.js调用webpack进行构建编译处理。服务器启动的时候该目录下的文件会映射至根路径下store用于组织应用的 Vuex 状态树文件。Nuxt.js框架继承了Vuex状态树的相关功能配置,在store目录下创建一个index.js文件可激活这些配置nuxt.config.js文件用于组织Nuxt.js应用的个性化配置,以便覆盖默认配置。package.json文件用于描述应用的依赖关系和对外暴露的脚本接口
nuxt.config.js
head:对应html中的head标签loading:上方进度条颜色build:build配置,loaders..
配置端口
在package.json中添加
"config": {
"nuxt": {
"host": "127.0.0.1",
"port": "8099"
}
},
配置全局 CSS
/asset/css/normailze.css/nuxt.config.js
css: ['~assets/css/normalize.css'],
配置 webpack 的 loader
在nuxt.config.js里是可以对webpack的基本配置进行覆盖的
build: {
loaders: [
{
test: /\.(png|jpe?g|gif|svg)$/,
loader: "url-loader",
query: {
limit: 10000,
name:"img/[name].[hash].[ext]"
}
}
],
}
路由
Nuxt.js的路由给我们进行了封装,让我们省去了很多配置环节 在/page里新建文件夹,并写入index.vue文件
<nuxt-link to="/">Home</nuxt-link>
<nuxt-link :to="{ name: 'news', params: { newsId: 3 } }">News</nuxt-link>
<nuxt-link to="/about/12">About</nuxt-link>
$route.params.newsId
动态路由
在 news 文件夹下新建_id.vue,以下划线前缀的vue文件就是动态路由,然后可以在该文件用$route.params.xx来接收参数
<nuxt-link to="/news/123">news</nuxt-link>
<nuxt-link to="/news/error">news</nuxt-link>
<nuxt-link :to="{ name: 'news-id', params: { id: 5 } }">News</nuxt-link>
动态参数校验
对参数传递的正确性校验,Nuxt.js准备了校验方法validate(),返回false则进入404页面
export default {
validate({ params }) {
return /^\d+$/.test(params.id)
},
}
路由动画效果
全局路由动画 在/assets/css/a.css,然后配置全局样式
.page-enter-active,
.page-leave-active {
transition: opacity 2s;
}
.page-enter,
.page-leave-active {
opacity: 0;
}
单独设置页面动画效果
- 在全局样式中添加自定义命名的动画样式
.single-enter-active,
.single-leave-active {
transition: all 2s;
font-size: 12px;
}
.single-enter,
.single-leave-active {
opacity: 0;
font-size: 40px;
}
- 在对应 index.vue 页面使用
export default {
transition: 'single',
}
默认模版
Nuxt为我们提供了默认模版定制方法,只要在根目录下创建app.html就可以实现了 {{HEAD}}读取nuxt.config.js里的信息,{{APP}}就是我们写的pages文件夹下的主体页面
<!DOCTYPE html>
<html lang="en">
<head>
{{HEAD}}
</head>
<body>
<p>111 TOP 111</p>
{{APP}}
</body>
</html>
默认布局
默认布局主要针对于页面的统一布局使用,位置在/layouts/default.vue,<nuxt/>为我们每个页面的内容
<template>
<div>
<p>hhhh top</p>
<nuxt />
</div>
</template>
建立错误页面
在/layout文件夹下新建error.vue文件
<template>
<div>
<h2 v-if="error.statusCode === 404">404页面,您需要的页面没有找到</h2>
<h2 v-else>500页面,服务器错误</h2>
</div>
</template>
<script>
export default {
props: ['error'],
}
</script>
meta 设置
需要对每个页面都有不同的title和meta设置,直接使用head方法来设置当前页面的头部信息
data () {
return {
title: 'news'
}
},
head () {
return {
title: this.title,
meta: [
{hid: 'description', name: 'news', content: 'This is news page'}
]
}
}
asyncData 方法获取数据
Nuxt.js添加了asyncData方法在渲染组件之前异步获取数据 由于asyncData方法是在组件初始化前被调用的,所以在方法内是没有办法通过this来引用组件的实例对象
npm install axios -S # 安装axios
import axios from 'axios'
···
asyncData () {
return axios.get('http://xxx.com/api')
.then(res => {
return {info:res.data}
})
}
···
{{info.name}}
现在都使用async...await来解决异步
async asyncData () {
let data = await axios.get('http://xxx.com/api/xx')
return {info:data}
}
静态资源
Nuxt.js提供了根路径~,引用资源时,使用~/static/img
全局引入 Element-UI
- 安装
npm i element-ui -S
- 在
/plugins文件夹新建ElementUI.js文件
import Vue from 'vue'
import ElementUI from 'element-ui'
Vue.use(ElementUI)
- 在
nuxt.config.js中添加配置,把axios.element-ui打包到vendor.js中
plugins: [
{
src: '~/plugins/ElementUI',
ssr: true
}
],
css: ['~assets/css/normalize.css', 'element-ui/lib/theme-chalk/index.css'],
build: {
vendor: ['axios','element-ui']
}
extendRoutes
在nuxt.config.js中通过extendRoutes配置项来扩展Nuxt.js生成的路由配置
router:{
extendRoutes(routes){
routes.push({
name: '',
path: '/login',
component:resolve(__dirname,'pages/login')
})
}
},
SSR
Server Side Render服务端渲染,在没有SPA之前,绝大多数的网页都是通过服务器渲染生成的:用户向服务器发送请求,服务器获取请求,然后再查询数据库,根据查询的数据动态的生成一张一张网页,最后将网页内容返回给浏览器端
no-ssr
<no-srr>xxx</no-srr>
Window 或 Document 对象未定义
if (process.browser) {
require('xxx')
window.xxx = {..}
}
更改当前页的描述 meta 标签
在应用配置文件nuxt.config.js中配置默认meta
module.exports = {
/*
** Headers of the page
*/
head: {
title: 'AAA系统',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'AAAAA系统' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
···
}
在页面中利用 hid 来覆盖指定的meta配置
export default {
head () {
return {
title: '购物车',
meta: [{
hid: 'description', name: 'description', content: '购物车'
}]
}
},
封装 SEO 处理
- 在
plugins目录下新建globalSEO.js
import Vue from 'vue'
Vue.mixin({
methods: {
$seo(title, content, payload = []) {
return {
title,
meta: [
{
hid: 'description',
name: 'description',
content,
},
].concat(payload),
}
},
},
})
- 在
nuxt.congfig.js
plugins: [ '~plugins/globalSEO'],
- 在
pages页面中
head () {
return this.$seo('购物车-在线订货系统' + (!this.$store.state.carTotal ? '' : ' ( '+ this.$store.state.carTotal +' )'),'购物车')
},
server
const { Nuxt, Builder } = require('nuxt')
const opn = require('opn')
const express = require('express')
const app = express()
const host = process.env.HOST || 'localhost'
const port = process.env.PORT || 8089
var bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(
bodyParser.urlencoded({
extended: true,
})
)
app.set('port', port)
// Start nuxt.js
async function start() {
// Import and Set Nuxt.js options
let config = require('../nuxt.config.js')
config.dev = !(process.env.NODE_ENV === 'production')
// Instanciate nuxt.js
const nuxt = await new Nuxt(config)
// Add nuxt.js middleware
app.use(nuxt.render)
// Build in development
if (config.dev) {
try {
const builder = new Builder(nuxt)
await builder.build()
} catch (error) {
// eslint-disable-line no-console
console.error(error)
process.exit(1)
}
}
// Listen the server
app.listen(port, host)
const _url = 'http://' + host + ':' + port
// eslint-disable-line no-console
console.log('Server listening on ' + _url)
opn(_url)
}
start()
Nuxt 部署
nuxt是ssr方式,不能指定静态文件根目录 在根目录新建 .dockerignore
#node_modules
#.nuxt
在根目录新建 Dockerfile
FROM node:8.9.1
MAINTAINER stark.wang
ENV NODE_ENV=production
ENV HOST 0.0.0.0
RUN mkdir -p /app
COPY . /app
WORKDIR /app
EXPOSE 3000
#If the environment in China build please open the following comments
RUN npm config set registry https://registry.npm.taobao.org
RUN npm install
RUN npm run build
CMD ["npm", "start"]
然后在服务端打镜像
# build image
$ docker build -t nuxt-demo .
# serve at localhost:8080
$ docker run -dt -p 8080:3000 nuxt-p
编辑
this.$set()
中间件实现拦截
~/middleware/auth.js
import utils from '~/utils/utils'
export default function ({route, req, res, redirect}) {
let isClient = process.client;
let isServer = process.server;
let redirectURL = '/login';
var token, path
//在服务端
if (isServer) {
let cookies = utils.getcookiesInServer(req)
path = req.originalUrl;
token = cookies.token ? cookies.token : ''
}
//在客户端判读是否需要登陆
if (isClient) {
token = utils.getcookiesInClient('token')
path = route.path;
}
if (path) {
redirectURL = '/login?ref=' + encodeURIComponent(path)
}
//需要进行权限判断的页面开头
if (!token) {
redirect(redirectURL)
}
~/utils/utils
import Cookie from 'js-cookie'
export default {
// 获取服务端cookie
getCookiesInServer: function (req) {
let service_cookie = {}
req &&
req.headers.cookie &&
req.headers.cookie.split(';').forEach((val) => {
let parts = val.split('=')
service_cookie[parts[0].trim()] = (parts[1] || '').trim()
})
return service_cookie
},
// 获取客户端cookie
getCookiesInClient: function (key) {
return Cookie.get(key) ? Cookie.get(key) : ''
},
}
最后运用到项目中, 在nuxt.config.js,全局
router: {
middleware: 'auth'
}
或者单页面pages/user/setting.vue中
export default {
middleware: 'auth',
}
nuxtServerInit
如果在状态树中指定了nuxtServerInit方法,Nuxt.js调用它的时候会将页面的上下文对象作为第2个参数传给它,当我们想将服务端的一些数据传到客户端时,这个方法是非常好用的
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}
fetch
用于在渲染页面前填充应用的状态树数据,与asyncData方法类似,不同的是他不会设置组件的数据
export default {
fetch({ store, redirect }) {
if (!store.state.access_token) {
return redirect('/')
}
},
}
