SpringBoot(二) 实现vue前端

前端的基本框架

导航栏的基本架构:
KOB 对战 对局列表 排行榜 用户中心

NavBar 组件

  • 因为导航栏多次复用,因此做页面的时候可以将导航栏专门提炼出来,在 vue 里面创造一个组件

  • vue 里面创组件一般是在 components 目录下,现在在其下面创建一个 NavBar.vue ,在 vue

    里面创建组件名至少要有 两个 字母大写,否则会报错。

  • 一个组件里面至少要有三个部分:html、js、css

    <template>
    </template>
    
    <script>
    </script>
    
    <style scoped>   // scoped 的作用是在这里面写的 css 它会加上一个随机字符串,使得这个样式不会影响到组件
                     // 以外的部分
    </style>
    

Bootstrap 框架来做导航栏,Bootstrap 能够让程序员很轻松地就可以做到美工的效果,它提供了很好的工具,选就可以了,不需要自己去创造,为了让程序员写一个漂亮的网站。

Bootstrap 里面搜 Nav 选择一个合适的就行了,粘过来放在 template 里面。然后在 src/App.vuescript 里面导入 NavBar ,并在 template 里面引用一下

<template>
  <NavBar />
  <router-view />
</template>

<script>
import NavBar from '@/components/NavBar.vue'
import "bootstrap/dist/css/bootstrap.min.css"
import "bootstrap/dist/js/bootstrap"
export default {
  components: {
    NavBar
  }
}
</script>
  • 然后在 script 里面导入一下 Boostrap 的 css 包 和 js 包 ,然后会产生一个报错信息,复制一下报错信息,去 vue 的控制台安装该依赖。

修改 Navbar 组件的样式

  • 可以去 NavBar 组件里面修改一下样式:删掉 fluid 然后导航栏会变窄一点、将 light 改为 dark 导航栏背景会变暗

  • NavBar.vue 里面的商标和内容换一下:King Of Bots、对战、对局列表、排行榜,删掉 button 按钮

  • 导航栏里面的聚焦控制一下 active 的位置,active 在的地方就会聚焦,先删掉,等下再看如何控 制

创建下拉菜单:

复制一下 id=“navbarText” 所在的 div 里面的 ul 的内容,覆盖掉下面的 span 标签 ,粘贴的 ul 里面的内容只保留一个 li 标签就可以了,并且删掉它里面控制宽度的 me-auto mb-2 mb-lg-0 的标签就可以了。

接着在 Bootstrap 页面里去找下拉菜单,替换掉导航栏右边的那个 li 标签

之后的每个页面一般也是写一个单独的组件

创建页面

① Pk ② Record ③ Ranklist ④ User/Bot ⑤ 404

页面的组件,一般喜欢放在 view 里面,放在 components 里面也行;以后每个页面里面也可能包含很多组件,推荐每个模块建一个文件夹。

然后分别创建文件夹 pk、 record、ranklist、user/bots

  • Pk 页面需要创建一个索引页面 PkIndexView.vue
  • Record 创建一个索引页面 RecordIndexView.vue
  • Ranklist 创建一个索引页面 RanklistIndexView.vue
  • User/Bot 创建一个索引页面 UserBotIndexView.vue
  • ⑤ 404 创建一个索引页面 NotFound.vue

每个页面都有三个部分:html、js、css,然后分别写上模板内容

链接对应页面

vue 里面的路径:

现在的主页(App.vue)里面包含两个内容:一个是 NavBar;另一个是 route-view ;

这个 route-view 它会自动更具我们的网址来变;它的变化方式在目录 route 下的 index.js 文件里面。

更改链接的步骤:

  1. 先在 index.js 文件里面导入我们写好的页面

  2. import PkIndexView from '@/views/pk/PkIndexView'
    import RecordIndexView from '@/views/record/RecordIndexView'
    import RanklistIndexView from '@/views/ranklist/RanklistIndexView'
    import UserBot from '@/views/user/bots/UserBotIndexView'
    import NotFound from '@/views/error/NotFound'
    

    然后在 const route 数组里面去添加路径

  3. route 里面的路径都是一个对象({}),然后在域名后输入不同的路径会显示不同的页面,但是还有一个问题,只输入域名会什么都没有,所以希望能够重定向到对战页面 (“/pk/”) ,如果是乱七八糟的页面就重定向到 404 (/404/)

    const route = [
        {                               //重定向对战页面
            path: "/",
            name: "home",
            redirect: "/pk/"
        }{
            path: "/pk/",                //域名之后的相对路径
            name: "pk_index",            //对路径起的名字
            components: PkIndexView,     //路径所对应的组件
        },                               //下面页面的路径也类似
        {
            path: "/:catchAll(.*)",      //上面的都没匹配上,该路径是没有被定义的,重定向到404
            redirect: "/404/"            //.* 可以匹配任意字符
        }
    ]
    
    1. 修改 link(也就是 NavBar 组件 html 里面的 href,都是在域名后添加的路径) 实现点哪个网址就跳向那一个页面。

      存在问题: 点完之后页面会刷新一下。但是一般来说这种前后端分离的项目可以实现点完之后不刷新, 这是可以做到的,它其实就是一个单页面的应用。

实现点击链接不刷新页面

vue-route 这个组件为我们提供了一个 route-link 标签

a 标签换成 route-link , href=" " 换成 :to="{name: " “}” 就可以实现了,注意这里的 name 是我们在写路径时设置的那个 name

演示一个案例如下:

<a class="navbar-brand" href="/">King Of Bots</a>
改为:
<route-link class="navbar-brand" :to="{name:"home"}">King Of Bots</route-link>

框住每个页面

每个页面里面放一个白框

Bootstrap 里面搜索 card ,它可以将一片区域框起来,发现每个页面都需要有一个白框,所以它是公共的,因此可以把它拧出来作为一个组件叫 ContentField.vue

白框说明: 首先我们要写一个 container 把它括起来,container 是一个自适应大小的容器,然后里面写一个 divcard ,在 card 里面放一个 divcard-body参照于 Bootstrap),在里面写内容

快捷写法:

div.container>div.card>div.card-body

这个白框未来里面要被填充,填充的内容会渲染在 slot 里面

然后每个页面在 js 区里面 import 这个组件并在 html 模块里引用它

html:
<ContentField>
    对战
</ContentField>

js:
import ContentField from '@/components/ContentField.vue'
export default {
    components : {
        ContentField
    }
}

调整白框的样式

白框太靠上了,需要将它往下拉一点,在它的上面添加一个外边距;这里可以体现组件的优势

ContentField 组件里面为 container 再添加一个名字 content-field, 然后在 css 模块里写样式

css:
div.content-field {
    margin-top:20px;
}

对导航栏实现聚焦(高亮)

首先判断当前在哪个页面,需要在 NavBar 组件的 JS 模块中写一个函数

此时需要导入一个 API

还需导入一个实时计算的 API computed ,当我们需要计算一个变量时就使用它;

js:
import { useRoute } from 'vue-router'
import { computed } from 'vue'
export default {
    setup() {
        const route = useRoute();
        let route_name = computed(()=>route.name);
        return {
            route.name;
        }
    }
}

如果希望在某个属性前面使用表达式的话,需要在它的前面加上冒号:,这个冒号其实就是 v-bind: 的简写

然后对 NavBar 组件中的 html 模块中的 route-link 中的 class 使用三目运算符

原版
<router-link class="nav-link" aria-current="page" :to="{ name: 'pk_index' }">对战</router-link>
修改后:
<router-link class="route_name == 'pk_index' ? 'nav-link active' : 'nav-link' " aria-current="page" :to="{ name: 'pk_index' }">对战</router-link>

这样就可以实现选中的导航栏高亮。

简易版网站

到这里其实就已经实现了一个简易版的网站,可用作各个网站的模板

游戏地图设计

地图大小是 13 * 13

地图是轴对称中心对称的,然后左下角有一条蛇,右上角有一条蛇,中间会随机一些障碍物,是完全对称的

障碍物的数量可以动态地调,并且保证蛇可以从左下角走到右上角去,每次刷新都会得到一个新的地图

地图中的物品是如何动起来的?

  • 地图是每秒钟刷新60次(帧)(可以调)
  • 在每一帧里计算物体的位置,然后将它渲染出来,每一帧都会覆盖上一帧,超过24是能接受的
  • 所以这里要实现一个基类,未来所有物品都要继承这个类,它实现了公共的功能(比如每秒刷新60帧)

游戏脚本

代码脚本一般都会放在 assets 里面,这也是秉承自 unity 的一些习惯

  • assets 里面创建一个目录叫 scripts 用来存储我们所有的脚本
  • 再创建一个目录叫 images 用来存储图片,记得将 background 背景图片放进去

scripts 里面创建基类 AcGameObject.js

AcGameObject

为了每一秒钟让所有对象都刷新一遍,我们需要把所有游戏对象先存下来。

定义一个全局数组 const AC_GAME_OBJECTS = []

随后创建游戏基类:

const AC_GAME_OBJECTS = []

export class AcGameObject {
    construct() {
        AC_GAME_OBJECTS.push(this);
    }
}

如何实现每秒钟刷新60次?

前端浏览器中有一个函数叫作 requestAnimationFrame,这个函数可以传一个回调函数,会在下一帧渲染之前执行一下这个回调函数(只执行一次),那么如何让它一直执行呢;可以将该回调函数写成一个迭代函数就行了。

const step = () => {
    requestAnimation(step);
}
requestAnimation(step);

游戏对象要具备如下几个函数

start() {   //只执行一次
    
}
update() {  //每一帧执行一次,除了第一帧之外
    
}
on_destroy() { //删除之前执行
    
}
destory() { //删除当前对象
    this.on_destroy();
    for(let i in AC_GAME_OBJECTS) {
        const obj = AC_GAME_OBJECTS[i];
        if(obj === this) {
            AC_GAME_OBJECTS.splice(i);
            break;
        }
    }
}

属性:

一般让物体移动都会有速度的概念,移动速度一般都是以秒为单位,一秒钟移动几个像素或者距离。

每两帧之间的时间间隔不一定是均匀的,距离由速度*时间间隔得来的,因此要记录一下时间间隔

constructor() {
    this.timedelta = 0;   //这一时刻与上一时刻的时间间隔
    this.has_called_start = false; //标记start函数执行过没
}

完成 step 函数的逻辑:

let last_tiemstamp;  //上一次执行的时刻
const step = timestamp => {
    for(let obj of AC_GAME_OBJECTS) {
        if(!obj.has_called_start) {
        	obj.has_called_start = true;
            obj.start();
        } else {
            obj.timedelta = timestamp - last_timestamp;
            obj.update();
        }
    }
    last_timestamp = timestamp;
}

实现游戏地图

src/assets/scripts 目录下创建一个 GameMap.js 文件

GameMap.js

地图要用到基类,所以导入 AcGameObject

import { AcGameObject } from '@/assets/scripts/AcGameObject'

注意事项:

有时候 import 要用到 {} ,有时候不用;它们的区别是:

  • 如果是 export 的话,就需要用 {} 括起来

  • 如果是 export default 或者全部导入的话,就不用**{}** , 每一个文件只能有一个 default,类似于 java 中的 public class

  • 总结:导入部分,引入非 default 时,使用花括号

构造函数要传两个值 ctx 和 parent,画布和它的父元素,

  • 前端游戏都是在画布标签里画
  • parent 用来动态地修改画布的长、宽

因为未来游戏地图的大小是会动态变化的,因此不要用绝对距离,这里可以先存下每个格子的绝对距离,未来我们存的

位置是相对距离,这里用先用 this.L 来保存下每个格子的绝对距离。

因为它是游戏对象,所以它可以有两个函数 start 和 update

update 每一帧都要执行,每一帧都要渲染,我们可以写一个辅助函数 render ,渲染的意思就是把游戏对象画到地图上,

因此要在 update 里面执行 render

PK 页面

背景没啥用,可以先删了

pk 页面可以存一个游戏区域,为了方便可以写成一个组件命名为 PlayGround.vue

PlayGround.vuehtml 区可以先写 一个 div class = “playground”

然后在 PkIndexView 页面导入该组件

为了方便调试,可以为 PlayGround.vue 添加一些样式

div.playground {
    width: 60vw;  //百分之60的浏览器宽度
    height: 70vh; //百分之70的浏览器高度
    background: lightblue; //背景颜色,浅蓝色
    margin: 40px auto; // margin 表示与上、左的外边距,左用 auto 表示居中,此时地图大小可以自适应浏览器的大小
}

游戏区里面不光包含游戏地图,还有记分板,所以 playground(PlayGround组件里的) 里面还可以搞个板子

所以新建一个组件叫作 GameMap.vue ,然后在组件 PlayGround.vue 里面导入组件 GameMap.vue 并使用

GameMap.vue

html:
<div ref="parent" class="gamemap">
	<canvas ref="canvas">                //画布,游戏放在这里面,ref是为了与下面的js产生关联
    </canvas>
</div>

js:
import { GameMap } from '@/assets/scripts/GameMap'      //为了创建游戏对象
import { ref,onMounted } from 'vue'                     //为了将canvas引入进来,ref是为了使用变量
                                                        //onMounted是组件挂载完之后需要执行哪些操作
export default {
    let parent = ref(null);
    let canvas = ref(null);
    
    onMounted(()=>{
        new GameMap(canvas.value.getContext('2d'),parent.value);
    });
    
    return {
        parent,
        canvas
    }
}
css:
div.gamemap {
    width: 100%;      //100%表示和它的父元素等长
    height: 100%;
}

GameMap.js 增加一个辅助函数 update_size() 来更新最大正方形的边长,其他的简单逻辑就直接写了

实现障碍物

创建组件 Wall.js

然后按照逻辑写就行,更多的是逻辑上的思考,不好做笔记

更改图标

用提供的 logo 替换掉 项目的目录 kob/web/public 下的 favicon.ioc 文件
onMounted } from ‘vue’ //为了将canvas引入进来,ref是为了使用变量
//onMounted是组件挂载完之后需要执行哪些操作
export default {
let parent = ref(null);
let canvas = ref(null);

onMounted(()=>{
    new GameMap(canvas.value.getContext('2d'),parent.value);
});

return {
    parent,
    canvas
}

}
css:
div.gamemap {
width: 100%; //100%表示和它的父元素等长
height: 100%;
}


**GameMap.js** 增加一个辅助函数 **update_size()** 来更新最大正方形的边长,其他的简单逻辑就直接写了

## 实现障碍物

创建组件 **Wall.js** 

然后按照逻辑写就行,更多的是逻辑上的思考,不好做笔记

## 更改图标

用提供的 **logo** 替换掉 项目的目录 **kob/web/public** 下的 **favicon.ioc** 文件 
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以在Vue前端使用Axios发送HTTP请求来与后端的Spring Boot应用进行通信,实现批量删除的功能。以下是一个简单的示例: 在Vue组件中,可以使用Axios发送DELETE请求来批量删除数据。首先,确保你已经在项目中安装了Axios依赖: ``` npm install axios ``` 然后,在Vue组件中,你可以通过以下方式使用Axios发送DELETE请求: ```vue <template> <div> <button @click="deleteData">批量删除</button> </div> </template> <script> import axios from 'axios'; export default { methods: { deleteData() { // 获取要删除的数据的ID列表 const ids = [1, 2, 3]; // 假设这里是要删除的数据的ID列表 // 发送DELETE请求 axios.delete('/api/data', { data: { ids: ids }, // 将ID列表作为请求体发送给后端 }) .then(response => { // 处理删除成功的逻辑 }) .catch(error => { // 处理删除失败的逻辑 }); }, }, }; </script> ``` 在后端的Spring Boot应用中,你可以编写一个接口来处理这个DELETE请求,并实现批量删除的逻辑。以下是一个简单的示例: ```java @RestController @RequestMapping("/api") public class DataController { @DeleteMapping("/data") public ResponseEntity<String> deleteData(@RequestBody Map<String, List<Integer>> request) { List<Integer> ids = request.get("ids"); // 根据ID列表执行批量删除操作 // ... return ResponseEntity.ok("删除成功"); } } ``` 这个示例中,我们使用了`@DeleteMapping`注解来处理DELETE请求,并通过`@RequestBody`注解来接收前端发送的请求体数据。在方法中,我们可以根据ID列表执行批量删除的逻辑。 当删除操作完成后,可以返回一个合适的响应给前端,表示删除成功。在这个示例中,我们返回了一个包含"删除成功"消息的HTTP响应。 这就是使用Spring Boot和Vue前端结合Axios实现批量删除的基本步骤。当然,具体的实现可能因项目的需求而有所不同,你可以根据自己的情况进行相应的调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值