半天快速用vue搭建小游戏——“花光马云的钱”

本文字数

本文总计1791字,预计花费15分钟。

先看半成品

预览图
预览1
预览11

在线地址:点我

扫码查看:二维码

github地址,希望小伙伴门能点个star~~:点我

本文适合人群

有一点点前端基础的,对vue有一点点了解的,知道基本语法的。

本文没有什么高级技巧,毕竟本人也是个小菜鸡。

下文主要讨论逻辑是怎么实现的,也就是js怎么写的,css建议直接复制本人GitHub里的。本人css水平也是一言难尽。。

技术栈

vue + vue-router + vant

没有使用用vuex,组件间使用eventBus进行通信(其实就是三两行代码,一切从简)

构建过程

  1. vue-cli初始化项目

    这个就不详细介绍了。

    首先保证安装了全局vue-cli脚手架,如果没有的话:

    npm install -g @vue/cli

    创建vue项目:

    vue create spend-all-money

    本文使用vant ui框架,进入spend-all-money目录,运行

    npm i vant -S
  2. 代码目录及基本结构

    目录:

    目录结构如上,不复杂。

    需要注意的是,我的所有vant组件引用都放到了src/vantImport.js里,并在main.js里引用了该文件。下文所有使用到的vant组件都已在该处进行引用,不再赘述。

    eventBus.js代码如下:

    import Vue from "vue";
    
    export default new Vue();

    同时在main.js里将其绑定到全局vue上:

    import bus from "./eventBus";
    
    Vue.prototype.$bus = bus;
    Vue.config.productionTip = false;

    这样在其他组件里可以使用this.$bus.$emit(......)或this.$bus.$on(....)进行发送和接收消息。

  3. 登录界面

    首先要做的是登录界面,大概就是两个按钮——“单机开始”和“网络开始”,其中“网络开始”留个坑,有空把后端写好再填坑。(ps:nest.js写起来真爽,typescript万岁)。

    首先新建src/views/Main/index.vue,然后在src/router/index.js里配置下路由。

    ....some code.....
    import Main from "../views/Main/index";  
    const routes = [
        {
            path: "/",
            name: "main",
            component: Main
          }
     ];
    ......somde code.......

    完成之后在src/views/Main/index.vue里编写具体代码。

    html如下:

        <!--    开始游戏-->
        <div class="main-start">
          <van-button
            round
            size="large"
            color="linear-gradient(to right, #4bb0ff, #6149f6)"
            class="main-start-btn"
            to="/single"
            >单机开始</van-button
          >
          <van-button
            round
            size="large"
            color="linear-gradient(to right, #4bb0ff, #6149f6)"
            class="main-start-btn"
            @click="goNetGame"
            >网络开始</van-button
          >
        </div>

    创建了两个vant-button,并将单机开始的link设置到具体游戏界面的路由。

    js部分没有什么需要写的,goNetGame方法使用了一个提示,留坑代填。

        // todo:网络游戏
        goNetGame() {
          this.$toast("敬请期待");
        }
  4. 单机游戏界面

    啰嗦一堆终于终于来到具体的游戏界面了。

    首先将游戏界面以组件化的思想进行拆分,大体可分为头部(马云头像)、总资产(粘性布局,页面往下划动时始终黏在页面最上方)、物品卡片。

    游戏界面就是以上几者的组合,其中物品卡片会有很多,用v-for进行循环渲染。

    html如下:

    <template>
      <div class="single">
        <HeaderLink></HeaderLink>
        <Header></Header>
        <TotalMoney></TotalMoney>
        <Card
          v-for="(item, i) in goodsList"
          :key="i"
          :name="item.name"
          :price="item.price"
          :image-url="item.imageUrl"
        ></Card>
      </div>
    </template>

    js如下:

    <script>
    import Header from "../../components/Header";
    import TotalMoney from "../../components/TotalMoney";
    import HeaderLink from "../../components/HeaderLink";
    import Card from "../../components/Card";
    import { mixin } from "./minxin";
    
    export default {
      mixins: [mixin],
      name: "single",
      components: {
        Card,
        HeaderLink,
        Header,
        TotalMoney
      }
    };
    </script>

mixin为src/views/SingleGame/mixin.js文件,里面包含了物品卡片的信息,如物品name、price、imageUrl等。因其太长,不把代码列出来了,直接给个文件链接,点我。如果小伙伴想要自己修改或者新增物品的话,也是在这个文件里进行修改哦。

完成后配置路由如下:

   const routes = [
  {
       path: "/",
       name: "main",
       component: Main
     },
     {
       path: "/single",
       name: "single",
       component: () => import("../views/SingleGame/")
     }
   ];

接下来可以编写具体的组件啦。

  1. 头部——马云照片

    新建src/components/Header.vue,其中html代码如下:

    <template>
      <div class="j-header">
        <van-image round width="8rem" height="8rem" src="mayun.jpg" />
        <div style="font-size: 25px">花 光 马 云 的 钱</div>
      </div>
    </template>

    主要就是一个展示作用,不需要什么js代码。

  2. 头部——总资产

    新建src/components/TotalMoney.vue,其中html代码如下:

    <template>
      <van-sticky>
        <div class="totalMoney">
          <div class="totalMoney-text">{{ monenyStr }}</div>
        </div>
      </van-sticky>
    </template>

    js代码如下:

    <script>
    export default {
      name: "TotalMoney",
    
      data() {
        return {
          totalMoney: 275000000000
        };
      },
    
      computed: {
        monenyStr() {
          let moneyStr = this.toThousandsStr(this.totalMoney);
          moneyStr = `剩余:¥${moneyStr}`;
          return moneyStr;
        }
      },
    
      created() {
        this.$bus.$on("changeMoney", money => {
          this.totalMoney = this.totalMoney - money;
        });
      },
    
      methods: {
        /**
         * 数字转字符串,并添加逗号
         * @param num
       */
      toThousandsStr(num) {
        let result;
        (num = (num || 0).toString()), (result = "");
        while (num.length > 3) {
          result = "," + num.slice(-3) + result;
          num = num.slice(0, num.length - 3);
        }
        if (num) {
          result = num + result;
        }
        return result;
      }
    }
  };
  </script>
  ```

  js代码定义了总钱数,并将其转为字符串,在数字间添加逗号以方便读。

      this.$bus.$on("changeMoney", money => {
        this.totalMoney = this.totalMoney - money;
      });
  上面这段代码可以监听其他组件发送来的消息,修改总钱数。
  1. 物品卡片

    新建src/components/Card.vue。

    html代码如下:

    <template>
      <div class="card">
        <!--    图片-->
        <van-image
          width="100"
          height="100"
          lazy-load
          :src="imageUrl"
          class="card-image"
        />
        <!--    名称-->
        <div class="card-name">{{ name }}</div>
        <!--    价格-->
        <div class="card-price">¥{{ priceStr }}</div>
        <!--    按钮-->
        <van-row class="card-control">
          <!--      卖-->
          <van-col span="8">
            <van-button
              type="danger"
              class="card-control-btn"
              @click="changeCount(-1)"
              >卖</van-button
            >
          </van-col>
          <!--      数量-->
          <van-col span="8">
            <van-field
              placeholder="0"
              input-align="center"
              style="border-style: solid; border-width: 1px"
              v-model="countStr"
              type="number"
              :clickable="true"
              maxlength="10"
            />
          </van-col>
          <!--      买-->
          <van-col span="8">
            <van-button
              type="primary"
              class="card-control-btn"
              @click="changeCount(1)"
              >买</van-button
            >
          </van-col>
        </van-row>
      </div>
    </template>

    理解一下以上代码,主要将一个卡片分为图片、价格、名称、买卖按钮以及数量输入框。

    js代码如下:

    <script>
    export default {
      name: "Card",
    
      props: {
        name: { type: String, default: "测试" },
        imageUrl: { type: String, default: "https://img.yzcdn.cn/vant/cat.jpeg" },
        price: { type: Number, default: 999 }
      },
    
      data() {
        return {
          count: 0,
          keyboardShown: false
        };
      },
    
      computed: {
        // 将数字转成字符串
        // todo:小数负数需要做进一步处理
        countStr: {
          get() {
            return this.count.toString();
          },
          set(newVal) {
            let counInt = parseInt(newVal);
            if (isNaN(counInt) || counInt <= 0) {
              counInt = 0;
            }
            this.count = counInt;
          }
        },
    
        priceStr: {
          get() {
            return this.toThousandsStr(this.price);
          }
        },
    
        // 该卡片的总价格:数量*单价
        cardMoney: {
          get() {
            return this.count * this.price;
          }
        }
      },
    
      watch: {
        // 监听总价值的改变并发送消息给总资产组件
        cardMoney(val, oldVal) {
          const diff = val - oldVal;
          // eslint-disable-next-line no-console
          console.log(val, oldVal);
          this.$bus.$emit("changeMoney", diff);
        }
      },
    
      methods: {
        changeCount(val) {
          if (this.count <= 0 && val < 0) {
            return;
          }
          this.count += val;
        },
    
        // todo:两个地方用到,后续可以单独出来
        /**
         * 数字转字符串,并添加逗号
         * @param num
       */
      toThousandsStr(num) {
        let result;
        (num = (num || 0).toString()), (result = "");
        while (num.length > 3) {
          result = "," + num.slice(-3) + result;
          num = num.slice(0, num.length - 3);
        }
        if (num) {
          result = num + result;
        }
        return result;
      }
    }
  };
  </script>
  ```

  这段代码说明该调用该组件时需要传入三个参数:物品名称(name)、物品图片链接(imageUrl)、物品价格(price)。

  点击买和卖时修改对应物品数量(count),监听count以获取该物品卡片的总价值(count*price),并在总价值发生变化时将变化值发送出去。

  ### 5. 总结

  以上就完成了所有功能的编写,是不是特别简单呢。觉得有帮助的话点个赞和star吧~

  github地址:[点我]( https://github.com/QJvic/spend-all-mone )

TODO:

1.阻止总资产变成负数。

2.写个成就功能,当花掉多少钱时弹出彩蛋。

3.完成在线联机功能。


JoeVic
1 声望0 粉丝