SSR实战:Nuxt.js

2019-10-21  本文已影响0人  key君

基于vue.js的通用框架
nuxt安装

npx create-nuxt-app <项目名>
选项


image.png

运行项目:npm run dev

整合axios
安装@nuxt/axios模块
npm install @nuxtjs/axios -S
配置
nuxt.config.js

  modules: ["@nuxtjs/axios", "cookie-universal-nuxt"],
  axios: {
    proxy: true,
  },
  proxy: {
    "/api": "http://localhost:8080",
  },

pages/index.vue
配置头
异步数据获取

<template>
  <div>
    <h2>商品列表</h2>
    <ul>
      <li v-for="good in goods" :key="good.id">
        <nuxt-link :to="`/detail/${good.id}`">
          <span>{{good.text}}</span>
          <span>¥{{good.price}}</span>
        </nuxt-link>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  head() {
    return {
      title: "课程列表",
      meta: [
        { name: "description", hid: "description", content: "set page meta" }
      ],
      link: [{ rel: "favicon", href: "favicon.ico" }]
    };
  },
  async asyncData({ $axios, error }) {
    // 页面上下文
    const { ok, goods } = await $axios.$get("/api/goods");
    if (ok) {
      return { goods };
    }
    // 错误处理
    error({ statusCode: 400, message: "数据查询失败" });
  }
  // data() {
  //   return { goods: [
  //     {id:1, text:'Web全栈架构师',price:8999},
  //     {id:2, text:'Python全栈架构师',price:8999},
  //   ] }
  // }
};
</script>

嵌套路由
pages/detail/_id.vue
_id会被作为参数的名字

<template>
    <div>
        {{$route.params.id}}
    </div>
</template>

<script>
    export default {
        
    }
</script>

<style lang="scss" scoped>

</style>

要想做路由嵌套 要创建一个根文件夹一样名字的文件
pages/detail.vue

<template>
    <div>
        detail page
        <nuxt-child></nuxt-child>
    </div>
</template>

<script>
    export default {
        
    }
</script>

<style lang="scss" scoped>

</style>

layouts/default.vue添加导航

<template>
  <div>
    <nav>
      <nuxt-link to="/">首页</nuxt-link>
      <!--别名:n-link,NLink,NuxtLink-->
      <NLink to="/admin">管理</NLink>
      <n-link to="/cart">购物车</n-link>
    </nav>

    <nuxt />
  </div>
</template>

<style>
html {
  font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  word-spacing: 1px;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: border-box;
  margin: 0;
}

.button--green {
  display: inline-block;
  border-radius: 4px;
  border: 1px solid #3b8070;
  color: #3b8070;
  text-decoration: none;
  padding: 10px 30px;
}

.button--green:hover {
  color: #fff;
  background-color: #3b8070;
}

.button--grey {
  display: inline-block;
  border-radius: 4px;
  border: 1px solid #35495e;
  color: #35495e;
  text-decoration: none;
  padding: 10px 30px;
  margin-left: 15px;
}

.button--grey:hover {
  color: #fff;
  background-color: #35495e;
}
</style>

nuxt.config.js可以追加或删除已生成的路由 因为nuxt的路由是自动生成的

router: {
    extendRoutes(routes, resolve) {
      // routes已经生成的路由
      // resolve是获取页面方法
      routes.push({
        name: "foo",
        path: "/foo",
        component: resolve(__dirname, "pages/custom.vue"),
      });
    },
  },

pages/cutom.vue

<template>
    <div>
        custom page
    </div>
</template>

<script>
    export default {
        
    }
</script>

<style lang="scss" scoped>

</style>

自定义布局 不配置导航头
layouts/blank.vue

<template>
  <div>
    <nuxt />
  </div>
</template>

pages/login.vue

<template>
  <div>
    <h2>用户登录</h2>
    <el-input v-model="user.username"></el-input>
    <el-input type="password" v-model="user.password"></el-input>
    <el-button @click="onLogin">登录</el-button>
  </div>
</template>

<script>
export default {
  layout:'blank',
  data() {
    return {
      user: {
        username: "",
        password: ""
      }
    };
  },
  methods: {
    onLogin() {
      this.$store.dispatch("user/login", this.user).then(ok=>{
          if (ok) {
            const redirect = this.$route.query.redirect || '/'
            this.$router.push(redirect);
          }
      });
    }
  }
};
</script>

安装依赖:
npm i koa-router koa-bodyparser -S
模拟接口服务器
根目录server/api.js
cd server
node .\api.js

const Koa = require('koa');
const app = new Koa();
const bodyparser = require("koa-bodyparser");
const router = require("koa-router")({ prefix: "/api" });

// 设置cookie加密秘钥
app.keys = ["some secret", "another secret"];

const goods = [
  { id: 1, text: "Web全栈架构师", price: 1000 },
  { id: 2, text: "Python架构师", price: 1000 }
];

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 === "jerry" && user.password === "123") {
    // 将token存入cookie
    const token = 'a mock token';
    ctx.cookies.set('token', token);
    ctx.body = { ok: 1, token };
  } else {
    ctx.body = { ok: 0 };
  }
});

// 解析post数据并注册路由
app.use(bodyparser());
app.use(router.routes());

app.listen(8080, () => console.log('api服务已启动'))

中间件 处理路由跳转之前的拦截
middleware/auth.js

// 参数是页面上下文
export default function({ route, redirect, store }) {
  // 上下文中通过store访问vuex中的全局状态
  // 通过vuex中令牌存在与否判断是否登录
  if (!store.state.user.token) {
    redirect("/login?redirect=" + route.path);
  }
}

pages/admin.vue
全局配置middleware 可以在nuxt.config.js
里面的router里配

<template>
    <div>
        admin page
    </div>
</template>

<script>
    export default {
        middleware: ['auth']
    }
</script>

<style lang="scss" scoped>

</style>

store/user.js

export const state = () => ({
  token: "",
});

export const mutations = {
  init(state, token) {
    state.token = token;
  },
};

export const getters = {
  isLogin(state) {
    return !!state.token;
  },
};

export const actions = {
  login({ commit, getters }, u) {
    return this.$axios.$post("/api/login", u).then(({ token }) => {
      if (token) {
        commit("init", token);
      }
      return getters.isLogin;
    });
  },
};

nuxtServerInit
store/index.js
安装依赖:
npm i -S cookie-universal-nuxt
注册 nuxt.config.js
modules: ["@nuxtjs/axios", "cookie-universal-nuxt"],

export const actions = {
    // 参数1:action上下文对象,参数2:nuxt页面上下文
    nuxtServerInit({ commit }, { app }) {
      const token = app.$cookies.get("token");
      if (token) {
        console.log("nuxtServerInit: token:"+token);
        commit("user/init", token);
      }
    }
  };

发布
npm run build
npm start

上一篇下一篇

猜你喜欢

热点阅读