1. Nuxt.js 概述

1.1 我们一起做过的SPA

  • SPA(single page web application)单页 Web 应用,Web 不再是一张张页面,而是一个整体的应用,一个由路由系统、数据系统、页面(组件)系统等等,组成的应用程序。
  • SPA 应用广泛用于对SEO要求不高的场景中
  • nuxt3 useFetch refresh 分页请求 nuxt 文档_html

1.2 什么是SEO

  • SEO:搜索引擎优化(Search Engine Optimization), 通过各种技术(手段)来确保,我们的Web内容被搜索引擎最大化收录,最大化提高权重,最终带来更多流量。
  • 非常明显,SPA程序不利于SEO
  • nuxt3 useFetch refresh 分页请求 nuxt 文档_javascript_02

  • SEO解决方案:提前将页面和数据进行整合
  • 前端:采用SSR
  • 后端:页面静态化 (freemarker 、thymeleaf、velocity)

1.3 什么是SSR技术

  • 服务端渲染(Server Side Render),即:网页是通过服务端渲染生成后输出给客户端。
  • 在SSR中,前端分成2部分:前端客户端、前端服务端
  • 前端服务端,用于发送ajax,获得数据
  • 前端客户端,用于将ajax数据和页面进行渲染,渲染成html页面,并响应给调用程序(浏览器、爬虫)
  • 如果爬虫获得html页面,就可以启动处理程序,处理页面内容,最终完成SEO操作。

1.4 SPA和SSR对比

SPA单页应用程序

SSR服务器端渲染

优势

1.页面内容在客户端渲染

2. 只关注View层,与后台耦合度低,前后端分离

3.减轻后台渲染画面的压力

1.更好的SEO,搜索引擎工具可以直接查看完全渲染的画面

2.更快的内容到达时间 (time-to-content),用户能更快的看到完整渲染的画面

劣势

1.首屏加载缓慢

2.SEO(搜索引擎优化)不友好

1.更多的服务器端负载

2.涉及构建设置和部署的更多要求,需要用Node.js渲染

3.开发条件有限制,一些生命周期将失效

4.一些常用的浏览器API无法使用

1.5 什么是Nuxt.js

  • Nuxt.js 是一个基于 Vue.js 的通用应用框架。
  • 通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI 渲染
  • Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置。

2 入门案例

2.1 create-nuxt-app 介绍

  • Nuxt.js 提供了脚手架工具 create-nuxt-app
  • create-nuxt-app 需要使用 npx
  • npx 命令为 NPM版本5.2.0默认安装组件
  • nuxt3 useFetch refresh 分页请求 nuxt 文档_html_03

2.2 安装

npx create-nuxt-app <project-name>
  • 例如
npx create-nuxt-app demo_nuxt02

nuxt3 useFetch refresh 分页请求 nuxt 文档_前端_04

  • nuxtjs改善

2.3 启动

npm run dev

nuxt3 useFetch refresh 分页请求 nuxt 文档_javascript_05

2.4 访问

http://localhost:3000

nuxt3 useFetch refresh 分页请求 nuxt 文档_前端_06

3. 目录结构

3.1 目录

目录名称

描述

assets

资源目录,用于存放需要编译的静态资源。例如:LESS、SASS等

默认情况下,Nuxt使用Webpack若干加载器处理目录中的文件

components

vue组件目录,Nuxt.js 不会增强该目录,及不支持SSR

layouts

布局组件目录

pages

页面目录,所有的vue视图,nuxt根据目录结构自动生成对应的路由。

plugins

插件目录

static

静态文件目录,不需要编译的文件

store

vuex目录

nuxt.config.js

nuxt个性化配置文件,内容将覆盖默认

package.json

项目配置文件

nuxt3 useFetch refresh 分页请求 nuxt 文档_javascript_07

3.2 别名

  • assets 资源的引用:~ 或 @
// HTML 标签
<img src="~assets/13.jpg" style="height:100px;width:100px;" alt="">
<img src="~/assets/13.jpg" style="height:100px;width:100px;" alt="">
<img src="@/assets/13.jpg" style="height:100px;width:100px;" alt="">

// CSS
background-image: url(~assets/13.jpg);
background-image: url(~/assets/13.jpg);
background-image: url(@/assets/13.jpg);
  • static 目录资源的引用:/ 直接引用
//html标签
<img src="/12.jpg" style="height:100px;width:100px;" alt="">

//css
background-image: url(/12.jpg);
  • 实例
<template>
  <div>
    <!-- 引用 assets 目录下经过 webpack 构建处理后的图片 -->
    <img src="~assets/13.jpg" style="height:100px;width:100px;" alt="">

    <!-- 引用 static 目录下的图片 -->
    <img src="/12.jpg" style="height:100px;width:100px;" alt="">

    <!-- css -->
    <div class="img1"></div>
    <div class="img2"></div>
  </div>
</template>

<script>
export default {

}
</script>

<style>
  .img1 {
    height: 100px;
    width: 100px;
    background-image: url(~assets/13.jpg);
    background-size: 100px 100px;
    display: inline-block;
  }
  .img2 {
    height: 100px;
    width: 100px;
    background-image: url(/12.jpg);
    background-size: 100px 100px;
    display: inline-block;
  }
</style>

4 路由

4.1 路由概述

  • Nuxt.js 依据 pages 目录结构自动生成 vue-router 模块的路由配置。
  • 要在页面之间切换路由,我们建议使用<nuxt-link> 标签。

标签名

描述

<nuxt-link>

nuxt.js中切换路由

<Nuxt />

nuxt.js的路由视图

<router-link>

vue默认切换路由

<router-view/>

vue默认路由视图

4.2 基础路由

  • 自动生成基础路由规则

路径

组件位置及其名称

规则

/

pages/index.vue

默认文件 index.vue

/user

pages/user/index.vue

默认文件 index.vue

/user/one

pages/user/one.vue

指定文件

  • 实例
情况1:访问路径,由pages目录资源的名称组成(目录名称、文件的名称)
  - 资源位置: ~/pages/user/one.vue
  - 访问路径:http://localhost:3000/user/one


情况2:每一个目录下,都有一个默认文件 index.vue
  - 资源位置: ~/pages/user/index.vue
  - 访问路径:http://localhost:3000/user
  • 思考:/user 可以匹配几种文件?
  • pages/user.vue 文件 【优先级高】
  • pages/user/index.vue 文件

4.3 动态路由

  • 在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。

路由中路径匹配

组件位置及其名称

/

pages/index.vue

/user/:id

pages/user/_id.vue

/:slug

pages/_slug/index.vue

/:slug/comments

pages/_slug/comments.vue

  • 实例1:获得id值,创建资源 user/_id.vue
<template>
  <div>
    查询详情 {{this.$route.params.id}}
  </div>
</template>

<script>
export default {
  transition: 'test',
  mounted() {
    console.info(this.$route)
  },
}
</script>

<style>

</style>

4.4 动态命名路由

  • 路径 /news/123 匹配_id.vue还是_name.vue
  • 我们可以使用<nuxt-link>解决以上问题
  • 通过name 确定组件名称:“xxx-yyy”
  • 通过params 给对应的参数传递值
<nuxt-link :to="{name:'news-id',params:{id:1002}}">第2新闻</nuxt-link>
<nuxt-link :to="{name:'news-name',params:{name:1003}}">第3新闻</nuxt-link>

4.5 默认路由

路径

组件位置及其名称

不匹配的路径

pages/_.vue

  • 404页面,可以采用 _.vue进行处理

4.6 嵌套路由(了解)

  • 创建嵌套子路由,你需要添加一个 父组件Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。
  • 要求:父组件 使用<nuxt-child/> 显示子视图内容
pages/
  --| book/						//同名文件夹
  -----| _id.vue
  -----| index.vue
  --| book.vue					//父组件
  • 步骤1:编写父组件 pages/child/book.vue
<template>
  <div>
      <nuxt-link to="/child/book/list">书籍列表</nuxt-link> |
      <nuxt-link to="/child/book/123">书籍详情</nuxt-link> |
      <hr>
      <nuxt-child />
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 步骤2:编写子组件 pages/child/book/list.vue
<template>
  <div>书籍列表</div>
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 步骤3:编写子组件 pages/child/book/_id.vue
<template>
  <div>书籍详情{{$route.params.id}} </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

4.7 过渡动效(了解)

4.7.1 全局过渡动效设置

  • Nuxt.js 默认使用的过渡效果名称为 page
  • .page-enter-active样式表示进入的过渡效果。
  • .page-leave-active样式表示离开的过渡效果。
  • 步骤1:创建 assets/main.css,编写如下内容:
.page-enter-active, .page-leave-active {
    transition: opacity .5s;
  }
  .page-enter, .page-leave-active {
    opacity: 0;
  }
  • 步骤2:nuxt.config.js 引入main.css文件
module.exports = {
    css: [
      'assets/main.css'
    ]
  }

4.7.1 自定义动画

  • 如果想给某个页面自定义过渡特效的话,只要在该页面组件中配置 transition 字段即可:
  • 步骤1:在全局样式 assets/main.css 中添加名称为test的过渡效果
.test-enter-active, .test-leave-active {
    transition: all 2s;
    font-size:12px;
  }
   .test-enter, .test-leave-active {
    opacity: 0;
    font-size:40px;
  }
  • 步骤2:需要使用特效的vue页面编写如下:
export default {
    transition: 'test'
  }

5. 视图

5.1 默认模板(了解)

  • 定制化默认的 html 模板,只需要在应用根目录下创建一个 app.html 的文件。
  • 默认模板:
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head {{ HEAD_ATTRS }}>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>
  • 修改模板,对低版本IE浏览器进行支持(兼容IE浏览器)
<!DOCTYPE html>
<!--[if IE 9]><html lang="en-US" class="lt-ie9 ie9" {{ HTML_ATTRS }}><![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--><html {{ HTML_ATTRS }}><!--<![endif]-->
  <head {{ HEAD_ATTRS }}>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>

5.2 默认布局【掌握】

5.2.1 布局概述

  • 布局:Nuxt.js根据布局,将不同的组件进行组合。
  • 模板:html页面,是布局后所有组件挂载的基础。

nuxt3 useFetch refresh 分页请求 nuxt 文档_javascript_08

5.2.2 布局分析

  • layouts/default.vue 默认布局组件
  • 访问路径根据路由,确定执行组件
  • 组件具体显示的位置,有布局来确定

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oK655tTp-1639705695557)(assets/image-20210428225159898.png)]

5.2.3 公共导航

  • 修改 layouts/default.vue
<template>
  <div>
    <nuxt-link to="/">首页</nuxt-link> |
    <nuxt-link to="/user/login">登录</nuxt-link> |
    <nuxt-link to="/user/123">详情</nuxt-link> |
    <nuxt-link to="/about">默认页</nuxt-link> |
    <nuxt-link to="/nuxt/async">async</nuxt-link> |
    <hr/>
    <Nuxt />
  </div>
</template>

5.3 自定义布局

  • 在layouts目录下创建组件:layouts/blog.vue
<template>
	<div>
        开头<br/>
        <nuxt/>
        结束<br/>
    </div>
  
</template>

<script>
export default {

}
</script>

<style>

</style>
  • 在需要的视图中使用 blog布局
<script>
export default {
  layout: 'blog'
  //...
}
</script>

nuxt3 useFetch refresh 分页请求 nuxt 文档_前端_09

5.4 错误页面

  • 编写layouts/error.vue页面,实现个性化错误页面
<template>
  <div>
    <div v-if="error.statusCode == 404">
      404 页面不存在 {{error.message}}
    </div>
    <div v-else>
      应用程序错误
    </div>
    <nuxt-link to="/">首 页</nuxt-link>
  </div>
</template>

<script>
export default {
  props: ['error']
}
</script>

<style>

</style>
  • 解决问题: 404 、500、连接超时(服务器关闭)
  • 总结:所学习的技术中,有2种方式处理错误页面
  • 方式1:默认路径,_.vue (先执行)
  • 方式2:错误页面,~/layouts/error.vue

5.5 Nuxt组件特殊配置

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

特殊配置项

描述

asyncData

SSR进行异步数据处理,也就是服务器端ajax操作区域。

fetch

在渲染页面之前获取数据填充应用的状态树(store)

head

配置当前页面的 Meta 标签

layout

指定当前页面使用的布局

transition

指定页面切换的过渡动效

scrollToTop

布尔值,默认: false。 用于判定渲染页面前是否需要将当前页面滚动至顶部。

5.5.1 模板代码

<template>
  <h1 class="red">Hello {{ name }}!</h1>
</template>

<script>
export default {
	//异步处理数据, 每次加载之前被调用
  asyncData (context) {
    // called every time before loading the component
    return { name: 'World' }
  },	
	//用于在渲染页面之前获取数据填充应用的状态树(store)
  fetch () {
    // The fetch method is used to fill the store before rendering the page
  },
	//配置当前页面的 Meta 标签
  head: {
    // Set Meta Tags for this Page
  },
  // and more functionality to discover
  ...
}
</script>

<style>
.red {
  color: red;
}
</style>

5.5.2 head

  • html模板代码
<html>
<head>
	<meta charset="UTF-8" />
	<title>我是标题</title>
	<link rel="stylesheet" type="text/css" href="css外部文件"/>
	<script src="js外部文件" type="text/javascript" charset="utf-8"></script>
</head>
<body>
</body>
</html>
  • 通过nuxt提供head属性,可以给单个也是设置:标题、外部css、外部js 等内容。

nuxt3 useFetch refresh 分页请求 nuxt 文档_javascript_10

<template>
  <div>
    详情页 {{$route.params.id}} <br/>

    <div class="bg2"></div>
    <div class="bg3"></div>

  </div>
</template>

<script>
export default {
  head: {
    title: '详情页',
    link: [
      {rel:'stylesheet',href:'/style/img.css'},....
    ],
    script: [
      { type: 'text/javascript', src: '/js/news.js' }
    ]
  }
}
</script>

<style>
  .bg2 {
    background-image: url('~static/img/2.jpg');
    width: 300px;
    height: 300px;
    background-size: 300px;
  }
</style>

6. ajax操作

6.1 整合 axios

6.1.1 默认整合

  • 在构建项目时,如果选择axios组件,nuxt.js将自动与axios进行整合

6.1.2 手动整合(可选)

  • 步骤1:package.json有axios的版本
"dependencies": {
      "@nuxtjs/axios": "^5.13.1",
    },
  • 步骤2:安装
npm install
  • 步骤3:nuxt.config.js 以模块的方式添加axios
modules: [
      // https://go.nuxtjs.dev/axios
      '@nuxtjs/axios',
    ],

6.1.3 常见配置

  • 修改 nuxt.config.js 进行baseURL的配置
// Axios module configuration: https://go.nuxtjs.dev/config-axios
    axios: {
      baseURL:'http://localhost:10010/'
    },

6.2 使用axios发送ajax

  • 在vue页面中,通过 this.nuxt3 useFetch refresh 分页请求 nuxt 文档_html_11axios 与之前 axios等效。
this.$axios.post("/search-service/search",this.searchMap).then( res => {
      //获得查询结果
      this.searchResult = res.data.data;
  });

6.3 使用asyncData发送 ajax

  • asyncData中的ajax将在“前端服务端执行”,在浏览器看到是数据,而不是ajax程序。

6.3.1 发送一次请求

  • 语法:
export default {
	async asyncData( context ) {  //context就相当于其他地方的this
        //发送ajax
        let { data } = await context.$axios.get('路径','参数')
        // 返回结果
        return {变量: 查询结果从data获取 }
	},
}
  • 实例
<template>
  <div>{{echo}}</div>
</template>

<script>
export default {
  async asyncData(context) {
    // 发送ajax
    let {data} = await context.$axios.get('/service-consumer/feign/echo/abc')
    // 返回数据
    return {
      echo: data
    }
  },
}
</script>

<style>

</style>

6.3.2 发送多次请求

  • 语法1:
export default {
      async asyncData( content ) {
          let [结果1,结果2] = await Promise.all([ ajax请求1, ajax请求2])
          return {
              变量1: 结果1,
              变量2: 结果2
          }
      },
  }
  • 语法2:
export default {
      async asyncData( content ) {
          let [{数据:别名1},{数据:别名2}] = await Promise.all([ ajax请求1, ajax请求2])
          return {
              变量1: 别名1,
              变量2: 别名2
          }
      },
  }
  • 实例
<template>
  <div>{{echo}} {{echo2}}</div>
</template>

<script>
export default {
  async asyncData(context) {
    // 发送ajax
    let [{data:echo}, {data:echo2}] = 
                await Promise.all([
                    context.$axios.get('/service-consumer/feign/echo/abc'),
                    context.$axios.get('/service-consumer/client/echo/abc')
                ])

    // 返回数据
    return {
      echo,
      echo2
    }
  },
}
</script>

<style>

</style>

6.4 使用fetch发送 ajax

  • fetch 方法用于在渲染页面前填充应用的状态树(store)数据, 与 asyncData 方法类似,不同的是它不会设置组件的数据。

nuxt3 useFetch refresh 分页请求 nuxt 文档_前端_12

  • 步骤1:创建store/index.js
export const state = () => ({
    str: 0
  })
  
  export const mutations = {
    setData (state, value) {
      state.str = value
    }
  }
  • 步骤2:测试页面
<template>
  <div>
    <!-- 显示数据 -->
    {{$store.state.str}}
  </div>
</template>

<script>

export default {
  async fetch( {store, $axios} ) {
    // 发送ajax
    let { data } = await $axios.get('/service-consumer/feign/echo/abc')
    // 设置数据
    store.commit('setData' , data )
  }
}
</script>

<style>

</style>

6.5 插件:自定义axios

6.5.1 客户端

  • 步骤一:在nuxt.conf.js中配置客户端插件,设置 mode 为 client
plugins: [
      { src: '~plugins/api.js', mode: 'client' }
    ],

nuxt3 useFetch refresh 分页请求 nuxt 文档_javascript_13

  • 步骤二:编写 plugins/api.js 对 内置的 $axios进行增强

nuxt3 useFetch refresh 分页请求 nuxt 文档_SEO_14

//自定义函数
const request = {
  test : (params) => {
    return axios.get('/service-consumer/feign/echo/abc',{
      params
    })
  },
}

var axios = null
export default ({ $axios }, inject) => {

  //3) 保存内置的axios
  axios = $axios

  //4) 将自定义函数交于nuxt
  // 使用方式1:在vue中,this.$request.xxx()
  // 使用方式2:在nuxt的asyncData中,content.app.$request.xxx()

  inject('request', request)
}

6.5.2 服务端

  • 步骤一:配置服务端插件,设置 mode 为 server
plugins: [
      { src: '~plugins/api.js', mode: 'client' },
      { src: '~plugins/api.server.js', mode: 'server' },
    ],
  • 步骤二:编写 plugins/api.server.js 对 内置的 $axios进行增强
const request = {
  test : (params) => {
    return axios.get('/service-consumer/feign/echo/abc',{
      params
    })
  },
  
}

var axios = null
export default ({ $axios, redirect, process }, inject) => {

  //赋值
  axios = $axios

  //4) 将自定义函数交于nuxt
  // 使用方式1:在vue中,this.$request.xxx()
  // 使用方式2:在nuxt的asyncData中,content.app.$request.xxx()
  inject('request', request)
}

6.5.3 插件配置总结

//方式1:通过src设置文件,通过mode设置模式
plugins: [
	{ src: '~/plugins/apiclient.js', mode: 'client' },		//前端客户端
	{ src: '~/plugins/apiserver.js', mode: 'server' },		//前端服务端
    { src: '~/plugins/api.js' }								//前端客户端 + 前端服务端
]

//方式2:通过命名来确定模式
plugins: [
    '~/plugins/api.client.js',				//前端客户端
    '~/plugins/api.server.js',				//前端服务端
    '~/plugins/api.js',						//前端客户端 + 前端服务端
]

7. Vuex 状态树

7.1 根模块数据操作

  • 步骤一:创建 store/index.js 添加一个 counter变量,并可以继续累加操作
export const state = () => ({
    counter: 0
  })
  
  export const mutations = {
    increment (state) {
      state.counter++
    }
  }
  • 步骤二:在页面中,使用
<template>
  <div>
    首页 {{counter}}
    <input type="button" value="+" @click="increment"/>
  </div>
</template>

<script>
import { mapState,mapMutations } from 'vuex'
export default {
  computed: {
    ...mapState(['counter'])
  },
  methods: {
    ...mapMutations(['increment'])
  },
}
</script>

<style>

</style>

7.2 其他模块数据操作

  • 步骤一:创建其他模块 store/book.js
export const state = () => ({
    money: 0
  })
  
  export const mutations = {
    addmoney (state) {
      state.money += 5
    }
  }
  • 步骤二:使用指定模块中的数据
<template>
  <div>
    首页 {{money}}
    <input type="button" value="+" @click="addmoney" />
  </div>
</template>

<script>
import { mapState,mapMutations } from 'vuex'
export default {
  computed: {
    money () {
      return this.$store.state.book.money
    }
  },
  methods: {
    ...mapMutations({
      addmoney: 'book/addmoney'
    })
  },
}
</script>

<style>

</style>

7.3 完整vuex模板

// state为一个函数, 注意箭头函数写法
const state = () => ({
  user: 'jack'
})

// mutations为一个对象
const mutations = {
  setUser(state, value) {
    state.counter = value
  }
}
// action执行mutation
const actions = {
  userAction (context,value){
    // 可以发送ajax
    context.commit('setUser',value)
  }

}

// 获取数据
const getters = {
  getUser (state) {
    return state.user
  }
}
export default {
  namespace: true,	// 命名空间
  state,
  mutations,
  actions,
  getters
}

8. nuxt流程总结

nuxt3 useFetch refresh 分页请求 nuxt 文档_css_15

9. 综合练习

  • 需求:查询学生列表信息
  • 要求1:可以进行“班级”条件查询
  • 要求2:对“班级”数据进行SEO
  • 要求3:学生数据不进行SEO
  • 表结构
#班级表
create table tab_class(
  cid int primary key auto_increment,
  cname varchar(50)
);
insert into tab_class(cid, cname) values(1,'Java56');
insert into tab_class(cid, cname) values(2,'Java78');

#学生表
create table tab_student(
  sid int primary key auto_increment,
  sname varchar(50),
  cid int
);

insert into tab_student(sname,cid) values('张三',1);
insert into tab_student(sname,cid) values('李四',1);
insert into tab_student(sname,cid) values('王五',2);
insert into tab_student(sname,cid) values('赵六',2);
  • 后端代码
  • 代码结构
  • controller/StudentController
package com.czxy.student.controller;

import com.czxy.student.service.StudentService;
import com.czxy.student.vo.StudentVo;
import com.czxy.vo.BaseResult;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/student")
public class StudentController {
    @Autowired
    private StudentService studentService;

    @PostMapping("/condition/{pageSize}/{pageNum}")
    public BaseResult condition(@PathVariable("pageSize") Integer pageSize,
                                @PathVariable("pageNum") Integer pageNum,
                                @RequestBody StudentVo studentVo){
     PageInfo pageInfo = studentService.condition(pageNum,pageSize,studentVo);
     return BaseResult.ok("查询成功",pageInfo);
    }
}
  • mapper/StudentMapper
package com.czxy.student.mapper;

import com.czxy.domain.Student;
import tk.mybatis.mapper.common.Mapper;

@org.apache.ibatis.annotations.Mapper
public interface StudentMapper extends Mapper<Student> {
}
  • service/StudentService
package com.czxy.student.service;

import com.czxy.domain.Student;
import com.czxy.student.mapper.StudentMapper;
import com.czxy.student.vo.StudentVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.util.StringUtil;

import java.util.List;

@Service
@Transactional
public class StudentService {
    @Autowired
    private StudentMapper studentMapper;


    public PageInfo condition(Integer pageNum, Integer pageSize, StudentVo studentVo) {
        Example example = new Example(Student.class);
        Example.Criteria criteria = example.createCriteria();

        if (StringUtil.isNotEmpty(studentVo.getCid())){
            criteria.andEqualTo("cid",studentVo.getCid());
        }

        if (StringUtil.isNotEmpty(studentVo.getSname())){
            criteria.andLike("sname","%"+studentVo.getSname()+"%");
        }

        if (StringUtil.isNotEmpty(studentVo.getStartAge())){
            criteria.andGreaterThanOrEqualTo("age",studentVo.getStartAge());
        }

        if (StringUtil.isNotEmpty(studentVo.getEndAge())){
            criteria.andLessThanOrEqualTo("age",studentVo.getEndAge());
        }

        PageHelper.startPage(pageNum,pageSize);

        List<Student> list = studentMapper.selectByExample(example);

        return new PageInfo(list);
    }
}
  • vo/StudentVo
package com.czxy.student.vo;

import lombok.Data;

@Data
public class StudentVo {
    private String cid;
    private String sname;
    private String startAge;
    private String endAge;
}
  • 启动器 —StudentServiceApplication
package com.czxy.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@SpringBootApplication
@EnableDiscoveryClient
public class StudentServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudentServiceApplication.class, args );
    }
}
  • 后端代码框架
  • nuxt.config.js
plugins: [
    {src: '@/plugins/api-client.js',mode:'client'},
    {src: '@/plugins/api-server.js'}
  ],
    axios: {
    baseURL: 'http://localhost:10010/',
  },
  • plugins/api-client.js
//自定义函数
const request = {
//分页查询
  condition(pageInfo,studentVo) {
    var url = `/student-service/student/condition/${pageInfo.pageSize}/${pageInfo.pageNum}`
    return axios.post(url, studentVo)
  },
  //模糊查询
  query(pageInfo,studentVo){
    var url = `/student-service/student/condition/${pageInfo.pageSize}/${pageInfo.pageNum}`
    return axios.post(url, studentVo)
  },
}

var axios = null
export default ({ $axios }, inject) => {

  //3) 保存内置的axios
  axios = $axios

  //4) 将自定义函数交于nuxt
  // 使用方式1:在vue中,this.$request.xxx()
  // 使用方式2:在nuxt的asyncData中,content.app.$request.xxx()

  inject('requestclient', request)
}
  • plugins/api-server.js
//自定义函数
const request = {
//班级列表
  list() {
    var url = '/student-service/classes/list'
    return axios.get(url)
  },
}

var axios = null
export default ({ $axios }, inject) => {

  //3) 保存内置的axios
  axios = $axios

  //4) 将自定义函数交于nuxt
  // 使用方式1:在vue中,this.$request.xxx()
  // 使用方式2:在nuxt的asyncData中,content.app.$request.xxx()

  inject('requestServer', request)
}
  • pages/student.vue
<template>
  <div>
    <hr />
    请选择班级:
    <select v-model="studentVo.cid" @click="query()">
      <option value="" >--请选择班级--</option>
      <option v-for="c in classesList" :key="c.index" :value="c.cid">
        {{ c.cname }}
      </option>
    </select>
    <br />
    学生列表
    <table border="1">
      <tbody>
        <tr>
          <td>序号</td>
          <td>姓名</td>
          <td>班级</td>
          <td>操作</td>
        </tr>
        <tr v-for="s in pageInfo.list" :key="s.index">
          <td>{{ s.sid }}</td>
          <td>{{ s.sname }}</td>
          <td>{{ s.classes_test !=null ? s.classes_test.cname : s.cid }}</td>
          <td>修改 删除</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      studentVo: {
        cid: "",
      },
      pageInfo: {
        pageSize:10,
        pageNum:1,
      },
    };
  },
  methods: {
    async conditionFn() {
      let { data } = await this.$requestclient.condition(this.pageInfo,this.studentVo);
      this.pageInfo = data.data;
    },
    async query() {
      let { data } = await this.$requestclient.query(this.pageInfo,this.studentVo);
      this.pageInfo = data.data;
    },
  },
  async asyncData({ $requestServer }) {
    let { data } = await $requestServer.list();
    return {
      classesList: data.data,
    };
  },
  mounted() {
    this.conditionFn();
  },
};
</script>

<style>
</style>
  • pages/index.vue
<template>
  <div>
      <a href="/student">学生列表</a>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
  • layouts/default.vue
<template>
  <div>
      <!-- 导航条 -->
      <nuxt-link to="/">首页</nuxt-link>
      <!-- 视图 -->
      <nuxt/>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>