美文网首页
SSR实战:Nuxt.js

SSR实战:Nuxt.js

作者: key君 | 来源:发表于2019-10-21 16:30 被阅读0次

    基于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

    相关文章

      网友评论

          本文标题:SSR实战:Nuxt.js

          本文链接:https://www.haomeiwen.com/subject/tgazmctx.html