diff --git a/src/tutorial/src/step-1/description.md b/src/tutorial/src/step-1/description.md index d2ed2c9a59..c753f979f6 100644 --- a/src/tutorial/src/step-1/description.md +++ b/src/tutorial/src/step-1/description.md @@ -1,25 +1,38 @@ -# Adding Data +# Adding Reactive Properties -For now, our component renders some static data. Try to change a number 3 in the code to something different to see how the rendered result changes. - -Let's add some dynamic data. Within component `data` return statement, add a property `colorsNumber`. +:::tip WIP +The tutorial is currently work in progress. Check back later! +::: For now, our component renders some static data. Try to change a number 3 in the code to something different to see how the rendered result changes. -Let's add some dynamic data. Within component `data` return statement, add a property `colorsNumber`. +How to make it dynamic? We need to create our first _reactive_ property `colorsNumber` -For now, our component renders some static data. Try to change a number 3 in the code to something different to see how the rendered result changes. +
-Let's add some dynamic data. Within component `data` return statement, add a property `colorsNumber`. +```js +data() { + return { + colorsNumber: 3 + } +} +``` -For now, our component renders some static data. Try to change a number 3 in the code to something different to see how the rendered result changes. +
-Let's add some dynamic data. Within component `data` return statement, add a property `colorsNumber`. +
-For now, our component renders some static data. Try to change a number 3 in the code to something different to see how the rendered result changes. +```js +import { ref } from 'vue' +const colorsNumber = ref(3) +``` -Let's add some dynamic data. Within component `data` return statement, add a property `colorsNumber`. +
-For now, our component renders some static data. Try to change a number 3 in the code to something different to see how the rendered result changes. +Now, we can use it in our template instead of a static number: + +```html +

Number of colors: {{ colorsNumber }}

+``` -Let's add some dynamic data. Within component `data` return statement, add a property `colorsNumber`. +Try to change the `colorsNumber` and check how it immediately updates the rendered HTML. diff --git a/src/tutorial/src/step-2/App/composition.js b/src/tutorial/src/step-2/App/composition.js index 2b5a52c75e..fa61e67fc2 100644 --- a/src/tutorial/src/step-2/App/composition.js +++ b/src/tutorial/src/step-2/App/composition.js @@ -2,5 +2,9 @@ import { ref } from 'vue' export default { name: 'App', - setup() {} + setup() { + const colorsNumber = ref(3) + + return { colorsNumber } + } } diff --git a/src/tutorial/src/step-2/App/options.js b/src/tutorial/src/step-2/App/options.js index aa6e952b89..d9b4727a56 100644 --- a/src/tutorial/src/step-2/App/options.js +++ b/src/tutorial/src/step-2/App/options.js @@ -1,6 +1,8 @@ export default { name: 'App', data() { - return {} + return { + colorsNumber: 3 + } } } diff --git a/src/tutorial/src/step-2/App/style.css b/src/tutorial/src/step-2/App/style.css new file mode 100644 index 0000000000..1098ac353b --- /dev/null +++ b/src/tutorial/src/step-2/App/style.css @@ -0,0 +1,28 @@ +* { + margin: 0; + padding: 0; +} + +#app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #2c3e50; +} + +label { + font-size: 18px; +} + +input { + font-size: 18px; + padding-left: 5px; + width: 35px; +} + +.panel { + color: white; + background-color: teal; + transition: background 0.5s; +} diff --git a/src/tutorial/src/step-2/App/template.html b/src/tutorial/src/step-2/App/template.html index 8fa2da1d10..0ed513091c 100644 --- a/src/tutorial/src/step-2/App/template.html +++ b/src/tutorial/src/step-2/App/template.html @@ -1 +1,6 @@ -

Step 2!

+
+
+

Guess the Color

+

Number of colors: {{ colorsNumber }}

+
+
diff --git a/src/tutorial/src/step-2/description.md b/src/tutorial/src/step-2/description.md index 06d6fa89dd..acd8bb2ef8 100644 --- a/src/tutorial/src/step-2/description.md +++ b/src/tutorial/src/step-2/description.md @@ -1 +1,17 @@ -# Two-way Binding +# Binding Dynamic Attributes + +Let's make our example more interactive! What if we could allow user to change `colorsNumber` from the UI? To implement this, we need to start with adding an `` field to our component template + +```html{4} +
+

Guess the Color

+

Number of colors: 3

+ +
+``` + +Now, we have to provide some initial value to our input, and we want to display `colorsNumber` there. In Vue, we can use a `v-bind` directive or its shorthand `:` to bind the component reactive property to the element attribute: + +```html + +``` diff --git a/src/tutorial/src/step-3/App/composition.js b/src/tutorial/src/step-3/App/composition.js new file mode 100644 index 0000000000..fa61e67fc2 --- /dev/null +++ b/src/tutorial/src/step-3/App/composition.js @@ -0,0 +1,10 @@ +import { ref } from 'vue' + +export default { + name: 'App', + setup() { + const colorsNumber = ref(3) + + return { colorsNumber } + } +} diff --git a/src/tutorial/src/step-3/App/options.js b/src/tutorial/src/step-3/App/options.js new file mode 100644 index 0000000000..d9b4727a56 --- /dev/null +++ b/src/tutorial/src/step-3/App/options.js @@ -0,0 +1,8 @@ +export default { + name: 'App', + data() { + return { + colorsNumber: 3 + } + } +} diff --git a/src/tutorial/src/step-3/App/style.css b/src/tutorial/src/step-3/App/style.css new file mode 100644 index 0000000000..1098ac353b --- /dev/null +++ b/src/tutorial/src/step-3/App/style.css @@ -0,0 +1,28 @@ +* { + margin: 0; + padding: 0; +} + +#app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #2c3e50; +} + +label { + font-size: 18px; +} + +input { + font-size: 18px; + padding-left: 5px; + width: 35px; +} + +.panel { + color: white; + background-color: teal; + transition: background 0.5s; +} diff --git a/src/tutorial/src/step-3/App/template.html b/src/tutorial/src/step-3/App/template.html new file mode 100644 index 0000000000..96c6b08ad8 --- /dev/null +++ b/src/tutorial/src/step-3/App/template.html @@ -0,0 +1,7 @@ +
+
+

Guess the Color

+

Number of colors: {{ colorsNumber }}

+ +
+
diff --git a/src/tutorial/src/step-3/description.md b/src/tutorial/src/step-3/description.md new file mode 100644 index 0000000000..3c119b88c8 --- /dev/null +++ b/src/tutorial/src/step-3/description.md @@ -0,0 +1,15 @@ +# Listening to Events + +Now we can see that `colorsNumber` is displayed on the input field. However, when we change the number in the input, we don't see any changes on `Number of colors` in the template 🤔. It happens because we only have _one-way binding_ now, displaying reactive property in the input field but not _changing_ it on user input. + +To make this change, we need to listen to the `input` DOM event on the `` field and update `colorsNumber` on it. This can be done with Vue's `v-on` directive or its shorthand `@`: + +```html + +``` + +`$event` is the HTML native [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event)(in our case it's `input`). diff --git a/src/tutorial/src/step-4/App/composition.js b/src/tutorial/src/step-4/App/composition.js new file mode 100644 index 0000000000..fa61e67fc2 --- /dev/null +++ b/src/tutorial/src/step-4/App/composition.js @@ -0,0 +1,10 @@ +import { ref } from 'vue' + +export default { + name: 'App', + setup() { + const colorsNumber = ref(3) + + return { colorsNumber } + } +} diff --git a/src/tutorial/src/step-4/App/options.js b/src/tutorial/src/step-4/App/options.js new file mode 100644 index 0000000000..d9b4727a56 --- /dev/null +++ b/src/tutorial/src/step-4/App/options.js @@ -0,0 +1,8 @@ +export default { + name: 'App', + data() { + return { + colorsNumber: 3 + } + } +} diff --git a/src/tutorial/src/step-4/App/style.css b/src/tutorial/src/step-4/App/style.css new file mode 100644 index 0000000000..1098ac353b --- /dev/null +++ b/src/tutorial/src/step-4/App/style.css @@ -0,0 +1,28 @@ +* { + margin: 0; + padding: 0; +} + +#app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #2c3e50; +} + +label { + font-size: 18px; +} + +input { + font-size: 18px; + padding-left: 5px; + width: 35px; +} + +.panel { + color: white; + background-color: teal; + transition: background 0.5s; +} diff --git a/src/tutorial/src/step-4/App/template.html b/src/tutorial/src/step-4/App/template.html new file mode 100644 index 0000000000..5fb77d43c0 --- /dev/null +++ b/src/tutorial/src/step-4/App/template.html @@ -0,0 +1,7 @@ +
+
+

Guess the Color

+

Number of colors: {{ colorsNumber }}

+ +
+
diff --git a/src/tutorial/src/step-4/description.md b/src/tutorial/src/step-4/description.md new file mode 100644 index 0000000000..b5b23ea51c --- /dev/null +++ b/src/tutorial/src/step-4/description.md @@ -0,0 +1,16 @@ +# Two-Way Binding + +In the previous step we created a _two-way binding_: we update `input` field on reactive property change and vice versa. Vue.js has a `v-model` directive to make two-way binding less verbose. Let's replace out `:value` and `@input` with it: + +```html + +``` + +Now, we can choose how many colors we'll have in our guessing game! As a last touch, let's add a label to our input field and set up minimum and maximum for it: + +```html + +``` diff --git a/src/tutorial/src/step-5/App/composition.js b/src/tutorial/src/step-5/App/composition.js new file mode 100644 index 0000000000..fa61e67fc2 --- /dev/null +++ b/src/tutorial/src/step-5/App/composition.js @@ -0,0 +1,10 @@ +import { ref } from 'vue' + +export default { + name: 'App', + setup() { + const colorsNumber = ref(3) + + return { colorsNumber } + } +} diff --git a/src/tutorial/src/step-5/App/options.js b/src/tutorial/src/step-5/App/options.js new file mode 100644 index 0000000000..d9b4727a56 --- /dev/null +++ b/src/tutorial/src/step-5/App/options.js @@ -0,0 +1,8 @@ +export default { + name: 'App', + data() { + return { + colorsNumber: 3 + } + } +} diff --git a/src/tutorial/src/step-5/App/style.css b/src/tutorial/src/step-5/App/style.css new file mode 100644 index 0000000000..4280ff054c --- /dev/null +++ b/src/tutorial/src/step-5/App/style.css @@ -0,0 +1,56 @@ +* { + margin: 0; + padding: 0; +} + +#app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #2c3e50; +} + +label { + font-size: 18px; +} + +input { + font-size: 18px; + padding-left: 5px; + width: 35px; +} + +.panel { + color: white; + background-color: teal; + transition: background 0.5s; +} + +nav { + display: flex; + height: 30px; + justify-content: space-between; + align-items: center; + padding: 0 20px; + background-color: white; + color: teal; + font-size: 16px; + text-transform: uppercase; +} + +nav button { + text-transform: uppercase; + padding: 0 8px; + height: 100%; + font-size: 16px; + background-color: white; + border: none; + cursor: pointer; + color: teal; +} + +nav button:hover { + background-color: teal; + color: white; +} diff --git a/src/tutorial/src/step-5/App/template.html b/src/tutorial/src/step-5/App/template.html new file mode 100644 index 0000000000..de225285ef --- /dev/null +++ b/src/tutorial/src/step-5/App/template.html @@ -0,0 +1,10 @@ +
+
+

Guess the Color

+

Number of colors: {{ colorsNumber }}

+ +
+
diff --git a/src/tutorial/src/step-5/description.md b/src/tutorial/src/step-5/description.md new file mode 100644 index 0000000000..c8e8120259 --- /dev/null +++ b/src/tutorial/src/step-5/description.md @@ -0,0 +1,41 @@ +# Conditional Rendering + +It's time to actually make our game start. For now, we want to have two states: + +- game is not started: we are displaying our input field so user can define the number of colors to guess; +- game is started: for now, we want to hide the input field and we want to display a text "Game is started". + +Let's start with creating one more reactive property - `gameStarted`: + +
+ +```js{2} +const colorsNumber = ref(3) +const gameStarted = ref(false) +``` + +
+ +
+ +```js{4} +data() { + return { + colorsNumber: 3, + gameStarted: false + } +} +``` + +
+ +Let's display a new `section` only when game is started. We will use `v-if` directive for this: + +```html{4} +
+ +
+
Game is started
+``` + +Try to change `gameStarted` to `true` and you will see a text rendered below the header. diff --git a/src/tutorial/src/step-6/App/composition.js b/src/tutorial/src/step-6/App/composition.js new file mode 100644 index 0000000000..1ac71c4024 --- /dev/null +++ b/src/tutorial/src/step-6/App/composition.js @@ -0,0 +1,11 @@ +import { ref } from 'vue' + +export default { + name: 'App', + setup() { + const colorsNumber = ref(3) + const gameStarted = ref(false) + + return { colorsNumber, gameStarted } + } +} diff --git a/src/tutorial/src/step-6/App/options.js b/src/tutorial/src/step-6/App/options.js new file mode 100644 index 0000000000..511a8196bc --- /dev/null +++ b/src/tutorial/src/step-6/App/options.js @@ -0,0 +1,9 @@ +export default { + name: 'App', + data() { + return { + colorsNumber: 3, + gameStarted: false + } + } +} diff --git a/src/tutorial/src/step-6/App/style.css b/src/tutorial/src/step-6/App/style.css new file mode 100644 index 0000000000..4280ff054c --- /dev/null +++ b/src/tutorial/src/step-6/App/style.css @@ -0,0 +1,56 @@ +* { + margin: 0; + padding: 0; +} + +#app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #2c3e50; +} + +label { + font-size: 18px; +} + +input { + font-size: 18px; + padding-left: 5px; + width: 35px; +} + +.panel { + color: white; + background-color: teal; + transition: background 0.5s; +} + +nav { + display: flex; + height: 30px; + justify-content: space-between; + align-items: center; + padding: 0 20px; + background-color: white; + color: teal; + font-size: 16px; + text-transform: uppercase; +} + +nav button { + text-transform: uppercase; + padding: 0 8px; + height: 100%; + font-size: 16px; + background-color: white; + border: none; + cursor: pointer; + color: teal; +} + +nav button:hover { + background-color: teal; + color: white; +} diff --git a/src/tutorial/src/step-6/App/template.html b/src/tutorial/src/step-6/App/template.html new file mode 100644 index 0000000000..bcd0001455 --- /dev/null +++ b/src/tutorial/src/step-6/App/template.html @@ -0,0 +1,11 @@ +
+
+

Guess the Color

+

Number of colors: {{ colorsNumber }}

+ +
+
Game is started
+
diff --git a/src/tutorial/src/step-6/description.md b/src/tutorial/src/step-6/description.md new file mode 100644 index 0000000000..9d32374265 --- /dev/null +++ b/src/tutorial/src/step-6/description.md @@ -0,0 +1,36 @@ +# Event Modifiers + +Let's start our game as soon as user submits the form with pressing Enter on the input field. To make this more semantic, let's wrap our input in `
` tag: + +```html + + +
+``` + +Form with the single input will be submitted on Enter press automatically. We only need to listen to the form's `submit` event: + +```html +
+ +
+``` + +However, if we leave it like this, page will refresh and no text will be shown. The reason is we need to _prevent a default form submit event_ and make our change instead. In JavaScript, it's done with `event.preventDefault()` method; in Vue.js we have an event modifier `.prevent` that does the same under the hood. + +```html +
+ +
+``` + +Now, whenever user enter a number in the input field and presses Enter, we can see that game is started. diff --git a/src/tutorial/src/step-7/App/composition.js b/src/tutorial/src/step-7/App/composition.js new file mode 100644 index 0000000000..1ac71c4024 --- /dev/null +++ b/src/tutorial/src/step-7/App/composition.js @@ -0,0 +1,11 @@ +import { ref } from 'vue' + +export default { + name: 'App', + setup() { + const colorsNumber = ref(3) + const gameStarted = ref(false) + + return { colorsNumber, gameStarted } + } +} diff --git a/src/tutorial/src/step-7/App/options.js b/src/tutorial/src/step-7/App/options.js new file mode 100644 index 0000000000..511a8196bc --- /dev/null +++ b/src/tutorial/src/step-7/App/options.js @@ -0,0 +1,9 @@ +export default { + name: 'App', + data() { + return { + colorsNumber: 3, + gameStarted: false + } + } +} diff --git a/src/tutorial/src/step-7/App/style.css b/src/tutorial/src/step-7/App/style.css new file mode 100644 index 0000000000..4280ff054c --- /dev/null +++ b/src/tutorial/src/step-7/App/style.css @@ -0,0 +1,56 @@ +* { + margin: 0; + padding: 0; +} + +#app { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-align: center; + color: #2c3e50; +} + +label { + font-size: 18px; +} + +input { + font-size: 18px; + padding-left: 5px; + width: 35px; +} + +.panel { + color: white; + background-color: teal; + transition: background 0.5s; +} + +nav { + display: flex; + height: 30px; + justify-content: space-between; + align-items: center; + padding: 0 20px; + background-color: white; + color: teal; + font-size: 16px; + text-transform: uppercase; +} + +nav button { + text-transform: uppercase; + padding: 0 8px; + height: 100%; + font-size: 16px; + background-color: white; + border: none; + cursor: pointer; + color: teal; +} + +nav button:hover { + background-color: teal; + color: white; +} diff --git a/src/tutorial/src/step-7/App/template.html b/src/tutorial/src/step-7/App/template.html new file mode 100644 index 0000000000..f07aaa99a8 --- /dev/null +++ b/src/tutorial/src/step-7/App/template.html @@ -0,0 +1,13 @@ +
+
+

Guess the Color

+

Number of colors: {{ colorsNumber }}

+
+ +
+
+
Game is started
+
diff --git a/src/tutorial/src/step-7/description.md b/src/tutorial/src/step-7/description.md new file mode 100644 index 0000000000..12d45808e4 --- /dev/null +++ b/src/tutorial/src/step-7/description.md @@ -0,0 +1,37 @@ +# More on Conditional Rendering + +The last thing we want to implement in this lesson is hiding the input field when the game is already started and showing a button `Change colors number`. Clicking on the button will set the game to "not-started" and show the input again. First, let's add the button to our template: + +```html{1-3} + +
+ +
+``` + +Now, let's display the `