Vue.js Guide Notebook - Essential




BB

HI EVERYONE!
In order to avoid ambiguity, I try my best to write this article in English. ( Nevertheless, I’m poor in English QAQ
This article is concerning the essential part of Vue.js, and most of the content is from official guide(documentation). Of course, I may modify the samples in some part.
Additionally, the note of this series may NOT be updated, because I just want to use some nice UI library based on Vue.js.

Introduction

Text Interpolation

<body>
    <div id="app">
        
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!'
            }
        })
    </script>
</body>


Bind Element Attributes

e.g. Keep this element’s title attribute up-to-date with the message property on the Vue instance.

<body>
    <div id="app">
        <span v-bind:title="message">
            Hover it!
        </span>
    </div>
    <script type="text/html">
        var app = new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!'
            }
        })
    </script>
</body>


Conditionals

<body>
    <div id="app">
        <span v-if="ok">
            Surprise!
        </span>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                ok: true
            }
        })
    </script>
</body>


Loops

<body>
    <div id="app">
        <p v-for="ele in todos">
            
        </p>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                todos: [
                    { text: 'A' },
                    { text: 'B' },
                    { text: 'C' }
                ]
            }
        })
    </script>
</body>


Event Listeners

v-on: add an event listener

<body>
    <div id="app">
        <p>  </p>
        <button v-on:click="funReverse"> Click Here! </button>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                message: 'This is a message!'
            },
            methods: {
                funReverse: function() {
                    this.message = this.message.split('').reverse().join('')
                }
            }
        })
    </script>
</body>


Two-way Binding

v-model: two-way bindings

<body>
    <div id="app">
        <p>  </p>
        <input v-model="message">
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                message: 'This is a message!'
            }
        })
    </script>
</body>


Component

<body>
    <div id="app">
        <ol>
            <template-todo
                v-for="item in ls"
                v-bind:todo="item"
                v-bind:key="item.id"
            ></template-todo>
        </ol>
    </div>
    <script type="text/javascript">
        Vue.component('template-todo', {
            props: ['todo'],
            template: '<li></li>'
        })

        var app = new Vue({
            el: '#app',
            data: {
                ls: [
                    { id: 0, text: 'A' },
                    { id: 1, text: 'B' },
                    { id: 2, text: 'C' }
                ]
            }
        })
    </script>
</body>


Template Syntax

Once-time Text Interpolation

v-once: perform one-time interpolations

<body>
    <div id="app">
        <p v-once></p>
    </div>
    <script type="text/javascript">

        var app = new Vue({
            el: '#app',
            data: {
                msg: 'Hello Vue!'
            }
        })
    </script>
</body>


Raw HTML

<body>
    <div id="app">
        <p></p>
        <p><span v-html="rawhtml"></span></p>
    </div>
    <script type="text/javascript">

        var app = new Vue({
            el: '#app',
            data: {
                rawhtml: "<span style='color:red'>RED</span>"
            }
        })
    </script>
</body>


HTML Attributes

v-bind: binding html attributes

<body>
    <div id="app">
        <button v-bind:disabled="ok">Button</button>
    </div>
    <script type="text/javascript">

        var app = new Vue({
            el: '#app',
            data: {
                ok: true
            }
        })
    </script>
</body>


Directives

Directives: Special attributes with the v- prefix. e.g. v-if
Argument: Some directives can take an “argument”, denoted by a colon after the directive name. e.g. v-bind:title="msg"
Dynamic Arguments: New in 2.6.0+! e.g. <a v-on:[eventName]="doSomething"> ... </a>, in which eventName is dynamic.
Modifiers: Special postfixes denoted by a dot, which indicate that a directive should be bound in some special way. e.g. <form v-on:submit.prevent="onSubmit"> ... </form>

Shorthands

<!-- full syntax -->
<a v-on:click="doSomething"> ... </a>

<!-- shorthand -->
<a @click="doSomething"> ... </a>


<!-- full syntax -->
<a v-bind:href="url"> ... </a>

<!-- shorthand -->
<a :href="url"> ... </a>


Computed Properties and Watchers

Computed Properties

Computed properties are cached based on their dependencies.

<body>
    <div id="app">
        <p>Orgin: </p>
        <p>Reversed: </p>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                msg: "Hello World!"
            },
			// Computed Properties (getter)
            computed: {
                revMsg: function () {
                    return this.msg.split('').reverse().join('')
                }
            }
        })
    </script>
</body>


<body>
    <div id="app">
        <p>Name: </p>
        <p>FirstName: </p>
        <p>LastName: </p>
        <button @click="tfun">Click here to Change Full Name</button>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                firstName: "first",
                lastName: "last"
            },
            computed: {
                fullName: {
					// getter
                    get: function () {
                        return this.firstName + ' ' + this.lastName
                    },
					// setter
                    set: function (nv) {
                        var names = nv.split(' ')
                        this.firstName = names[0]
                        this.lastName = names[names.length - 1]
                    }
                }
            },
            methods: {
                tfun: function () {
                    this.fullName = "Hello World!"
                }
            }
        })
    </script>
</body>


Watchers

<body>
    <div id="app">
        <p>Please input: <input type="text" v-model="question"></p>
        <p></p>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                question: "",
                response: "Waiting"
            },
            watch: {
                question: function (nq, oq) {
                    this.response = "Typing..."
                }
            },
        })
    </script>
</body>


Binding HTML Classes

v-bind:class: dynamically toggle class
e.g. if isActive is true, the class will be shown

<body>
    <div id="app" class="static" :class="{ active: isActive }">
        <button @click="toggleActive"> Click! </button>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                isActive: true
            },
            methods: {
                toggleActive: function () {
                    if(this.isActive === true) {
                        this.isActive = false
                    } else {
                        this.isActive = true
                    }
                }
            }

        })
    </script>
</body>


Bind to a computed property that returns a object

<body>
    <div id="app" class="static" :class="classObject">
        <button @click="toggleActive"> Click! </button>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                isActive: true
            },
            computed: {
                classObject: function () {
                    return {
                        isActive: this.isActive
                    }
                }
            },
            methods: {
                toggleActive: function () {
                    if(this.isActive === true) {
                        this.isActive = false
                    } else {
                        this.isActive = true
                    }
                }
            }
        })
    </script>
</body>


Pass an array to v-bind:class to apply a list of classes

<body>
    <div id="app" :class="[activeClass, errorClass]"></div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                activeClass: 'active',
                errorClass: 'text-danger'
            }
        })
    </script>
</body>


<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
<div v-bind:class="[{ active: isActive }, errorClass]"></div>


Binding Inline Styles

v-bind:style: bind to css

<body>
    <div id="app" v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">
        Here is the text!
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                activeColor: "red",
                fontSize: 30
            }
        })
    </script>
</body>


<div v-bind:style="[baseStyles, overridingStyles]"></div>


Conditional Rendering

v-if, v-else, v-else-if

<body>
    <div id="app">
        <div v-if="Math.random() > 0.5">
            Now you see me
        </div>
        <div v-else>
            Now you dont
        </div>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
            }
        })
    </script>
</body>


<body>
    <div id="app">
        <div v-if="Math.random() < 0.3">
            Number is in 0 - 0.3
        </div>
        <div v-else-if="Math.random() < 0.6">
            Number is in 0.3 - 0.6
        </div>
        <div v-else>
            Other
        </div>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
            }
        })
    </script>
</body>


template on v-if

<body>
    <div id="app">
        <template v-if="ok">
            <h1>Title</h1>
            <p>Paragraph 1</p>
            <p>Paragraph 2</p>
        </template>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                ok: true
            }
        })
    </script>
</body>


Controlling Reusable Elements with [key]

Add a key attribute to make elements separate

<body>
    <div id="app">
        <template v-if="loginType === 'username'">
            <label>Username</label>
            <input placeholder="Enter your username" key="username-input">
        </template>
        <template v-else>
            <label>Email</label>
            <input placeholder="Enter your email address" key="email-input">
        </template>
        <br>
        <button @click="toggleLoginType"> Submit </button>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                loginType: 'username'
            },
            methods: {
                toggleLoginType: function () {
                    if(this.loginType === 'username') {
                        this.loginType = 'email'
                    } else {
                        this.loginType = 'username'
                    }
                }
            }
        })
    </script>
</body>


v-show

v-show will always be rendered and remain in DOM.

<h1 v-show="ok">Hello!</h1>


List Rendering

Mapping an array to list with v-for

<body>
    <div id="app">
        <ol>
            <li v-for="ele in arr">
                
            </li>
        </ol>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                arr: [
                    { msg: 'Hello' },
                    { msg: 'World' }
                ]
            },
        })
    </script>
</body>


An optional second argument is for the index of item

<body>
    <div id="app">
        <ul>
            <li v-for="(ele, idx) in arr">
                 ranks .
            </li>
        </ul>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                arr: [
                    { msg: 'Hello' },
                    { msg: 'World' }
                ]
            },
        })
    </script>
</body>


An object with v-for

<body>
    <div id="app">
        <ul>
            <li v-for="ele in obj">
                
            </li>
        </ul>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                obj: {
                    firstName: 'houz',
                    lastName: 'aj',
                    score: 0,
                    ranking: 999
                }
            },
        })
    </script>
</body>


An optional second argument is for the key of item

<body>
    <div id="app">
        <ul>
            <li v-for="(ele, key) in obj">
                : 
            </li>
        </ul>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                obj: {
                    firstName: 'houz',
                    lastName: 'aj',
                    score: 0,
                    ranking: 999
                }
            },
        })
    </script>
</body>


About array

Because of limitations in javascript, Vue cannot detect the following changes to an array:

vm.items[indexOfItem] = newValue
vm.items.length = newLength

Therefore, use the following code to replace them

Vue.set(vm.items, indexOfItem, newValue) //vm.$set <==> Vue.set
vm.items.splice(indexOfItem, 1, newValue)
vm.items.splice(newLength)


Object Change Detection

Vue cannot detect property addition or deletion. the method Vue.set(object, key, value) can be used to make Vue detect it.

var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})

Vue.set(vm.userProfile, 'age', 27)

the method Vue.assign() can assign a number of new properties to an existing object

vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})


Displaying Filtered/Sorted Results

<body>
    <div id="app">
        <ul>
            <li v-for="n in evenNumbers">
                
            </li>
        </ul>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                numbers: [1, 2, 3, 4, 5, 7, 8, 888]
            },
            computed: {
                evenNumbers: function () {
                    return this.numbers.filter(function (number) {
                        return (number & 1) === 0
                    })
                }
            }
        })
    </script>
</body>


<body>
    <div id="app">
        <ul>
            <li v-for="n in even(numbers)">
                
            </li>
        </ul>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                numbers: [1, 2, 3, 4, 5, 7, 8, 888]
            },
            methods: {
                even: function (numbers) {
                    return this.numbers.filter(function (number) {
                        return (number & 1) === 0
                    })
                }
            }
        })
    </script>
</body>


v-for in range

<body>
    <div id="app">
        <ul>
            <li v-for="n in 10">
                
            </li>
        </ul>
    </div>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
            }
        })
    </script>
</body>


v-for on a <template>

<ul>
  <template v-for="item in items">
    <li></li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>


v-for with a Component

In 2.2.0+, when using v-for with a component, a key is now required.

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>


Event Handling

Listening to Events

<body>
    <div id="app">
        <button v-on:click="counter += 1">Add 1</button>
        <p>The button above has been clicked  times.</p>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                counter: 0
            }
        })
    </script>
</body>


Method Event Handlers

<body>
    <div id="app">
        <button @click="greet">Click</button>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
            },
            methods: {
                greet: function () {
                    alert("Hello World!")
                }
            }
        })
    </script>
</body>


<body>
    <div id="app">
        <button @click="greet('HHHH')">Click</button>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
            },
            methods: {
                greet: function (msg) {
                    alert("Hello " + msg + "!")
                }
            }
        })
    </script>
</body>


Access the original DOM event

$event: pass it into a method using the special $event variable in an inline statement

<body>
    <div id="app">
        <button v-on:click="warn('Form cannot be submitted yet.', $event)">
            Submit
        </button>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
            },
            methods: {
                warn: function (message, event) {
                    // now we have access to the native event
                    if (event) event.preventDefault()
                    alert(message)
                }
            }
        })
    </script>
</body>


Event Modifiers

Vue provides event modifiers for v-on. Recall that modifiers are directive postfixes denoted by a dot.

<!-- the click events propagation will be stopped -->
<a v-on:click.stop="doThis"></a>

<!-- the submit event will no longer reload the page -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- modifiers can be chained -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- just the modifier -->
<form v-on:submit.prevent></form>

<!-- use capture mode when adding the event listener -->
<!-- i.e. an event targeting an inner element is handled here before being handled by that element -->
<div v-on:click.capture="doThis">...</div>

<!-- only trigger handler if event.target is the element itself -->
<!-- i.e. not from a child element -->
<div v-on:click.self="doThat">...</div>

<!-- New in 2.1.4+ -->
<!-- the click event will be triggered at most once -->
<a v-on:click.once="doThis"></a>

<!-- New in 2.3.0+ -->
<!-- the scroll event's default behavior (scrolling) will happen -->
<!-- immediately, instead of waiting for `onScroll` to complete  -->
<!-- in case it contains `event.preventDefault()`                -->
<div v-on:scroll.passive="onScroll">...</div>


Key Modifiers

Vue allows adding key modifiers for v-on when listening for key events:
Vue provides aliases for the most commonly used key codes when necessary for legacy browser support:

<body>
    <div id="app">
        <!-- only call `vm.submit()` when the `key` is `Enter` -->
        <input v-on:keyup.enter="submit">
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            methods: {
                submit: function () {
                    alert('success!')
                }
            },

        })
    </script>
</body>


<body>
    <div id="app">
        <textarea cols="30" rows="10" v-on:keyup.67.ctrl="perCopy">

        </textarea>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            methods: {
                perCopy: function () {
                    alert('Don\'t Copy!')
                }
            },

        })
    </script>
</body>


Mouse Button Modifiers

(New in 2.2.0+)


Form Input Bindings

Basic Usage

v-model: binding to input, textarea, checkbox, ratio, select, etc

e.g. Bind to an array

<body>
    <div id="app">
        <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
        <label>Jack</label>
        <input type="checkbox" id="john" value="John" v-model="checkedNames">
        <label>John</label>
        <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
        <label>Mike</label>
        <br>
        <span>Checked names: </span>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                checkedNames: []
            }
        })
    </script>
</body>


<body>
    <div id="app">
        <select v-model="selected" multiple>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
        <br>
        <span>Selected: </span>
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                selected: []
            }
        })
    </script>
</body>


Value Bindings

<!-- `picked` is a string "a" when checked -->
<input type="radio" v-model="picked" value="a">

<!-- `toggle` is either true or false -->
<input type="checkbox" v-model="toggle">

<!-- `selected` is a string "abc" when the first option is selected -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>

<!-- When toggle is true, the value is 'yes'. Otherwise, it is 'no' -->
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no">


Modifiers

.lazy: add the lazy modifier to instead sync after change events

<body>
    <div id="app">
        <input v-model.lazy="msg" @change="show">
    </div>

    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                msg: ''
            },
            methods: {
                show: function () {
                    alert(this.msg);
                }
            }
        })
    </script>
</body>


.number: automatically typecast as a number

<input v-model.number="age" type="number">


.trim: make user input be trimmed automatically

<input v-model.trim="msg">


Components Basics

data must be a function

In order to make component independent, data must be a function

data: function () {
  return {
    count: 0
  }
}


Passing Data to Child Components with Props

<body>
    <div id="app">
        <sample title="HELLO WORLD!"></sample>
    </div>

    <script type="text/javascript">
        Vue.component('sample', {
            props: ['title'],
            template: `<button></button>`
        });

        var app = new Vue({
            el: '#app',
            data: {
                msg: ''
            },
            methods: {
                show: function () {
                    alert(this.msg);
                }
            }
        })
    </script>
</body>


A Single Root Element

Every component must have a single root element

Passing Data to Parent Component with $emit

<body>
    <div id="app">
        <div :style="{ fontSize: postFontSize + 'em' }">
            <blog-post
                    v-for="post in posts"
                    v-bind:key="post.id"
                    v-bind:post="post"
                    v-on:enlarge-text="postFontSize += $event"
            ></blog-post>
        </div>
    </div>

    <script type="text/javascript">
        Vue.component('blog-post', {
            props: ['post'],
            template: `
                <div class="blog-post">
                  <h3></h3>
                  <button v-on:click="$emit('enlarge-text', 0.1)">
                      Enlarge text
                  </button>
                  <div v-html="post.content"></div>
                </div>`
        });

        var app = new Vue({
            el: '#app',
            data: {
                postFontSize: 1,
                posts: [
                    {
                        title: 'Hello World',
                        id: 0,
                        content: 'NOTHING'
                    }
                ]
            }
        })
    </script>
</body>


Dynamic Components

<!-- Component changes when currentTabComponent changes -->
<component v-bind:is="currentTabComponent"></component>