nuxtJs学习

服务端渲染SSR

nuxt渲染流程

在这里插入图片描述

nuxt安装

运行 create-nuxt-app

npx create-nuxt-app <项目名>

路由

路由生成

查看.nuxt/router.js验证生成路由

pages目录中所有 *.vue 文件自动生成应用的路由配置,新建:

  • pages/detail.vue 详情页
  • pages/cart.vue 购物车页
  • pages/admin.vue 商品管理页
  • pages/login.vue 登录页

导航

添加路由导航,layouts/default.vue

<nav>
    <nuxt-link to="/">首页</nuxt-link>
    <!--别名:n-link,NLink,NuxtLink-->
    <NLink to="/admin">管理</NLink>
    <n-link to="/cart">购物车</n-link>
</nav>
  • 禁用预加载: <n-link no-prefetch>page-no-prefetch</n-link>

商品列表,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>
                    <button @click.prevent="addCart(good)">加购物车</button>
            	</nuxt-link>
            </li>
        </ul>
    </div>
</template>
<script>
export default {
    data() {
    	return { 
            goods: [
                {id:1, text:'Web全栈架构师',price:8999},
                {id:2, text:'Python全栈架构师',price:8999},
            ] 
        }
    },
    methods: {
   	 addCart(){}
    }
};
</script>

动态路由

以下划线作为前缀的 .vue文件 或 目录会被定义为动态路由,如下面文件结构

pages/
--| detail/
----| _id.vue

如果detail/里面不存在index.vue,:id将被作为可选参数

嵌套路由

创建内嵌子路由,你需要添加一个 .vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。 构造文件结构如下:

pages/
--| index/
----| _id.vue
--| index.vue

测试代码,main.vue

<template>
  <ul>
    <li v-for="good in goods" :key="good.id" >
    	<!--修改目标路由名称为index-id-->
      <nuxt-link :to="{name: 'index-id', params: {id: good.id}}">
        <span>{{good.text}}</span>
        <span>¥{{good.price}}</span>
        <button @click.prevent="addCart(good)">加购物车</button>
      </nuxt-link>
    </li>
	</ul>
  <!--添加路由视图-->
  <nuxt-child></nuxt-child>
</template>

视图

下图展示了Nuxt.js 如何为指定的路由配置数据和视图

默认布局

查看 layouts/default.vue

<template>
	<nuxt/>
</template>

自定义布局

创建空白布局页面layouts/blank.vue,用于login.vue

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

页面 pages/login.vue 使用自定义布局:

export default {
	layout: 'blank'
}

自定义错误页面

创建layouts/error.vue

<template>
  <div class="container">
    <h1 v-if="error.statusCode === 404">页面不存在</h1>
    <h1 v-else>应用发生错误异常</h1>
    <nuxt-link to="/">首 页</nuxt-link>
  </div>
</template>
<script>
export default {
props: ['error']
}
</script>

页面

页面组件就是 Vue 组件,只不过 Nuxt.js 为这些组件添加了一些特殊的配置项

给首页添加标题和meta等,index.vue

export default {
  head() {
    return {
      title: "课程列表",
      meta: [{ name: "description", hid: "description", content: "set page meta" }],
      link: [{ rel: "favicon", href: "favicon.ico" }],
    };
	},
};

异步数据获取

asyncData 方法使得我们可以在设置组件数据之前异步获取或处理数据

范例:获取商品数据

接口准备

  • 安装依赖:npm i koa-router koa-bodyparser -S
  • 创建接口文件,server/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 tk = 'a mock token';
    ctx.cookies.set('token', tk );
    ctx.body = { ok: 1, token: tk  };
  } else {
  	ctx.body = { ok: 0 };
  }
});
// 解析post数据并注册路由
app.use(bodyparser());
app.use(router.routes());
app.listen(8080, () => console.log('api服务已启动'))

整合axios

安装@nuxt/axios模块:·npm install @nuxtjs/axios -S

配置:nuxt.config.js(注意配置重启生效)

modules: [
	'@nuxtjs/axios',
],
axios: {
	proxy: true
},
proxy: {
	"/api": "http://localhost:8080"
},

测试代码:获取商品列表,index.vue

<script>
export default {
  async asyncData({ $axios, error }) {
    const {ok, goods} = await $axios.$get("/api/goods");
    if (ok) {
    return { goods };
  	}
    // 错误处理
    error({ statusCode: 400, message: "数据查询失败" });
	},
}
</script>

测试代码:获取商品详情,/index/_id.vue

<template>
  <div>
    <pre v-if="goodInfo">{{goodInfo}}</pre>
  </div>
</template>
<script>
export default {
  async asyncData({ $axios, params, error }) {
    if (params.id) {
    // asyncData中不能使用this获取组件实例
    // 但是可以通过上下文获取相关数据
    	const { data: goodInfo } = await $axios.$get("/api/detail", { params });
      if (goodInfo) {
     	 return { goodInfo };
      }
   	 error({ statusCode: 400, message: "商品详情查询失败" });
    } else {
    	return { goodInfo: null };
    }
  }
};
</script>

中间件

中间件会在一个页面或一组页面渲染之前运行我们定义的函数,常用于权限控制、校验等任务。

范例代码:管理员页面保护,创建middleware/auth.js

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

注册中间件,admin.vue(运行报错,因为不存在user模块)

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

状态管理

vuex 应用根目录下如果存在 store 目录,Nuxt.js将启用vuex状态树。定义各状态树时具名导出state, mutations, getters, actions即可。 范例:用户登录及登录状态保存,创建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.$login(u).then(({ token }) => {
    if (token) {
   	 commit("SET_TOKEN", token);
    }
    return getters.isLogin;
    });
	}
};

插件

Nuxt.js会在运行应用之前执行插件函数,需要引入或设置Vue插件、自定义模块和第三方模块时特别有用。

范例代码:接口注入,利用插件机制将服务接口注入组件实例、store实例中,创建plugins/api-inject.js

export default ({ $axios }, inject) => {
  inject("login", user => {
  	return $axios.$post("/api/login", user);
  });
};

注册插件,nuxt.config.js

plugins: ["@/plugins/api-inject"],

登录页面逻辑,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 {
  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>

范例:添加请求拦截器附加token,创建plugins/interceptor.js

export default function({ $axios, store }) {
$axios.onRequest(config => {
if (store.state.user.token) {
config.headers.Authorization = "Bearer " + store.state.user.token;
}
return config;
});
}

注册插件,nuxt.config.js

plugins: ["@/plugins/interceptor"]

nuxtServerInit

通过在store的根模块中定义 nuxtServerInit 方法,将服务端的一些数据传到客户端。

范例:登录状态初始化,store/index.js

export const actions = {
  // nuxtServerInit 必须声明在根模块
  // 参数1是action上下文, 参数2是组件上下文
  nuxtServerInit({ commit }, { app }) {
  const token = app.$cookies.get("token");
  if (token) {
  console.log("nuxtServerInit: token:"+token);
  commit("user/SET_TOKEN", token);
  }
  }
};
  • 安装依赖模块cookie-universal-nuxt: npm i -S cookie-universal-nuxt
  • 注册, nuxt.config.js:modules: ["cookie-universal-nuxt"],

发布部署

服务端渲染应用部署

先进行编译构建,然后再启动 Nuxt 服务

npm run build
npm start

静态应用部署

Nuxt.js 可依据路由配置将应用静态化,使得我们可以将应用部署至任何一个静态站点主机服务商。这种情况必须是接口服务器及项目运行的情况下才能使用

npm run generate
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值