Vuejs渲染列表

Published on 2016 - 06 - 14

we are going to learn about list rendering. Using Vue’s directives we are going to demonstrate how to:

  1. Render a list of items based on an array. 2. Repeat a template.
  2. Iterate through the properties of an object. 4. Filter an array of items.
  3. Order an array of items.
  4. Apply a custom filter to a list.

Install & Use Bootstrap

To make our work easier on the eye, we are going to import Bootstrap.

Head to bootstrap and click the download button. For our example we need only one file, for now: css/bootstrap.min.css. When we use this .css file in our app, we have access to all the pretty structures and styles. Just include it within the head tag of your page and you are good to go.

Bootstrap requires a containing element to wrap site contents and house our grid system. You may choose one of two containers to use in your projects. Note that, due to padding and more, neither container is nestable.

  • Use .container for a responsive fixed width container.
    ...
  • Use.container-fluid for a full width container,spanning the entire width of your viewport.
    ...

At this point, we would like to make an example of Vue.js with Bootstrap classes. This is the introductory example concerning classes and many will follow. Of course, not much study or experimentation is required in order make use of combined Vue and Bootstrap.

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.cs\ s" rel="stylesheet">
    <title>Hello Bootstrap</title> 
</head>
<body>
<div class="container">
    <h1>Hello Bootstrap, sit next to Vue.</h1> 
    <pre>
        {{$data | json}} 
    </pre>
</div> 
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.js"></script> <script type="text/javascript">
    new Vue({
        el: '.container',
        data: { 

        }
    }) 
</script>
</html>

Shown here is the installed Bootstrap and the basic set up for our stories example.

Notice this time, instead of targeting app id, we have targeted the container class within the el option inside the Vue instance. Going that way, we have gained the styles and structure that comes along with this class and made our app a bit more delightful.

v-for

In order to loop through each item in an array, we will use v-for Vue’s directive.

The v-for loop works on arrays/objects and is used to loop through each item in an array. This directive requires a special syntax in the form of item in array where array is the source data Array and item is an alias for the Array element being iterated on.

Range v-for

Directive v-for can also take an integer. Whenever a number is passed instead of an array/object, the template will be repeated as many times as the number given.

<html> 
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.mi\ n.css" rel="stylesheet">
    <title>Hello Vue</title> 
</head>
<body>
<div class="container">
    <h1>The multiplication table of 4.</h1> 
    <ul class="list-group">
        <li v-for="i in 11" class="list-group-item"> 
            {{ i }} times 4 equals {{ i * 4 }}.
        </li> 
    </ul>
</div> 
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.js"></script> <script type="text/javascript">
    new Vue({
        el: '.container'
    })
</script>
</html>

The above code displays the multiplication table of 4.

Array Rendering

Loop Through an Array

In the next example we will set up the following array of Stories inside our data object and we will display them all, one by one.

stories: [
    "I crashed my car today!",
    "Yesterday, someone stole my bag!",
    "Someone ate my chocolate...",
]

What we need to do here, is to render a list. Specifically, an array of strings.

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.cs\ s" rel="stylesheet">
    <title>Stories</title> 
</head>
<body>
    <div class="container">
        <h1>Let's hear some stories!</h1> 
        <div>
            <ul class="list-group">
                <li v-for="story in stories" class="list-group-item">
                Someone said "{{ story }}" </li>
            </ul> 
        </div>
        <pre>
            {{$data | json}}
        </pre> 
    </div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.js"></script> <script type="text/javascript">
    new Vue({
        el: '.container',
        data: {
            stories: [
                "I crashed my car today!",
                "Yesterday, someone stole my bag!",
                "Someone ate my chocolate...",
            ] 
        }
    })
</script>
</html>

This is the output of the above code. Using v-for we have managed to display our stories in a simple unordered list. It is really that easy!

Loop Through an Array of Objects

Now, we change the Stories array to contain story objects. A story object has 2 properties: plot and writer. We will do the same thing we did before but this time instead of echoing story immediately, we will echo story.plot and story.writer respectively.

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.cs\ s" rel="stylesheet">
    <title>Stories</title> 
</head>
<body>
    <div class="container">
        <h1>Let's hear some stories!</h1> 
        <div>
            <ul class="list-group">
                <li v-for="story in stories" class="list-group-item">
                    {{ story.writer }} said "{{ story.plot }}" 
                </li>
            </ul> 
        </div>
        <pre>
            {{$data | json}}
        </pre> 
    </div>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.js"></script> <script type="text/javascript">
new Vue({
    el: '.container',
    data: {
        stories: [ 
        {
                plot: "I crashed my car today!",
                writer: "Alex"
            },
            {
                plot: "Yesterday, someone stole my bag!",
                writer: "John"
            }, 
            {
                writer: "John"
            },
            {
                plot: "I ate someone's chocolate!",
                writer: "Alex"
            }, 
        ]
    }
})
</script> 
</html>

Additionally, when you need to display the index of the current item, you can use $index special variable. Following is an example to show how it works.

<ul class="list-group">
    <li v-for="story in stories" class="list-group-item">
        {{$index}}. {{ story.writer }} said "{{ story.plot }}" 
    </li>
</ul>

The $index inside the curly braces, clearly represents the index of the iterated item in the given example.

Another way to access the index of the iterated item, is to specify an alias for the index of the array as shown below.

<ul class="list-group">
    <li v-for="(index, story) in stories" class="list-group-item">
        {{index}} {{ story.writer }} said "{{ story.plot }}" 
    </li>
</ul>

The output of the last code is exactly the same with the previous one.

Object v-for

You can use v-for to iterate through the properties of an Object. We mentioned before that you can bring to display the index of the array, but you can also do the same when iterating an object. In addition to $index, each scope will have access to another special property, the $key.

We have restructured our data to be a single object with 3 attributes this time: plot, writer and upvotes. As you can see in the example code above, we use $key and $index to bring inside the list the key-value pairs, as well as the $index of each pair.

<div class="container">
    <h1>Let's hear some stories!</h1> 
    <ul class="list-group">
        <li v-for="value in story" class="list-group-item"> 
            {{$index}} : {{$key}} : {{ value }}
        </li> 
    </ul>
</div>

new Vue({
    el: '.container', 
    data: {
        story: {
            plot: "Someone ate my chocolate...",
            writer: 'John',
            upvotes: 47
        }
    }
 })

Alternatively, you can also specify an alias for the key.

<div class="container">
    <h1>Let's hear some stories!</h1> 
    <ul class="list-group">
        <li v-for="(key, value) in story" class="list-group-item">
            {{$index}} : {{key}} : {{ value }} 
        </li>
    </ul>
</div>

Either way the result will be:

Filtered Results

Sometimes we need to display a filtered version of an array without actually mutating or resetting the original data. In our example we want to display a list with the stories written by Alex and one list with the stories written by John. We can achieve this using the built-in filter, filterBy.

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.cs\ s" rel="stylesheet">
    <title>User Stories</title> 
</head>
<body>
    <div class="container">
        <h1>Let's hear some stories!</h1> 
        <div>
            <h3>Alex's stories</h3> 
            <ul class="list-group">
                <li v-for="story in stories | filterBy 'Alex' in 'writer'" class="list-group-item">
                     {{ story.writer }} said "{{ story.plot }}"
                </li> 
            </ul>
            <h3>John's stories</h3> 
            <ul class="list-group">
                <li v-for="story in stories | filterBy 'John' in 'writer'" class="list-group-item">
                    {{ story.writer }} said "{{ story.plot }}"
                </li> 
            </ul>
        </div> 
        <pre>
            {{$data | json}} 
        </pre>
    </div> 
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.js"></script> <script type="text/javascript">
new Vue({
    el: '.container',
    data: {
        stories: [
            {
                plot: "I crashed my car today!",
                writer: "Alex"
            },
            {
                plot: "Yesterday, someone stole my bag!",
                writer: "John"
            },
            {
                plot: "Someone ate my chocolate...",
                writer: "John"
            },
            {
                plot: "I ate someone's chocolate!",
                writer: "Alex"
            },
        ]
    }
})
</script>
</html>

Simple enough, right? Next we will implement a very basic (but awesome) search. When the user types a part of a story, we can guess which story it is and who wrote it, in real time. We’ll add a text input binded to an empty variable query so we can dynamically filter our Stories array.

<div class="container">
    <h1>Lets hear some stories!</h1> 
    <div>
        <h3> Alex's stories </h3>
         <ul class="list-group">
            <li v-for="story in stories | filterBy 'Alex' in 'writer'" class="list-group-item">
                {{ story.writer }} said "{{ story.plot }}" 
            </li>
        </ul>
        <h3> John's stories </h3>
        <ul class="list-group">
            <li v-for="story in stories | filterBy 'John' in 'writer'" class="list-group-item">
                {{ story.writer }} said "{{ story.plot }}" 
            </li>
        </ul>
        <div class="form-group">
            <label for="query">
                What are you looking for?
            </label>
            <input v-model="query" class="form-control"> 
        </div>
        <h3>Search results:</h3> 
        <ul class="list-group">
            <li v-for="story in stories | filterBy query in 'plot'" class="list-group-item">
                        {{ story.writer }} said "{{ story.plot }}"
            </li> 
        </ul>
    </div> 
</div>

Ordered Results

Sometimes we may want to display the items of an Array ordered by some criteria. Luckily there is an orderBy built in filter to sort our list in no time! First we will enhance our Stories with a new property called upvotes. Then we’ll go on and display our array ordered by the count of each story’s upvotes. The more famous a story is, the higher it should appear.

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.cs\ s" rel="stylesheet">
    <title>Famous Stories</title> 
</head>
<body>
    <div class="container">
        <h1>Let's hear some stories!</h1> 
        <ul class="list-group">
            <li v-for="story in stories | orderBy 'upvotes'" class="list-group-item">
                            {{ story.writer }} said "{{ story.plot }}"
                            and upvoted {{ story.upvotes }} times.
            </li> 
        </ul>
        <pre>
            {{ $data | json }}
        </pre>
    </div> 
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.js"></script> <script type="text/javascript">
new Vue({
    el: '.container',
    data: {
        stories: [ 
            {
                        plot: "I crashed my car today!",
                        writer: "Alex",
                        upvotes: 28
             },
              {
                        plot: "Yesterday, someone stole my bag!",
                        writer: "John",
                        upvotes: 8
            },
            {
                plot: "Someone ate my chocolate...",
                writer: "John",
                upvotes: 51
            },
            {
                plot: "I ate someone's chocolate!",
                writer: "Alex",
                upvotes: 74
            },
        ]
    }
})
</script>
</html>

Hmmm, the array is ordered but this is not what we expected. We wanted the famous stories first. Luckily, again, orderBy filter accepts two arguments: the key to sort the array, and the order which specifies whether the result should be ordered in ascending (order >= 0) or descending (order < 0) order.

Eventually, for the sake of ordering the array in descending order, our code will look like this:

<ul class="list-group">
    <li v-for="story in stories | orderBy 'upvotes' -1"  class="list-group-item">
            {{ story.writer }} said "{{ story.plot }}"
            and upvoted {{ story.upvotes }} times. 
    </li>
</ul>

We can easily change the order we sort the array, by dynamically changing the order parameter. A button is added, which will toggle the value of a new variable between -1 and 1, and then the new variable is passed as order parameter to orderBy filter. Watch now.

new Vue({
    el: '.container',
    data: {
        order: -1,
        stories: [
            {
                plot: "I crashed my car today!",
                writer: "Alex",
                upvotes: 28
            },
            {
                plot: "Yesterday, someone stole my bag!",
                writer: "John",
                upvotes: 8
            },
            {
                plot: "Someone ate my chocolate...",
                writer: "John",
                upvotes: 51
            },
            {
                plot: "I ate someone's chocolate!",
                writer: "Alex",
                upvotes: 74
            },
        ]
    }
})

We initialize order variable with the value of -1 and then we pass it to orderBy filter.

<ul class="list-group">
    <li v-for="story in stories | orderBy 'upvotes' order" class="list-group-item">
            {{ story.writer }} said "{{ story.plot }}"
            and upvoted {{ story.upvotes }} times. 
    </li>
</ul>
<button @click="order = order * -1">Reverse Order</button>

Impressing huh? If you are not impressed by now, guess who is! ..“We are!”..

Custom Filter

This is the most cumbersome part. Assume we want to display only the famous stories (the ones with upvotes greater than 20). In order to achieve that we have to create a custom filter and apply it to filterBy. We are going to create a filter named famous which expects two parameters:

  • the array we want to filter
  • and the bound which defines the amount of upvotes a story must have in order to be considered as famous

The famous filter returns an array which contains only the objects that satisfy a condition.

If you can’t keep up with this example don’t worry, you will get it sooner or later, just keep reading..

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.cs\ s" rel="stylesheet">
    <title>Famous Stories</title> 
</head>
<body>
<div class="container">
    <h1>Let's hear some famous stories!</h1>
    <ul class="list-group">
        <li v-for="story in stories | famous" class="list-group-item">
                {{ story.writer }} said "{{ story.plot }}"
                and upvoted {{ story.upvotes }} times. 
            </li>
        </ul> 
        <pre>
        {{ $data | json }} 
        </pre>
    </div> 
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.js"></script> <script type="text/javascript">
Vue.filter('famous', function (stories) {
    return stories.filter(function(item){ 
        return item.upvotes > 20;
    });
})

new Vue({
    el: '.container',
    data: {
        stories: [
            {
                plot: "I crashed my car today!",
                writer: "Alex",
                upvotes: 28
            },
            {
                plot: "Yesterday, someone stole my bag!",
                writer: "John",
                upvotes: 8
            },
            {
                plot: "Someone ate my chocolate...",
                writer: "John",
                upvotes: 51
            },
            {
                plot: "I ate someone's chocolate!",
                writer: "Alex",
                upvotes: 74
            },
        ]
    }
})
</script>
</html>

Reference