DEV Community

Cover image for Frontend Shorts: Vue.js + Vanilla.js — Digital Dices
Ilona Codes
Ilona Codes

Posted on

Frontend Shorts: Vue.js + Vanilla.js — Digital Dices

Let me show you how you can implement a dice-rolling simulator in less than 30 minutes of your time on the front-end.

Currently, I am playing around with Vue.js. Despite the solution with VanillaJS, I will also present how to code it quickly with Vue.js too.

Let's walk through the process:

Traditionally, we are starting with writing HTML-tree to render two dices:

<!-- index.html | VanillaJS Implementation -->

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Dice Rolling Simulator</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <div id="app" onclick="roll()">
        <div class="dice" data-dots>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>

        <div class="dice" data-dots>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>
    <script src="index.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

There are 2 div-parents with the class .dice, it means there are 2 playing dices on the screen.

The data-dots is an attribute, which represents how many dots will be rendered on the dice after each roll.

The roll() function makes tapping work everywhere, so the user can make a roll upon a click easily.

You already know that you need to generate random numbers for each roll. And here we need to add JavaScript:

// index.js | VanillaJS Implementation

const dices = window.document.querySelectorAll('.dice');

const roll = () => {
    dices.forEach(dice => {
        const dots = Math.floor(Math.random() * 6) + 1;
        dice.setAttribute("data-dots", dots);
    })
};

// first initial roll for when the page loads
roll();
Enter fullscreen mode Exit fullscreen mode

We are going to roll 2 dices at the same time.

Then we need to loop through the dices with forEach method to simulate one of the six dice sides and randomize dice output after each roll: const dots = Math.floor(Math.random() * 6) + 1;

To render the output result, we set data-dots attribute to the corresponding value dots.

The template structure on Vue.js looks a bit differently, but not that much, let's compare:

<!-- index.html | Vue.js Implementation -->

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dice Rolling Simulator</title>
    <link rel="stylesheet" href="./index.css">
</head>
<body>
    <div id="app" v-on:click="roll">
        <div class="dice" 
            v-for="dice in dices" 
            v-bind:data-dots="dice.dots" 
        >
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>
    <script src="./lib/vue-2.6.11.min.js"></script>
    <script src="./index.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
// index.js | Vue.js implementation

const app = new Vue({
    el: '#app',
    data: {
        dices: [
            { dots: 1 },
            { dots: 1 },
        ]
    },

    mounted() {
    // first initial roll for when the component mounts
        this.roll();
    },

    methods: {
        roll() {
            this.dices.forEach(dice => {
                dice.dots = Math.floor(Math.random() * 6) + 1;
            });
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

Every Vue application starts by creating a new Vue instance with the Vue function: const app = new Vue({ // options })

The mounting DOM-element called el; the data object includes the data structure that manages the state of our component.

Additionally, to data properties, Vue instances expose instance properties, hooks, and methods too.

For our example, we have to override the mounted hook to invoke initial "roll()" for when the user loads the page.

In methods, there is a simple method roll() to throw random numbers after each dice roll written in VanillaJS.

To handle click event in the browser to roll dices, v-on:click="roll" has been added to the Vue instance with the #app. To pass the data to the element, you have to bind with v-bind:data-dots="dice.dots".

Last but not least, to make it work appropriately according to the HTML mark-up and scripts, we need CSS-styles:

.dice {
    display: inline-block;
    position: relative;
    border: 3px solid black;
    width: 100px;
    height: 100px;
    margin: 0.5rem;
}

.dice > div {
    content: ' ';
    position: absolute;
    width: 20px;
    height: 20px;
    border-radius: 100%;
}

.dice[data-dots="1"] > :nth-child(1) {
    top: 40px;
    left: 40px;
    background-color: black;
}

.dice[data-dots="2"] > :nth-child(1) {
    top: 20px;
    left: 40px;
    background-color: black;

}

.dice[data-dots="2"] > :nth-child(2) {
    top: 50px;
    left: 40px;
    background-color: black;
}

/* ... see full file here: https://gist.github.com/ilonacodes/b4aef61073129f41fd99b802c7ce8d8c */
Enter fullscreen mode Exit fullscreen mode

It's not the full CSS-file, but here it is important to understand the styling pattern. The example above shows you how to style dots for one dot and two dots on the dice.

It means,

  • if we need to render one dot: .dice[data-dots="1"], we position inside the .dice class its first child: .dice[data-dots="1"] > :nth-child(1) according to position we have written for this selector;

  • if we need to render two dots on the dice: .dice[data-dots="2"] > :nth-child(1) and .dice[data-dots="2"] > :nth-child(2), we just add styles to the second child within the styles of the first child.

For rendering three dots on the dice:
.dice[data-dots="3"] > :nth-child(1), .dice[data-dots="3"] > :nth-child(2), .dice[data-dots="3"] > :nth-child(3)

For rendering four dots on the dice:
.dice[data-dots="4"] > :nth-child(1), .dice[data-dots="4"] > :nth-child(2), .dice[data-dots="4"] > :nth-child(3), .dice[data-dots="4"] > :nth-child(4)

And so on till the dice[data-dots="6"] included.

Dice Rolling Simulator

That's it for now. Let me know if you find these frontend code snippets useful or joyful for you.

Thank you for reading! 🙏

Code your best,
Ilona Codes

Top comments (3)

Collapse
 
gtanyware profile image
Graham Trott • Edited

This looked like a good way to spend an hour or so of lockdown (as well as providing a neat addition to my collection of demos), so I prototyped the same thing using my own DSL. My main aim was to see how efficient I could make the algorithm for drawing the dots, so I used a table of coordinates, with 6 rows each having 6 pairs of values that specify the top/left coordinates of a dot, which is itself constructed as a rounded DIV with absolute positioning. The renderer runs along the row for the dot count requested and stops when it hits a zero. I added a simple animation for when a dice is clicked.

I've put it up on a demo website. The script is in the BODY of the page and is compiled and run by a JS library called in by the HEAD. The actual code looks like this:

!   Twin dice roller

    script DiceRoller

    div Screen
    div Dice
    div Dot
    variable NDice
    variable M
    variable N
    variable D
    variable Index
    variable Row
    variable Dots
    variable Patterns
    variable Left
    variable Top

!   Set up constants
    put 2 into NDice
!   Poke some CSS styles into the HEAD
    set style `.ec-dice` to `{width:100px;height:100px;margin:20px;`
        cat `background:yellow;border:1px solid black;display:inline-block;`
        cat `position:relative}`
    set style `.ec-dot` to `{width:20px;height:20;position:absolute;`
        cat `background:black;border-radius: 10px}`

!   'Patterns' contains 6 rows of data. Each is a set of 6 top/left pairs
!   to set the dot positions. Iteration stops at the first zero.
    set Patterns to
        40 40  0  0  0  0  0  0  0  0  0  0
        10 40 70 40  0  0  0  0  0  0  0  0
        10 40 40 40 70 40  0  0  0  0  0  0
        10 10 70 10 10 70 70 70  0  0  0  0
        10 10 70 10 10 70 70 70 40 40  0  0
        10 10 10 70 40 10 40 70 70 10 70 70

!   Create the screen
    create Screen
    set the style of Screen to `padding:1em`
    set the elements of Dice to NDice

!   Draw or redraw
Redraw:
!   Run the randomiser 10 times to simulate the dice spinning
    put 0 into M
    while M is less than 10
    begin
!       Create a single dice
        put 0 into N
        while N is less than NDice
        begin
            index Dice to N
            remove element Dice
            create Dice in Screen
            set the class of Dice to `ec-dice`
            gosub to RandomiseDots
            add 1 to N
        end
        wait 10 ticks
        add 1 to M
    end
    on click Dice go to Redraw
    stop

!   Randomize the dots for a single dice
!   This is done by reading from the appropriate row of the data table.
RandomiseDots:
    put random 6 into Dots
    multiply Dots by 12 giving Row
    put 0 into D
    while D is less than 12
    begin
        add D to Row giving Index
        index Patterns to Index
        put Patterns into Top
        add 1 to D
        if Top is not 0
        begin
            add 1 to Index
            index Patterns to Index
            put Patterns into Left
            create Dot in Dice
            set the class of Dot to `ec-dot`
            set style `top` of Dot to Top
            set style `left` of Dot to Left
            on click Dot go to Redraw
        end
        add 1 to D
    end
    return
Collapse
 
name123star profile image
name123-star • Edited

Hi, I am learning Vue JS currently and was facing some difficulty grasping it and was searching online for tips when I landed on this post. I am creating an essay writing service website using Vue. I really liked Vue a lot as it is a lot cleaner than vanilla js. I would contact if I face any difficulty with my code.

Collapse
 
coldestheart profile image
Ilia (COLD) • Edited

Sory, but worstest way to play around with Vue is: "script src="./lib/vue-2.6.11.min.js"></script"
And telling it to others.
Vue is not so different from other frameworks.
To feel Vue, and how it could be powerfull, i think, you need to create vue-node project(or maybe better Nuxt Project) and try features assigned to it, how like a people usually says: "The devil's always in the details"
Anyway this code could be refactored by using only vuejs and this will be right way.