Nuxt.js常见的使用配置

1,842 阅读5分钟

初识

  • Nuxt.js 一个完整的服务器端请求到渲染的流程

配置SEO

  • ssr主要是为了seo,我们可以统一为所有页面配置对应的title,description,也可以单独为每一个页面自定义配置
  • 统一为所有页面配置可以在nuxt.config.js文件中配置如下:
head: {
        title: '我们想要配置的标题',
        meta: [
            { charset: 'utf-8' },
            { hid: 'description', name: 'description', content: process.env.npm_package_description || '' },
        ],
        link: [
            { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
        ]
    },

上面代码中的npm_package_description,事实上是在package.json里面增加如下配置

"description": "携程旅行网是中国领先的在线旅行服务公司,向超过9000万会员提供酒店预订、酒店点评及特价酒店查询、机票预订、飞机票查询、时刻表、票价查询、航班查询、度假预订、商旅管理、为您的出行提供全方位旅行服务。",
  • 单独为某一个页面配置的话,可以在页面对应的vue文件里面增加如下配置:
head() {
    return {
      title: '自定义标题',
      meta: [
        { name: 'description', hid: 'description', content: 'set page desc' }
      ],
      link: [{ rel: 'favicon', href: 'favicon.ico' }]
    }
  },

配置路由

  • 在pages文件夹下新建一个页面程序就会生成对应的路由
  • 可以在.nuxt/router.js 这个文件里面看到自动生成的路由选项
  • layouts文件夹里面一般会放一些模板文件,如果页面使用模板,可如下设置:
export default {
    layout: 'blank'// blank为模板文件的名称
}
  • 我们可以在模板文件里面配置路由,如下代码所示:
<template>
  <div>
    <nuxt-link to="/">首页</nuxt-link>
    <NLink to="/admin">管理</NLink>
    <n-link no-prefetch to="/cart">购物车</n-link>
    <nuxt />
  </div>
</template>
  1. nuxt-link的别名可以为:n-link,NLink,NuxtLink

  2. 默认nuxt.js会启用prefetch在页面空闲的时候预加载其它路由数据,在路由上配置no-prefetch则会禁用预加

  3. 如果要定义动态路由,以下划线作为前缀的 .vue文件或目录会被定义为动态路由,如下所示

  4. 如果要配置嵌套路由

异步数据获取

  • 因为是服务器端渲染,所以要准备服务接口
  1. 首页安装
npm i koa koa-router koa-bodyparser -S
  1. 在根目录下创建server文件夹,并新建api.js,在此文件夹下创建mock接口,并启动mock接口 node server/api
const Koa = require('koa');
const app = new Koa();
const bodyparser = require("koa-bodyparser");
// 配置所有接口的请求前缀是api
const router = require("koa-router")({ prefix: "/api" });
// 设置cookie加密秘钥
app.keys = ["some secret", "another secret"];
// 一些mock 数据
const goods = [
    { id: 1, text: "连衣裙", price: 580 }, { id: 2, text: "衬衣", price: 320 },{ id: 3, text: "睡裙", price: 260 }
];
router.get("/goods", ctx => {
    ctx.body = {
        ok: 1,
        goods
    };
});
router.get("/detail", ctx => {
    ctx.body = {
        ok: 1,
        data: goods.find(good => good.id == ctx.query.id)
    };
});
router.post("/login", ctx => {
    const user = ctx.request.body;
    if (user.username === "admin" && user.password === "123456") {
        // 将token存入cookie
        const token = 'a mock token'; 
        ctx.cookies.set('token', token, { 
            httpOnly: false ,
            expires:new Date('2029-2-12'), // cookie失效时间
            maxAge:1000*60*60*24, 
        }); 
        ctx.body = { ok: 1, token };
    } else {
        ctx.body = { ok: 0 };
    }
});
// 解析post数据并注册路由 
app.use(bodyparser());
app.use(router.routes());
app.listen(8080, () => console.log('服务已启动'))
  1. 安装axios库
npm install @nuxtjs/axios -S
  1. 配置axios,使之成为nuxt模块并可用,在nuxt.config.js配置如下(所有修改nuxt.config.js都需要重启之后才能生效)
    modules: [
        '@nuxtjs/axios', 
    ],
    axios: {
        proxy: true
    },
    proxy: {
        "/api": "http://localhost:8080"
    },
  1. 使用
async asyncData({ $axios, error }) {
    // 运行时间是在组件创建前,这时候this是不能用的
    const { ok, goods } = await $axios.$get('/api/goods')
    if (ok) {
      return { goods }
    }
    // 错误处理  重定向到错误页面
    error({ statusCode: 400, message: '数据查询失败' })
  },

async Data的一些注意事项,官网上说的很清晰:

* ##权限验证

  • 常见的需求,有些页面需要权限控制,这个时候中间键就会起作用了
  • 比方说在middleware文件夹下创建auth,示例代码如下:
export default function ({ route, redirect, store }) { 
    // 上下文中通过store访问vuex中的全局状态
    // 通过vuex中令牌存在与否判断是否登录
    if (!store.state.user.token) {
        redirect("/login?redirect=" + route.path);
    }
}
  • 使用时可以通过单独页面使用,也可以统一使用
  • 如果是统一使用的话,则可以在nuxt.config.js配置如下
router:{
        middleware:[auth]
    },
  • 如果只需要对某几个页面配置的话,则可以在具体页面中使用
export default {
  middleware: ['auth']
}

状态管理

  • 在Nuxt.js根目录下会有store目录,在此目录建立文件,并具名导出state, mutations, getters, actions即可
  • 比方说,我在store目录下建立user.js,示例代码如下所示:
export const state = () => ({
    token: ''
});
export const mutations = {
    SET_TOKEN (state, token) {
        state.token = token;
    }
};
export const getters = {
    isLogin (state) {
        return !!state.token;
    }
};
export const actions = {
    login ({ commit, getters }, u) {
        // 利用nuxt提供inject注入了$login
        // this指向的是当前vue的实例
        return this.$login(u).then(({ token }) => {
            if (token) {
                commit("SET_TOKEN", token);
            }
            return getters.isLogin;
        });
    }
};
  • 解释一下上面示例中this.$login方法是通过插件注入的
  • 就以this.$login来说,在plugin文件夹下创建api-inject.js
export default ({ $axios }, inject) => {
    inject("login", user => {
        return $axios.$post("/api/login", user);
    });
};
  • 创建了login方法还只是其中一步,还需要在nuxt.config.js中配置
    plugins: [
        '@/plugins/api-inject',
    ],
  • 一般来说,添加请求拦截器,附加token,都可以使用plugin来实现,示例代码如下所示:
export default function ({ $axios, store }) {
    // onRequest是$axios模块提供的帮助文档
    $axios.onRequest(config => {
        if (store.state.user.token) {
            config.headers.Authorization = "Bearer " + store.state.user.token;
        }
        return config;
    });
}

登录后下次刷新还能保留登录状态

  1. 安装依赖模块:cookie-universal-nuxt
npm i -S cookie-universal-nuxt
  1. 配置 nuxt.config.js模块
    modules: [
        "cookie-universal-nuxt",
    ],
  1. store的根模块中定义 nuxtServerInit 方法,将服务端的一些数据传到客户端
export const actions = {
    // nuxtServerInit必须声明在根模块当中
    // 参数一是action上下文   参数二是组件上下文
    nuxtServerInit ({ commit }, { app }) {
        const token = app.$cookies.get("token");
        if (token) {
            commit("user/SET_TOKEN", token);
        }
    }
};

配置雪碧图

  1. 因为我这边css用的是scss,安装对应的loader
npm install -D sass-loader node-sass
  1. 自动把小图标合成雪碧图使用webpack-spritesmith
npm install --save-dev webpack-spritesmith
  1. 在nuxt.config.js文件中配置
    build: {
        extractCSS: { allChunks: true },
        /*
        ** You can extend webpack config here
        */
        extend (config, ctx) {
            //如果是开发环境而且在客户端中执行
            if (ctx.isDev && ctx.isClient) {
                // 雪碧图插件
                let path = require('path');
                let SpritesmithPlugin = require('webpack-spritesmith');
                // 雪碧图处理模板
                let templateFunction = function (data) {
                    let shared = '.icon { display:inline-block; background-image: url(I); background-size:WSMpx HSMpx; }'
                        .replace('I', data.sprites[0].image)
                        .replace('WSM', data.spritesheet.width)
                        .replace('HSM', data.spritesheet.height);

                    let perSprite = data.sprites.map(function (sprite) {
                        return '.icon-N { width: Wpx; height: Hpx; background-position: Xpx Ypx; }'
                            .replace('N', sprite.name)
                            .replace('W', sprite.width)
                            .replace('H', sprite.height)
                            .replace('X', sprite.offset_x)
                            .replace('Y', sprite.offset_y);
                    }).join('\n');

                    return shared + '\n' + perSprite;
                };
                // 雪碧图扩展webpack配置
                config.resolve.modules.push('./assets/img');  //css在哪里能找到sprite图
                config.plugins.push(
                    new SpritesmithPlugin({
                        src: {
                            cwd: path.resolve(__dirname, './assets/img/spr/'), // 图标根路径
                            glob: '**/*.png' // 匹配任意 png 图标
                        },
                        target: {
                            image: path.resolve(__dirname, './assets/img/spr.png'), // 生成雪碧图目标路径与名称
                            // 设置生成CSS背景及其定位的文件或方式
                            css: [
                                [path.resolve(__dirname, './assets/scss/spr.scss'), {
                                    format: 'function_based_template'
                                }]
                            ]
                        },
                        customTemplates: {
                            'function_based_template': templateFunction,
                        },
                        apiOptions: {
                            cssImageRef: "~assets/img/spr.png", // css文件中引用雪碧图的相对位置路径配置
                        },
                        spritesmithOptions: {
                            padding: 10,
                        }
                    })
                )
            }
        }
    }
  1. 使用:
  • 在 assets>img 目录下新建 spr 文件夹,把要用到的图标都放到此文件夹里面
  • 页面上使用时,引入对应的css
<style lang="scss">
@import '../assets/scss/spr.scss'; //引入方式
</style>
  • 使用图标很简单,图标的类名跟图标的文件名一致就行了,示例代码如下所示:
<i class="icon icon-huawei_hover"></i>

示例源码可见:git hub 源码

具体配置可见官网 Nuxt.js官网

最后

如果你觉得这篇文章不错,请别忘记点个关注哦~😊