Xử lý danh sách với v-for Phần 1

Xử lý mảng nội dung là công việc rất hay gặp trong các ứng dụng web, ví dụ như khi bạn xây dựng một bảng liệt kê các sản phẩm, hay danh sách các khách hàng… Vue.js thiết kế directive v-for cho những trường hợp như vậy, cú pháp v-for cũng khá quen thuộc vì nó cũng na ná với rất nhiều các ngôn ngữ khác. Trước khi giới thiệu các kiến thức liên quan đến v-for chúng ta cùng tìm hiểu cách xây dựng giao diện bằng framework CSS Bootstrap. Từ bài đầu tiên đến giờ, các ví dụ đều chưa được chú ý đến giao diện, nó làm cho cảm hứng viết code giảm đi nhiều. Bootstrap hẳn nhiều bạn đã biết, nó giúp cho việc xây dựng giao diện trở lên hết sức đơn giản và có thể tương thích nhiều loại thiết bị đặc biệt là điện thoại thông minh.

1. Cài đặt và sử dụng Bootstrap

Bootstrap là framework CSS rất nổi tiếng là phần mềm mã nguồn mở được phát triển bởi Twitter. Framework này xây dựng sẵn rất nhiều các thành phần và chúng ta chỉ việc sử dụng lại một cách phù hợp. Bootstrap dựa trên một hệ thống lưới với 12 cột (bạn có thể tùy chỉnh được). Có rất nhiều cách cài đặt Bootstrap giống như cài đặt môi trường cho Vue.js, trong khuôn khổ Khóa học Vue.js này chúng ta sẽ sử dụng CDN để giúp cho việc demo được thuận lợi. Bạn chỉ cần thêm liên kết này vào phần trong thẻ <head>.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">

Nếu không cần các hiệu ứng bạn có thể bỏ qua phần Javascript và thư viện jQuery yêu cầu của Bootstrap.

Khi sử dụng hệ thống lưới mặc định của Bootstrap, nó yêu cầu mọi nội dung phải được đưa vào trong một container.

<div class="container">
  <!-- Content here -->
</div>

Bootstrap rất đơn giản, bạn chỉ cần đọc qua tài liệu Bootstrap và chúng ta cùng áp dụng vào bài tập cuối ở bài Câu lệnh điều kiện v-if xem thế nào nhé.

<!DOCTYPE html>
<html>
<head>
    <title>Bài tập sử dụng v-if Vuejs sử dụng Bootstrap- Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
</head>
<body>
    <div id="app" class="container">
        <div class="alert alert-success" role="alert" v-if="user.email == 'test@allaravel.com' && user.password == '123456'">
            Chào mừng {{ user.email }} đã đăng nhập thành công!
        </div>
        <div class="alert alert-danger" role="alert" v-if="(user.email != 'test@allaravel.com' && user.email != null) || (user.password != '123456' && user.password != null)">
            Thông tin đăng nhập sai, vui lòng thử lại!
        </div>
        <form v-if="user.email != 'test@allaravel.com' || user.password != '123456'">
            <div class="form-group row">
                <label for="staticEmail" class="col-sm-2 col-form-label">Email</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" v-model="user.email">
                </div>
            </div>
            <div class="form-group row">
                <label for="inputPassword" class="col-sm-2 col-form-label">Password</label>
                <div class="col-sm-10">
                    <input type="password" class="form-control" v-model="user.password">
                </div>
            </div>
        </form>        
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                user: {}
            }
        })
    </script>
</body>
</html>

Kết quả như sau:

Bạn thấy đấy, chỉ thay đổi chút ít mà giao diện đã rất đẹp, các ví dụ sau này sẽ luôn áp dụng bootstrap, nếu có thời gian bạn nên tìm hiểu cách sử dụng framework hữu ích này nhé.

2. Xử lý danh sách Vuejs v-for

Vòng lặp v-for được dùng để xử lý mảng hoặc một danh sách các đối tượng, nó lặp qua từng phần tử trong mảng. V-for khá giống với cấu trúc foreach trong PHP, tuy nhiên phần cú pháp cụ thể có phần đối ngược, cú pháp trong PHP như sau:

foreach($array as $value) {

}

Với v-for trong Vuejs thì ngược lại

v-for="value in array"

Trong cú pháp chúng ta để là array nhưng nên hiểu đây là nguồn dữ liệu cho v-for và nó có thể có các dạng như sau:

  • Một số nguyên
  • Một mảng các giá trị
  • Một mảng các đối tượng
  • Một đối tượng

Ngoài giá trị value, chúng ta có thể muốn biết chỉ mục (index) của phần tử hiện tại chúng ta có thể sử dụng biến được Vue.js định nghĩa sẵn là index. Với trường hợp nguồn dữ liệu là đối tượng, chúng ta có thể dùng một biến khác là key chứa tên thuộc tính của đối tượng. Chúng ta sẽ đi vào cụ thể việc sử dụng các biến này trong các phần tiếp theo.

Chú ý, bạn có thể thay từ khóa “in” bằng từ khóa “of”, như vậy cú pháp sẽ gần với cú pháp lặp của Javascript.

2.1 Lặp một số nguyên lần

Trong cú pháp ở trên, array có thể là một số nguyên, khi đó v-for sẽ lặp số lần đúng bằng số nguyên đó. Cách này thường sử dụng khi bạn muốn xây dựng một phần tử hoặc một đoạn mã HTML lặp lại nhiều lần. Chúng ta cùng vào một ví dụ thực tế, xây dựng một bản cửu chương bằng v-for.

Sử dụng v-for lặp một số nguyên lần có cách dùng giống như vòng lặp for trong các ngôn ngữ khác, ví dụ ngôn ngữ PHP.

for(i = 1; i <= number; i++) {

}

2.2 Xử lý mảng giá trị

Mảng là một dạng dữ liệu rất phổ biến, mảng có thể chứa các giá trị hoặc các đối tượng. Trong phần này chúng ta cùng nhau tìm hiểu về cách thức lặp qua các phần tử của một mảng giá trị. Ví dụ chúng ta có một mảng chứa tiêu đề các bài viết và chúng ta cần in ra màn hình danh sách này.

<!DOCTYPE html>
<html>
<head>
    <title>Xử lý mảng giá trị với v-for Vuejs - Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div id="app" class="container">        
        <div class="row">
            <div class="col-md-12 text-center">
                <h1 class="text-success">Danh sách các bài viết</h1>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12" v-for="title in postTitles">
                <h4>{{ title }}</h4>
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                postTitles: [
                    'Giới thiệu framework Vue.js',
                    'Cài đặt môi trường Vue.js',
                    'Các công cụ sử dụng trong phát triển Vue.js'
                ]
            }
        })
    </script>
</body>
</html>

Kết quả như sau:

Danh sách này sẽ khó nhìn nếu không có chỉ mục ở đầu mỗi tiêu đề. Vue.js cũng đã thiết kế sẵn các cú pháp giúp lấy chỉ mục một cách dễ dàng với một biến được đặt tên là index.

<div class="col-md-12" v-for="(title, index) in postTitles">
    <h4>{{ index + 1}}. {{ title }}</h4>
</div>

Ok, như vậy danh sách tiêu đề được in ra màn hình đã khá đẹp rồi đấy.

2.3 Xử lý mảng đối tượng

Thao tác với mảng dữ liệu đôi khi không phải chỉ là mảng giá trị mà có thể là mảng các đối tượng. Khi duyệt qua mảng các đối tượng, muốn truy xuất đến giá trị thuộc tính của đối tượng chúng ta sử dụng cú pháp đối_tượng.thuộc_tính.

Ví dụ tiếp theo chúng ta sẽ in ra danh sách các sản phẩm đang bán, mỗi sản phẩm là một đối tượng gồm các thông tin:

  • Tên sản phẩm
  • Ảnh sản phẩm
  • Giá sản phẩm
  • Đường dẫn đến sản phẩm chi tiết
<!DOCTYPE html>
<html>
<head>
    <title>Xử lý mảng đối tượng với v-for Vuejs - Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div id="app" class="container">        
        <div class="row">
            <div class="col-md-12 text-center">
                <h1 class="text-success">Danh sách sản phẩm đèn LED chiếu sáng</h1>
            </div>
        </div>
        <div class="row">
            <div class="col-md-3" v-for="product in products">
                <a :href="product.url" target="_blank">
                    <img :src="product.image" class="img-thumbnail">
                </a>
                <h5 class="text-center text-info">{{ product.price }}</h5>
                <h5 class="text-center">{{ product.name }}</h5>
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                products: [
                    {name: 'Đèn led âm trần LIPER 8W series E', image: 'http://bigi.vn/public/images/products/liper/downlight/LP-DL08EW03-Y1.png', url: 'http://bigi.vn/san-pham/led-am-tran-sieu-mong-liper-8w-anh-sang-trang-lo-cat-%CF%8690-110mm-ma-lp-dl08ew03-y1', price: '161,000đ'},
                    {name: 'Đèn led âm trần LIPER 7W series F', image: 'http://bigi.vn/public/images/products/liper/downlight/LPDL-07A01-YX.png',url: 'http://bigi.vn/san-pham/led-am-tran-liper-7w-anh-sang-vang-lo-cat-%CF%8675-85mm-ma-lpdl-07a01-yx-w',price: '209,000đ'},
                    {name: 'Đèn led âm trần LIPER 10W series A', image: 'http://bigi.vn/public/images/products/liper/downlight/LPDL-10A01-YX.png',url: 'http://bigi.vn/san-pham/led-am-tran-liper-10w-anh-sang-trang-lo-cat-%CF%8695-105mm-ma-lpdl-10a01-yx-c',price: '257,000đ'},
                    {name: 'Đèn led ốp trần LIPER 12W', image: 'http://bigi.vn/public/images/products/liper/downlight/LPDL-12K01-YE-00.png',url: 'http://bigi.vn/san-pham/led-op-tran-liper-12w-anh-sang-trang-tron-%CF%86153x58mm-ma-lp-dl12k01-ye-c',price: '402,000đ'},
                    {name: 'Đèn led pha LIPER 10W', image: 'http://bigi.vn/public/images/products/liper/flood/LPFL-10A-00.png',url: 'http://bigi.vn/san-pham/led-pha-sieu-ben-dep-liper-10w-mau-den-anh-sang-trang-ma-lpfl-10x01-c',price: '232,000đ'},
                    {name: 'Đèn led pha LIPER công suất lớn 100W', image: 'http://bigi.vn/public/images/products/liper/flood/LPFL-100A-X2-00.png',url: 'http://bigi.vn/san-pham/led-pha-sieu-ben-dep-liper-100w-mau-trang-anh-sang-trang-ma-lpfl-100x21-c',price: '1,262,000đ'},
                    {name: 'Đèn led phượt LIPER 30W pin 8 tiếng', image: 'http://bigi.vn/public/image/product/p00943/den-led-pha-flood-light-lpfl-30k01-co-the-su-dung-sac-o-to-1000x1000.jpg',url: 'http://bigi.vn/san-pham/den-led-pha-liper-lpfl-30k01-30w',price: '1,262,000đ'},
                    {name: 'Đèn đường công nghệ LED 200W', image: 'http://bigi.vn/public/image/product/p00942/led-den-duong-liper-lpstl-200a01-200w-chieu-sang-cong-cong-chieu-sang-do-thi-1000x1000.jpg',url: 'http://bigi.vn/san-pham/led-den-duong-liper-lpstl-200a01-cong-suat-200w',price: 'Liên hệ'}
                ]
            }
        })
    </script>
</body>
</html>

Kết quả như sau:

2.4 Duyệt thuộc tính đối tượng bằng v-for

Bạn có thể sử dụng v-for để duyệt qua các thuộc tính của một đối tượng, khi đó nguồn dữ liệu của v-for là đối tượng. Ví dụ tiếp theo chúng ta sẽ in chi tiết thông tin một đối tượng ra màn hình.

<!DOCTYPE html>
<html>
<head>
    <title>Duyệt thuộc tính đối tượng với v-for Vuejs - Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div id="app" class="container">        
        <div class="row">
            <div class="col-md-12 text-center">
                <h1 class="text-success">Chi tiết thông tin người dùng</h1>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12" v-for="(value, key, index) in user">
                {{ index }}. {{ key }}: {{ value }}
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                user: {
                    name: 'Nguyễn Văn A',
                    email: 'nguyenvana@allaravel.com',
                    phone: '0904123456',
                    joinedDate: '15/03/2017',
                    location: 'Hà Nội'
                }
            }
        })
    </script>
</body>
</html>

Kết quả

2.5 Xử lý lặp có điều kiện với v-for

Trong lập trình, việc phối hợp giữa cấu trúc lặp và cấu trúc điều kiện rất hay diễn ra, thông thường chúng ta sử dụng hai block với block này nằm trọn trong block kia. Với Vue việc phối hợp theo kiểu thông thường sẽ dẫn đến dư thừa thẻ html. Bạn hãy xem ví dụ sau nhé:

<tr v-for="(user, index) in users">
    <div v-if="user.active">
        <th scope="row">{{ index }}</th>
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
        <td>{{ user.phone }}</td>
        <td>{{ user.location }}</td>
    </div>
</tr>

Đoạn mã này duyệt qua danh sách người dùng và hiển thị những người dùng đang hoạt động, đoạn mã hoạt động bình thường, tuy nhiên để ý bạn sẽ thấy bị thừa một thẻ div, do nếu không có thẻ div này không biết đưa v-if vào đâu? Vue.js cho phép có thể có hai cấu trúc v-for và v-if trong cùng một thẻ HTML và thứ tự ưu tiên là v-for được xử lý trước v-if.

Ví dụ tiếp theo đây sẽ lặp qua danh sách người dùng và hiển thị những người dùng đang hoạt động dưới dạng một bảng.

<!DOCTYPE html>
<html>
<head>
    <title>Xử lý lặp có điều kiện v-for Vuejs - Allaravel.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
    <div id="app" class="container">        
        <div class="row">
            <div class="col-md-12 text-center">
                <h1 class="text-success">Danh sách người dùng đang hoạt động</h1>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <table class="table">
                    <thead>
                        <tr>
                            <th scope="col">#</th>
                            <th scope="col">Họ tên</th>
                            <th scope="col">Email</th>
                            <th scope="col">Số điện thoại</th>
                            <th scope="col">Nơi ở</th>
                        </tr>
                    </thead>
                        <tbody>
                            <tr v-for="(user, index) in users" v-if="user.active">
                                <th scope="row">{{ index }}</th>
                                <td>{{ user.name }}</td>
                                <td>{{ user.email }}</td>
                                <td>{{ user.phone }}</td>
                                <td>{{ user.location }}</td>
                            </tr>
                        </tbody>
                </table>
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script type="text/javascript">
        var vue = new Vue({
            el: '#app',
            data: {
                users: [
                    {name: 'Nguyễn Văn Minh', email: 'minhnv@allaravel.com', phone: '0904123456', location: 'Hà Nội',active: 1},
                    {name: 'Trần Mộng Tú', email: 'tutm@allaravel.com', phone: '0904123456', location: 'Sài Gòn',active: 1},
                    {name: 'Lê Viết Xuân', email: 'xuanlv@allaravel.com', phone: '0904123456', location: 'Quảng Nam',active: 0},
                    {name: 'Nguyễn Đức Tuấn', email: 'tuannd@allaravel.com', phone: '0904123456', location: 'Quảng Ninh',active: 1},
                    {name: 'Đinh Mạnh Dũng', email: 'dungdm@allaravel.com', phone: '0904123456', location: 'Nam Định',active: 0},
                    {name: 'Trần Thanh Phương', email: 'phuongtt@allaravel.com', phone: '0904123456', location: 'Hà Nội',active: 0},
                    {name: 'Trần Văn Tùng', email: 'tungtv@allaravel.com', phone: '0904123456', location: 'HCM',active: 1}
                ]
            }
        })
    </script>
</body>
</html>

3. Bài tập

Như vậy chúng ta đã khám phá những kiến thức cơ bản về cú pháp v-for trong Vue.js, vì bài viết khá dài nên chúng ta chia thành 2 phần để giúp các bạn có thể theo dõi tốt hơn. Các bạn cũng có thể ôn luyện lại các kiến thức trên với một bài tập nho nhỏ tiếp theo:

Chúng ta có một mảng chứa các danh mục và các bài viết được đọc nhiều nhất trong danh mục đó như sau:

data: {
    mostViewedCategories: [
        {
            name: 'Kiến thức framework Laravel', 
            posts: [
                {title: 'Học Laravel 5 miễn phí', url: 'https://allaravel.com/laravel-tutorials/khoa-hoc-laravel-5-mien-phi/'},
                {title: 'Tìm kiếm thông minh với Typeahead trong ứng dụng Laravel', url: 'https://allaravel.com/laravel-tutorials/tim-kiem-thong-minh-voi-typeahead-trong-ung-dung-laravel/'},
                {title: 'Xác thực API bằng OAuth2 với Laravel Passport', url: 'https://allaravel.com/laravel-tutorials/xac-thuc-api-bang-oauth-2-voi-laravel-passport/'}
            ]
        },
        {
            name: 'Kiến thức framework Vue.js', 
            posts: [
                {title: 'Khóa học Vue.js miễn phí', url: 'https://allaravel.com/tutorials/vuejs-framework/khoa-hoc-vue-js-2-mien-phi/'},
                {title: 'Series Xây dựng diễn đàn dạng đơn trang với Vuejs', url: 'https://allaravel.com/laravel-tutorials/xay-dung-forum-dang-spa-voi-laravel-va-vue-js/'},
                {title: 'Vue.js là gì?', url: 'https://allaravel.com/tutorials/vuejs-framework/gioi-thieu-framework-vue-js/'}
            ]
        },
        {
            name: 'Design Pattern', 
            posts: [
                {title: 'Inversion of Control nguyên lý của các nguyên lý', url: 'https://allaravel.com/tutorials/inversion-of-control-nguyen-ly-cua-cac-nguyen-ly/'},
                {title: 'Design Pattern sự tiến hóa trong lập trình', url: 'https://allaravel.com/tutorials/design-pattern-su-tien-hoa-trong-lap-trinh/'},
                {title: 'SOLID 5 nguyên lý vàng trong thiết kế hướng đối tượng', url: 'https://allaravel.com/laravel-tutorials/solid-5-nguyen-ly-vang-trong-thiet-ke-huong-doi-tuong/'}
            ]
        }
    ]
}

Hãy duyệt qua mảng này và trình bày nội dung mảng lên như hình sau:

Những bài viết được xem nhiều nhất trên Allaravel

Phần lời giải sẽ có trong “Xử lý vòng lặp với v-for Phần 2” nhưng trước hết bạn hãy cố gắng hoàn thiện nó nhé. Hẹn gặp lại trong phần 2.

Add Comment