Skip to content

Move conditional rendering and list rendering #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/.vuepress/components/conditional-1.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<div id="no-key-example" class="demo">
<div>
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" />
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" />
</template>
</div>
<button @click="toggleLoginType">Toggle login type</button>
</div>
</template>

<script>
export default {
data() {
return {
loginType: 'username'
}
},
methods: {
toggleLoginType() {
this.loginType = this.loginType === 'username' ? 'email' : 'username'
}
}
}
</script>

<style lang="scss" scoped></style>
32 changes: 32 additions & 0 deletions src/.vuepress/components/conditional-2.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<div id="no-key-example" class="demo">
<div>
<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>
</div>
<button @click="toggleLoginType">Toggle login type</button>
</div>
</template>

<script>
export default {
data() {
return {
loginType: 'username'
}
},
methods: {
toggleLoginType() {
this.loginType = this.loginType === 'username' ? 'email' : 'username'
}
}
}
</script>

<style lang="scss" scoped></style>
17 changes: 17 additions & 0 deletions src/.vuepress/components/list-1.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<ul id="example-1" class="demo">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
</template>

<script>
export default {
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}
</script>
18 changes: 18 additions & 0 deletions src/.vuepress/components/list-2.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<ul id="example-2" class="demo">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
</template>

<script>
export default {
data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
}
</script>
21 changes: 21 additions & 0 deletions src/.vuepress/components/list-3.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<ul id="v-for-object" class="demo">
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
</template>

<script>
export default {
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}
</script>
21 changes: 21 additions & 0 deletions src/.vuepress/components/list-4.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<ul id="v-for-object" class="demo">
<li v-for="(value, name) in myObject">{{ name }}: {{ value }}</li>
</ul>
</template>

<script>
export default {
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}
</script>

<style lang="scss" scoped></style>
23 changes: 23 additions & 0 deletions src/.vuepress/components/list-5.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<ul id="v-for-object" class="demo">
<li v-for="(value, name, index) in myObject">
{{ index }}. {{ name }}: {{ value }}
</li>
</ul>
</template>

<script>
export default {
data() {
return {
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
}
}
</script>

<style lang="scss" scoped></style>
5 changes: 5 additions & 0 deletions src/.vuepress/components/list-6.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div id="range" class="demo">
<span v-for="n in 10">{{ n }} </span>
</div>
</template>
53 changes: 53 additions & 0 deletions src/.vuepress/components/list-7.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<div id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder="E.g. Feed the cat"
/>
<button>Add</button>
</form>
<ul>
<li v-for="(todo, index) in todos" :key="todo.id">
{{ todo.title }}
<button v-on:click="todos.splice(index, 1)">Remove</button>
</li>
</ul>
</div>
</template>

<script>
export default {
data() {
return {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes'
},
{
id: 2,
title: 'Take out the trash'
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
}
},
methods: {
addNewTodo() {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
}
</script>
4 changes: 2 additions & 2 deletions src/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ module.exports = {
'template-syntax',
// 'computed',
// 'class-and-style',
// 'conditional',
// 'list'
'conditional',
'list'
// 'events'
]
}
Expand Down
138 changes: 138 additions & 0 deletions src/guide/conditional.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Conditional Rendering

<div class="vueschool"><a href="https://vueschool.io/lessons/vuejs-conditionals?friend=vuejs" target="_blank" rel="sponsored noopener" title="Learn how conditional rendering works with Vue School">Learn how conditional rendering works with a free lesson on Vue School</a></div>

## `v-if`

The directive `v-if` is used to conditionally render a block. The block will only be rendered if the directive's expression returns a truthy value.

```html
<h1 v-if="awesome">Vue is awesome!</h1>
```

It is also possible to add an "else block" with `v-else`:

```html
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
```

### Conditional Groups with `v-if` on `<template>`

Because `v-if` is a directive, it has to be attached to a single element. But what if we want to toggle more than one element? In this case we can use `v-if` on a `<template>` element, which serves as an invisible wrapper. The final rendered result will not include the `<template>` element.

```html
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
```

### `v-else`

You can use the `v-else` directive to indicate an "else block" for `v-if`:

```html
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
```

A `v-else` element must immediately follow a `v-if` or a `v-else-if` element - otherwise it will not be recognized.

### `v-else-if`

The `v-else-if`, as the name suggests, serves as an "else if block" for `v-if`. It can also be chained multiple times:

```html
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
```

Similar to `v-else`, a `v-else-if` element must immediately follow a `v-if` or a `v-else-if` element.

### Controlling Reusable Elements with `key`

Vue tries to render elements as efficiently as possible, often re-using them instead of rendering from scratch. Beyond helping make Vue very fast, this can have some useful advantages. For example, if you allow users to toggle between multiple login types:

```html
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" />
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" />
</template>
```

Then switching the `loginType` in the code above will not erase what the user has already entered. Since both templates use the same elements, the `<input>` is not replaced - just its `placeholder`.

Check it out for yourself by entering some text in the input, then pressing the toggle button:

<conditional-1 />

This isn't always desirable though, so Vue offers a way for you to say, "These two elements are completely separate - don't re-use them." Add a `key` attribute with unique values:

```html
<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>
```

Now those inputs will be rendered from scratch each time you toggle. See for yourself:

<conditional-2 />

Note that the `<label>` elements are still efficiently re-used, because they don't have `key` attributes.

## `v-show`

Another option for conditionally displaying an element is the `v-show` directive. The usage is largely the same:

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

The difference is that an element with `v-show` will always be rendered and remain in the DOM; `v-show` only toggles the `display` CSS property of the element.

::: tip
Note that `v-show` doesn't support the ::: v-pre `<template>` ::: element, nor does it work with `v-else`.</p>
:::

## `v-if` vs `v-show`

`v-if` is "real" conditional rendering because it ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles.

`v-if` is also **lazy**: if the condition is false on initial render, it will not do anything - the conditional block won't be rendered until the condition becomes true for the first time.

In comparison, `v-show` is much simpler - the element is always rendered regardless of initial condition, with CSS-based toggling.

Generally speaking, `v-if` has higher toggle costs while `v-show` has higher initial render costs. So prefer `v-show` if you need to toggle something very often, and prefer `v-if` if the condition is unlikely to change at runtime.

## `v-if` with `v-for`

::: tip
Using `v-if` and `v-for` together is **not recommended**. See the [style guide](TODO:/v2/style-guide/#Avoid-v-if-with-v-for-essential) for further information.
:::

When used together with `v-if`, `v-for` has a higher priority than `v-if`. See the [list rendering guide](list#v-for-with-v-if) for details.
Loading