Web Drop Down Menu: Hướng Dẫn Toàn Diện Khắc Phục Lỗi Tương Tác Tự Động Hóa

Rate this post

web drop down menu là một thành phần giao diện không thể thiếu trên hầu hết các website hiện đại, đóng vai trò quan trọng trong việc thu thập dữ liệu và điều hướng người dùng. Tuy nhiên, khi chuyển sang môi trường tự động hóa quy trình bằng robot (RPA) hoặc các công cụ kiểm thử, các menu thả xuống này thường trở thành điểm nghẽn kỹ thuật phức tạp nhất. Bài viết này sẽ đi sâu phân tích cơ chế hoạt động, nguyên nhân gây ra lỗi “mất kích hoạt sự kiện” (missing trigger), và cung cấp các giải pháp chuyên sâu để đảm bảo quá trình tự động hóa thành công. Chúng tôi sẽ tập trung vào sự khác biệt giữa mô phỏng hành vi người dùng và kích hoạt sự kiện cấp độ mã nguồn, hai khía cạnh then chốt trong tự động hóa element web. Để giải quyết triệt để các thách thức trong việc xử lý dropdown menu, việc hiểu rõ luồng sự kiện (event flow) là bắt buộc.

Bản Chất Kỹ Thuật Của Web Drop Down Menu Trong Tự Động Hóa

Mặc dù bề ngoài đơn giản, một menu thả xuống trên web có thể được xây dựng bằng nhiều công nghệ khác nhau, dẫn đến các thách thức đa dạng trong tự động hóa. Việc tự động hóa thành công đòi hỏi sự hiểu biết sâu sắc về cấu trúc DOM (Document Object Model) và cách thức các sự kiện JavaScript được kích hoạt.

Phân Loại Cơ Bản: Standard <select> vs. Custom JS/CSS

Có hai loại menu thả xuống chính mà một công cụ RPA phải đối mặt. Sự khác biệt này quyết định chiến lược tự động hóa mà bạn nên áp dụng.

Menu <select> chuẩn HTML là loại cơ bản nhất, sử dụng thẻ <select> và các thẻ con <option>. [Bằng chứng chuyên môn] cho thấy, khi người dùng chọn một mục trong menu này, trình duyệt sẽ tự động kích hoạt sự kiện change (thay đổi). Các công cụ tự động hóa cấp độ cao thường có thể tương tác trực tiếp với DOM để đặt giá trị (value) mà không cần mô phỏng thao tác click chuột. Điều này thường được thực hiện qua lệnh select đơn giản, vốn là cách tiếp cận nhanh chóng và đáng tin cậy nhất.

Ngược lại, các thành phần tùy chỉnh (Custom Components) được tạo ra bằng JavaScript và CSS (thường gặp trong các framework như React, Angular, hoặc Vue). Chúng không sử dụng thẻ <select> gốc mà sử dụng các thẻ <div>, <ul>, và <li> để mô phỏng giao diện của một menu thả xuống. Trong trường hợp này, việc chọn một mục đòi hỏi phải mô phỏng chính xác trình tự hành động của người dùng: click vào nút mở (trigger button), chờ danh sách hiện ra, sau đó click vào mục mong muốn. Thao tác này thường liên quan đến các sự kiện onClick thay vì change.

Cơ Chế Sự Kiện (Event Mechanism) Và Tầm Quan Trọng Của Trigger

Trong lập trình web, sự kiện là cầu nối giữa hành động của người dùng (hoặc robot) và phản hồi của ứng dụng. Khi một mục được chọn từ menu thả xuống, trang web có thể cần thực hiện một hoặc nhiều hành động, như điền dữ liệu vào một trường khác, làm hiển thị một trường văn bản bị ẩn, hoặc gửi một yêu cầu AJAX lên máy chủ.

Các sự kiện quan trọng nhất liên quan đến web drop down menu bao gồm: change, input, click, và blur. Lệnh select của các công cụ RPA thường chỉ làm thay đổi thuộc tính value của phần tử. Nó có thể không tự động kích hoạt sự kiện JavaScript đính kèm, đặc biệt là sự kiện change. Nếu nhà phát triển web thiết kế trang web chỉ phản hồi khi sự kiện change được kích hoạt (dispatched) một cách tự nhiên bởi trình duyệt hoặc được gọi rõ ràng bằng mã JavaScript, công cụ tự động hóa sẽ thất bại.

Đây chính là nguyên nhân cốt lõi dẫn đến vấn đề trong bài toán thực tế. Công cụ RPA (UI Vision) có thể thiết lập giá trị chính xác bằng lệnh select, nhưng nếu trang web yêu cầu một “trigger” cụ thể (như sự kiện change được kích hoạt sau khi giá trị được đặt), và lệnh select chỉ đơn thuần thay đổi DOM mà không kích hoạt sự kiện, thì bước tiếp theo (hiển thị trường văn bản) sẽ không bao giờ xảy ra.

Xem thêm  One More Cafe Menu: Khám Phá Trọn Vẹn Thực Đơn Và Đánh Giá Chi Tiết Tại Chikhli

Phân Tích Chi Tiết Sự Cố Của UI Vision RPA Trên MacOS

Trường hợp sử dụng UI Vision RPA trên MacOS 12.0.1 với Chrome Version 105.0.5195.102 là một ví dụ điển hình về xung đột giữa mô phỏng cấp độ API và mô phỏng cấp độ vật lý trong tự động hóa. Người dùng đã xác nhận vấn đề xảy ra khi sử dụng công cụ UI Vision RPA 8.0.1.

Phân Tích Lệnh clickselect (Native vs. Simulated Event)

Trong lần thử đầu tiên, kịch bản tự động hóa ghi lại đã sử dụng tổ hợp lệnh “click” và sau đó “select”.

  1. Lệnh click: Lệnh này có thể dùng để mở menu thả xuống (nếu đó là menu tùy chỉnh) hoặc chỉ đơn giản là chuẩn bị cho thao tác tiếp theo.
  2. Lệnh select: Lệnh này được thiết kế để tương tác trực tiếp với các thẻ <select> chuẩn HTML. Về mặt kỹ thuật, nó sẽ tìm phần tử <option> có giá trị tương ứng và đặt thuộc tính selected thành true cho phần tử đó.

Kết quả của lần thử này là: UI Vision CHỌN ĐÚNG GIÁ TRỊ nhưng KHÔNG KÍCH HOẠT TƯƠNG TÁC WEB tiếp theo. Điều này gần như khẳng định rằng menu thả xuống đang được xử lý bằng JavaScript thông qua một event listener (bộ lắng nghe sự kiện), và lệnh select của UI Vision chỉ đơn thuần thay đổi thuộc tính DOM (Document Object Model) mà không gửi đi sự kiện change cần thiết. Đây là một điểm yếu phổ biến khi các công cụ RPA cố gắng bỏ qua hành vi cấp độ trình duyệt để tương tác trực tiếp với DOM, nhằm tăng tốc độ thực thi.

Vấn Đề Với Phương Pháp Mô Phỏng Tọa Độ (XClickXType)

Khi người dùng chuyển sang sử dụng mô phỏng cấp độ hình ảnh và tọa độ bằng lệnh XClickXType, vấn đề lại chuyển sang một hướng khác, liên quan đến tương tác vật lý (mô phỏng chuột/bàn phím).

  1. XClick: Lệnh này hoạt động dựa trên tọa độ màn hình hoặc nhận dạng hình ảnh, mô phỏng một cú click chuột thật. Nó được sử dụng để mở menu thả xuống, hành động này đã thành công.
  2. XType: Lệnh này mô phỏng việc gõ phím. Người dùng đã sử dụng nó để gõ tên mục mong muốn. Điều này thường hoạt động tốt trong các menu tìm kiếm hoặc khi menu hỗ trợ gõ phím để di chuyển nhanh.
  3. XType ${KEY_ENTER}: Lẽ ra lệnh này phải mô phỏng việc nhấn Enter để xác nhận lựa chọn. Tuy nhiên, nó bị “treo” (hang) và không thực sự chọn mục đó.

Sự cố này cho thấy một thách thức kép:

  • Hành vi của XType có thể bị ảnh hưởng bởi timing (thời gian) và bối cảnh hoạt động của hệ điều hành (MacOS 12.0.1). Đôi khi, sau khi gõ xong, cần có một độ trễ nhỏ để giao diện người dùng phản ứng trước khi nhấn Enter.
  • Cơ chế hoạt động của menu thả xuống tùy chỉnh có thể yêu cầu một sự kiện onClick (click chuột) vào chính phần tử trong danh sách thay vì chỉ là phím Enter sau khi gõ.

Thao tác XType ${KEY_ESC} đôi khi chọn mục đầu tiên (erratic behavior) càng củng cố giả thuyết rằng việc tương tác cấp độ vật lý không khớp hoàn toàn với logic xử lý sự kiện của trang web.

Sự Khác Biệt Giữa Mô Phỏng Người Dùng Thật Và Sự Kiện Lập Trình

Thao tác thủ công của người dùng (khi được ghi lại bằng Automator trên Mac) đã thành công. Điều này là do khi người dùng thực hiện một chuỗi thao tác: Click mở, Click chọn, trình duyệt sẽ tự nhiên kích hoạt toàn bộ luồng sự kiện: mousedown, mouseup, click, và quan trọng nhất là change hoặc các sự kiện tùy chỉnh khác.

Công cụ RPA, khi sử dụng lệnh select cấp độ DOM, chỉ thực hiện một bước (thay đổi giá trị) và bỏ qua các sự kiện khác. Khi sử dụng XClick/XType, nó cố gắng mô phỏng, nhưng sự mô phỏng này không hoàn hảo và dễ bị thất bại do các yếu tố môi trường (tốc độ CPU, độ trễ mạng, thay đổi giao diện nhỏ). Việc khắc phục phải hướng tới một trong hai hướng: Hoặc là mô phỏng người dùng thật một cách hoàn hảo hoặc là can thiệp vào mã nguồn JavaScript để kích hoạt sự kiện bằng lập trình.

Các Phương Pháp Khắc Phục Nâng Cao Cho Lỗi Mất Trigger

Để giải quyết triệt để vấn đề mất kích hoạt sự kiện, đặc biệt là khi tương tác với web drop down menu tùy chỉnh, cần phải vượt qua các lệnh tự động hóa cơ bản và sử dụng các kỹ thuật can thiệp sâu hơn.

Phương Pháp A: Kích Hoạt Sự Kiện JavaScript Trực Tiếp (JavaScript Injection)

Đây là phương pháp đáng tin cậy nhất vì nó đi thẳng vào vấn đề: kích hoạt sự kiện cần thiết. Sau khi lệnh select đã thành công thay đổi giá trị của menu thả xuống (mà không kích hoạt sự kiện), bạn cần thêm một lệnh để buộc sự kiện đó phải xảy ra.

Bước thực hiện (sử dụng lệnh executeScript trong UI Vision):

  1. Thực hiện lệnh select: Dùng lệnh select để chọn giá trị mong muốn.
    • select | id=dropdown_id | value=muc_can_chon (Giả sử menu là <select> chuẩn).
  2. Kích hoạt sự kiện change: Sử dụng JavaScript để tạo và kích hoạt sự kiện change trên phần tử đó.
    • executeScript | var element = document.getElementById('dropdown_id'); element.dispatchEvent(new Event('change', {bubbles: true}));

Lệnh dispatchEvent sẽ tạo ra một sự kiện mới (ở đây là change), và thuộc tính {bubbles: true} đảm bảo sự kiện đó lan truyền lên cây DOM (bubbling), mô phỏng chính xác hơn hành vi tự nhiên của trình duyệt. Phương pháp này bỏ qua sự cần thiết của việc mô phỏng chuột/bàn phím và tương thích cao hơn với nhiều trình duyệt.

Xem thêm  Menu Kebab: Giải Mã Biểu Tượng Ba Dấu Chấm Trong Thiết Kế Giao Diện

Phương Pháp B: Kết Hợp XClick Chính Xác Và XMove

Nếu menu thả xuống là loại tùy chỉnh (custom dropdown) không phải <select> chuẩn, Phương pháp A sẽ không hoạt động, và việc quay lại mô phỏng vật lý là cần thiết, nhưng phải được thực hiện một cách chính xác hơn.

Chiến lược ở đây là đảm bảo cú click cuối cùng kích hoạt sự kiện onClick của phần tử menu con.

  1. Mở menu: Dùng XClick vào nút mở (trigger button).
  2. Xác định tọa độ mục tiêu: Đây là phần khó khăn. Cần sử dụng công cụ xác định tọa độ tương đối hoặc tuyệt đối một cách đáng tin cậy, hoặc sử dụng tính năng tìm kiếm hình ảnh của UI Vision.
  3. Di chuyển chuột (Tùy chọn): Dùng XMove để di chuyển chuột đến vị trí của mục cần chọn. Thao tác di chuột qua (hover) này đôi khi kích hoạt các lớp CSS hoặc sự kiện mouseover cần thiết.
  4. Click chọn: Dùng XClick chính xác vào mục cần chọn.

Việc XType ${KEY_ENTER} bị treo trong trường hợp gốc cho thấy nó đang đợi một phản hồi giao diện không bao giờ đến. Thay vì dùng XType, việc mô phỏng click chuột trực tiếp vào tọa độ của phần tử trong danh sách sẽ kích hoạt sự kiện click và hoàn tất quá trình lựa chọn, đồng thời kích hoạt luồng sự kiện web tiếp theo.

Phương Pháp C: Thay Đổi Giá Trị và Mô Phỏng Thao Tác Rời Chuột (onBlur)

Trong một số trường hợp, các nhà phát triển web gắn sự kiện kích hoạt vào onBlur (sự kiện xảy ra khi một phần tử mất focus). Điều này thường xảy ra sau khi người dùng click ra khỏi trường đó.

Nếu lệnh select hoặc XClick của bạn đã thay đổi giá trị nhưng không kích hoạt hành động tiếp theo, hãy thử buộc phần tử đó mất focus sau khi thay đổi giá trị.

  1. Thay đổi giá trị: Dùng select hoặc XClick để chọn mục.
  2. Buộc phần tử mất focus:
    • Giải pháp JS: executeScript | document.getElementById('dropdown_id').blur();
    • Giải pháp RPA: Click vào một phần tử khác trên trang (ví dụ: một trường văn bản khác hoặc một khu vực trống) bằng click hoặc XClick để buộc menu thả xuống ban đầu mất focus.

Phương pháp này hiệu quả khi sự kiện onBlur là sự kiện duy nhất được sử dụng để bắt đầu quá trình xác thực hoặc hiển thị trường tiếp theo.

Chiến Lược Lựa Chọn Lệnh Tự Động Hóa Phù Hợp (Select vs. XClick/XType)

Việc lựa chọn lệnh tự động hóa không chỉ là vấn đề sở thích mà còn là một quyết định kỹ thuật dựa trên cấu trúc của web drop down menu đang được tương tác.

Khi Nào Nên Dùng Lệnh Select (Ưu tiên Lớp Phủ DOM)

Lệnh select nên là lựa chọn ưu tiên hàng đầu nếu phần tử đó là một thẻ <select> chuẩn HTML.

  • Tính ổn định: Tương tác trực tiếp với DOM ít bị ảnh hưởng bởi thay đổi giao diện, độ phân giải màn hình hoặc môi trường hệ điều hành.
  • Tốc độ: Thực thi nhanh hơn vì không cần đợi các hoạt ảnh UI (User Interface) hoàn thành.
  • Khả năng phục hồi: Tốt hơn vì nó dựa trên ID hoặc XPath của phần tử, vốn ổn định hơn tọa độ màn hình.

Tuy nhiên, nếu lệnh select không kích hoạt trigger (như trong trường hợp gốc), hãy sử dụng kết hợp với executeScript để kích hoạt sự kiện JavaScript (Phương pháp A).

Khi Nào Bắt Buộc Phải Dùng Lệnh XClickXType (Mô Phỏng Vật Lý)

Các lệnh cấp độ hình ảnh và tọa độ (XClick, XType, XMove) là bắt buộc đối với các menu thả xuống tùy chỉnh (custom dropdown) hoặc các thành phần có logic phức tạp.

  • Menu Tùy Chỉnh: Hầu hết các thư viện UI hiện đại (như Bootstrap Select, Select2, Chosen, v.v.) đều tạo ra các menu không phải <select> gốc. Các công cụ RPA không thể sử dụng lệnh select trên chúng.
  • Yêu cầu Tương Tác Cụ Thể: Khi việc chọn một mục đòi hỏi phải kích hoạt chính xác một chuỗi sự kiện chuột/bàn phím (ví dụ: một sự kiện onContextMenu hoặc onDoubleClick hiếm gặp).

Khi sử dụng XClick/XType, việc mô phỏng hành vi người dùng cần phải chính xác đến từng bước nhỏ: Click mở, Chờ, Click chọn, Chờ.

Kỹ Thuật Chờ (Wait Techniques) Để Đảm Bảo Thành Công

Trong tự động hóa, đặc biệt là khi tương tác với các thành phần AJAX hoặc menu thả xuống, vấn đề về thời gian (timing) là nguyên nhân hàng đầu gây ra lỗi. Trường hợp người dùng XType ${KEY_ENTER} bị treo có thể là do công cụ RPA đã thực hiện lệnh này quá nhanh trước khi danh sách mục đã sẵn sàng để chấp nhận đầu vào.

Cần sử dụng các lệnh chờ có điều kiện (Explicit Waits) thay vì chờ cố định (Implicit Waits/Fixed Delays).

  • waitForVisible: Chờ cho đến khi danh sách mục thả xuống (hoặc trường văn bản tiếp theo) trở nên hiển thị.
  • waitForElementPresent: Đảm bảo phần tử trong danh sách đã được tải vào DOM.

Ví dụ: Sau khi XClick mở menu, cần thêm waitForVisible | //xpath_của_danh_sách_mục trước khi thực hiện XType hoặc XClick chọn mục. Điều này đảm bảo robot không cố gắng tương tác với một phần tử chưa tồn tại hoặc chưa hiển thị.

Tối Ưu Hóa Kịch Bản Tự Động Hóa Cho Môi Trường Đa Nền Tảng

Mặc dù trường hợp gốc xảy ra trên MacOS 12.0.1 và Chrome, một kịch bản tự động hóa chất lượng cao phải có khả năng hoạt động ổn định trên nhiều hệ điều hành và trình duyệt khác nhau.

Xem thêm  custom menu electron: Hướng Dẫn Chi Tiết Xây Dựng Thanh Menu Tùy Chỉnh

Thách Thức Của Các Trình Duyệt và Hệ Điều Hành Khác Nhau

Môi trường tự động hóa có thể thay đổi đáng kể hành vi của các lệnh.

  • Hệ điều hành: Trên Mac, cơ chế xử lý sự kiện cấp độ GUI (Graphical User Interface) của Chrome có thể khác biệt nhẹ so với Windows hoặc Linux, ảnh hưởng đến độ tin cậy của các lệnh mô phỏng vật lý như XClick. Các yếu tố như Scaling (tỷ lệ hiển thị) hoặc trạng thái ẩn (headless mode) đều có thể làm lệch tọa độ.
  • Trình duyệt: Cùng một lệnh select có thể tự động kích hoạt sự kiện change trong Firefox nhưng lại thất bại trong Chrome (hoặc ngược lại), tùy thuộc vào cách trình duyệt triển khai các sự kiện DOM cấp thấp.

Giải pháp tối ưu là sử dụng phương pháp JavaScript Injection (Phương pháp A) kết hợp với lệnh select bất cứ khi nào có thể, vì đây là phương pháp tương tác ở cấp độ mã nguồn, ít bị ảnh hưởng bởi giao diện người dùng.

Thiết Kế Mã Tự Động Hóa Có Khả Năng Phục Hồi (Resilient Automation)

Một kịch bản tự động hóa hiệu quả phải có khả năng xử lý lỗi. Đối với web drop down menu, điều này có nghĩa là thiết kế một quy trình dự phòng:

  1. Thử Phương án 1 (Ưu tiên): select + executeScript (kích hoạt change).
  2. Kiểm tra kết quả: Sử dụng verifyElementPresent hoặc waitForVisible để kiểm tra xem trường văn bản tiếp theo đã hiển thị chưa.
  3. Thử Phương án 2 (Dự phòng): Nếu Phương án 1 thất bại, chuyển sang chuỗi XClick mở + XClick chọn mục + waitForVisible.

Chiến lược thử-và-thất bại có kiểm soát này đảm bảo rằng quy trình tự động hóa có thể thích ứng với các loại menu thả xuống khác nhau mà không cần sự can thiệp thủ công liên tục. Trong trường hợp cụ thể của người dùng, việc áp dụng Phương pháp A (JavaScript Injection) ngay sau lệnh select là bước tiến đột phá, bởi vì nó giải quyết chính xác sự thiếu vắng của sự kiện kích hoạt sau khi giá trị đã được thay đổi.

Ngoài ra, cần lưu ý rằng các thông tin kỹ thuật như phiên bản hệ điều hành (MacOS 12.0.1), trình duyệt (Chrome 105.0.5195.102), và công cụ RPA (UI Vision RPA 8.0.1) là cực kỳ quan trọng cho việc gỡ lỗi. Các bản cập nhật phần mềm thường sửa lỗi, nhưng cũng có thể vô tình làm hỏng các phương pháp tự động hóa dựa trên tọa độ hoặc API không chính thức.

Sơ đồ minh họa vấn đề tương tác web drop down menu và kích hoạt sự kiện trong UI Vision RPASơ đồ minh họa vấn đề tương tác web drop down menu và kích hoạt sự kiện trong UI Vision RPA

Tối Ưu Hóa Tốc Độ Thực Thi Lệnh

Mặc dù Quy tắc Hemingway khuyến khích sự ngắn gọn và dứt khoát, trong tự động hóa, đôi khi sự “chậm trễ” có chủ đích lại là chìa khóa. Các lệnh mô phỏng vật lý cần có thời gian để hệ thống xử lý, đặc biệt là trên các trang web có tải nặng hoặc máy tính có cấu hình trung bình.

Thay vì dựa vào độ trễ mặc định của công cụ, hãy sử dụng lệnh pause (ví dụ: pause | 500) sau các tương tác quan trọng như XClick mở menu, hoặc trước khi XClick chọn mục, để cho phép DOM hoặc CSS kịp thời hoàn thành các hiệu ứng chuyển đổi trước khi robot thực hiện hành động tiếp theo.

Kỹ Thuật Chuyên Sâu: Xử Lý Các Sự Kiện Lồng Nhau và Thay Đổi Động

Các web drop down menu phức tạp có thể kích hoạt nhiều sự kiện lồng nhau (chained events). Ví dụ, chọn một Tỉnh thành sẽ kích hoạt tải danh sách Quận huyện, sau đó chọn Quận huyện sẽ kích hoạt tải danh sách Phường xã.

Để xử lý các sự kiện này, chiến lược tự động hóa phải tập trung vào việc xác minh trạng thái (state verification) thay vì chỉ thực hiện lệnh.

  1. Hành động: select | id=tinh_thanh | value=HN
  2. Xác minh & Chờ: waitForElementPresent | id=quan_huyen (Chờ cho đến khi menu Quận/Huyện được tải vào DOM).
  3. Hành động: select | id=quan_huyen | value=Đong_Đa

Trong trường hợp các menu được tạo động (dynamic creation), việc sử dụng XPath tương đối hoặc CSS Selector là cần thiết. Tuyệt đối không dựa vào các ID được tạo tự động sau mỗi lần tải trang, vì chúng sẽ thay đổi và làm hỏng kịch bản tự động hóa. Hãy luôn sử dụng các thuộc tính tĩnh (ví dụ: name, class hoặc data- attribute) để định vị phần tử.

Việc nắm vững các cơ chế tương tác và kích hoạt sự kiện là chìa khóa để vượt qua các rào cản kỹ thuật như lỗi mất trigger đã nêu. Bằng cách áp dụng các phương pháp can thiệp cấp độ JavaScript và mô phỏng vật lý chính xác, quy trình tự động hóa có thể đạt được độ tin cậy và khả năng phục hồi cao nhất.

Bất kể thách thức đến từ hệ điều hành MacOS 12.0.1, trình duyệt Chrome, hay phiên bản UI Vision RPA 8.0.1, giải pháp tối ưu luôn nằm ở việc hiểu rõ sự khác biệt giữa việc thay đổi giá trị của phần tử và việc kích hoạt luồng sự kiện JavaScript đính kèm. Khả năng giải quyết các vấn đề liên quan đến web drop down menu là thước đo rõ ràng nhất về sự chuyên nghiệp và kinh nghiệm của một kỹ sư tự động hóa.

Ngày Cập Nhật: Tháng 11 20, 2025 by Ngô Hồng Thái

Avatar photo
Ngô Hồng Thái

Ngô Hồng Thái từng có hơn 20 năm kinh nghiệm trong ngành báo chí truyền thống. Chính nền tảng này đã rèn luyện cho anh một con mắt quan sát tinh tế, khả năng phát hiện những câu chuyện bình dị nhưng đầy ý nghĩa trong cuộc sống. Anh không chỉ là một nhiếp ảnh gia bấm máy mà còn là một nhà báo kể chuyện bằng ngôn ngữ.

Bài viết: 30869

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *