js bind 传参、_Vue.js 记忆卡片项目实战

74e922d6-f217-eb11-8da9-e4434bdf6706.jpeg

Photo by Nada Gamal on Unsplash

如果你刚开始学习 Vue,想巩固基础知识,那么你可以试试通过这个有趣的练习来创建一个好玩的游戏。

在这篇文章中,我将逐步教你用 Vue.js 创建一个记忆卡片游戏。

这篇文章会介绍以下知识点:

- 使用 v-for 命令循环遍历一个数组对象

- 使用 v-bind 指令动态控制类名和样式

- 添加 Methods  和 Computed 属性

- 通过 Vue.set 方法向一个对象动态添加属性

- 使用 setTimeout 方法延迟 JavaScript 插件加载

- JavaScript 对象的浅拷贝和深拷贝

- 使用 Lodash 工具库

我们开始学习吧。

准备(包括项目所需的库)

第一步很简单,从 CDN 导入库到我们的 HTML5 基础代码中,这样就可以开始我们的小型项目了。

html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Memory Card Gametitle>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
head>
<body>

body>
html>

允许用户看到卡片网格

接下来,我们定义一些必要的 HTML 页面结构、CSS 样式和一个基础的 Vue 实例,这样用户就看得到这些卡片网格了。

Vue 实例

创建一个 Vue 的实例,在 data 属性内部定义一个 cards 属性用于存放卡片列表。

let app = new Vue({
    el: '#app',
    data:{
            cards: [
                {
                    name: 'Apple',
                    img: 'apple.gif',

                },
                {
                    name: 'Banana',
                    img: 'banana.gif',

                },
                {
                    name: 'Orange',
                    img: 'orange.jpg',

                },
                {
                    name: 'Pineapple',
                    img: 'pineapple.png',

                },
                {
                    name: 'Strawberry',
                    img: 'strawberry.png',

                },
                {
                    name: 'watermelon',
                    img: 'watermelon.jpg',

                },
            ],
    },
});

数组内的每个对象包含两个属性:图片的名字(用于匹配)和卡片上的图片。

HTML

我们已经在 Vue 实例中准备好了数据,可以在 VueJS 中通过 v-for 指令循环遍历它们。

<div id="app">
    <div class="row">
        <div class="col-md-6 col-lg-6 col-xl-5 mx-auto">
             <div class="row justify-content-md-center">
                    <div v-for="card in cards" class="col-auto mb-3 flip-container">
                    <div class="memorycard">
                        <div class="front border rounded shadow"><img width="100" height="150" src="/assets/images/memorycard/pattern3.jpeg">div>
                        <div class="back rounded border"><img width="100" height="150" :src="'/assets/images/memorycard/'+card.img">div>
                    div>
                 div>
            div>
        div>
    div>
    div>

我们使用了一些基础的 Bootstrap 框架内容搭配 VueJS 的 v-for 指令来循环遍历这些卡片,让它们以网格的形式展示出来。

每张记忆卡片由两部分组成:

- 正面:这里是一张所有卡片都会用到的公共图片(默认卡片显示的样子)

- 背面:这里包含每张卡片实际的图片(默认设置为隐藏)

添加一些基础的 CSS 样式,这样我们就只展示卡片的正面(默认卡片显示的样子):

.flip-container {
        -webkit-perspective: 1000;
        -moz-perspective: 1000;
        -o-perspective: 1000;
        perspective: 1000;
        min-height: 120px;
        cursor: pointer;
    }
    .front,
    .back {
        -webkit-backface-visibility: hidden;
        -moz-backface-visibility: hidden;
        -o-backface-visibility: hidden;
        backface-visibility: hidden;
        -webkit-transition: 0.6s;
        -webkit-transform-style: preserve-3d;
        -moz-transition: 0.6s;
        -moz-transform-style: preserve-3d;
        -o-transition: 0.6s;
        -o-transform-style: preserve-3d;
        -ms-transition: 0.6s;
        -ms-transform-style: preserve-3d;
        transition: 0.6s;
        transform-style: preserve-3d;
        top: 0;
        left: 0;
        width: 100%;
    }
    .back {
        -webkit-transform: rotateY(-180deg);
        -moz-transform: rotateY(-180deg);
        -o-transform: rotateY(-180deg);
        -ms-transform: rotateY(-180deg);
        transform: rotateY(-180deg);
        position: absolute;
    }

刷新页面,然后你应该看到 6 张正面的卡片以网格的形式展示,而每张卡片上的图片隐藏在背面。

76e922d6-f217-eb11-8da9-e4434bdf6706.png

卡片的正面(通过 v-for 循环指令展示)

翻转卡片

接下来,给卡片绑定一个事件,这样每当我们点击时,它应该翻转并显示背面的图片。

在原始的卡片数组的基础上添加另一个属性。这将确定当前卡片是否被翻转。

添加下面的 CSS 样式。当类名 flipped 添加到卡片的类名上时,将展示卡片的背面。同时,该样式可以设置一个好看的翻转动效。

 .flip-container.flipped .back {
        -webkit-transform: rotateY(0deg);
        -moz-transform: rotateY(0deg);
        -o-transform: rotateY(0deg);
        -ms-transform: rotateY(0deg);
        transform: rotateY(0deg);
    }
    .flip-container.flipped .front {
        -webkit-transform: rotateY(180deg);
        -moz-transform: rotateY(180deg);
        -o-transform: rotateY(180deg);
        -ms-transform: rotateY(180deg);
        transform: rotateY(180deg);
    }

使用 Vue 的 created 生命周期函数添加新的属性,然后添加一个 flipCard 方法来翻转卡片。

  created(){
        this.cards.forEach((card) => {
            card.isFlipped = false;
        });
    },

    methods:{
        flipCard(card){
            card.isFlipped = true;
        }
    }

给卡片绑定点击事件,调用 flipCard 方法,然后使用 v-bind 指令给卡片绑定 flipped 类。

 ...
for="card in cards" class="col-auto mb-3 flip-container" :class="{ 'flipped': card.isFlipped }" @click="flipCard(card)">
 ...

似乎还不错,我们看看点击一下卡片是否会翻转。

78e922d6-f217-eb11-8da9-e4434bdf6706.gif点击卡片未翻转

这个方法行不通,为什么呢?

回到刚才在生命周期函数中,我们在那里遍历卡片列表,并添加了一个新的属性,isFlipped——看上去没问题,但是 Vue 不喜欢这样。

想要让一个对象上新的属性生效,你需要使用 Vue.set 方法将它们添加到对象中。

   created(){
        this.cards.forEach((card) => {
            Vue.set(card,'isFlipped',false)
        });
    },

现在卡片应该在点击时会翻转了:

7be922d6-f217-eb11-8da9-e4434bdf6706.gif

挺好的!我们继续写代码。

匹配和洗牌

对,没错!使用这些卡片制作一个记忆游戏,我们需要每张卡片都正好有跟它匹配的卡片。同时我们也需要在游戏开始时清洗卡片的排列顺序。

在 Vue 实例中添加一个 memoryCards 属性,存放翻转过的卡片(也就是说,每张翻转后的卡片,都有另一张卡片和它背面的图片)。

 ...
memoryCards: [],
...

匹配

将卡片数组拼接起来,赋值给 memoryCards 属性,以实现每两张卡片背面的图片相同。

改变在 HTML 中的 v-for 指令遍历对象,让它从原来的 cards 数组改变到 memoryCards 数组。

 
for="card in memoryCards" class="col-auto mb-3 flip-container" :class="{ 'flipped': card.isFlipped }" @click="flipCard(card)">

然后,修改 created 方法,将数组拼接到 memoryCards 中:

 created(){
        this.cards.forEach((card) => {
            Vue.set(card,'isFlipped',false)
        });

        var cards1 = this.cards;
        var cards2 = this.cards;
        this.memoryCards = this.memoryCards.concat(cards1, cards2);
    },

是不是挺简单?

但这么做有两个问题:

- 直接让 cards1 等于 this.cards,并不能产生一个新的用于匹配的 cards 对象,cards1 指向的仍然是原始对象。

- cards1 和 cards2 指的是同一个对象。

改变 memoryCards 对象中的任何属性会引起两个匹配的数组同时变化。

7fe922d6-f217-eb11-8da9-e4434bdf6706.gif

我们可以试试用深拷贝来解决这个问题。

什么是深拷贝?

对于对象或数组中包含其他对象和数组的情况,要想拷贝这些元素需要通过深拷贝。否则,当改变嵌套引用上的数据时,原始对象和数组中的数据也会发生改变。

进行深拷贝的方法有很多,我们将使用最简单也是最常用的方法,使用 Lodash 库。

那么,什么是 Lodash 库?

Lodash 处理了对数组、数字、对象、字符串等类型的一些复杂操作,让 JavaScript 变得更方便使用。

在这个例子中,Lodash 有一个方法能让深拷贝的操作变得极其简单。

首先,通过下载源码或者使用 CDN 引用将 Lodash 包含在页面中。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值