Tìm hiểu về cách xây dựng web widget (P1)

Web widget ngày này được sử dụng khá nhiều, ví dụ như các button like, share, comment... của facebook. Hay các chat ember widget như của subiz, tawk. Từ trước đến nay mình sử dùng mấy cái này cho website của mình và khách hàng khá nhiều, nhưng chưa bao giờ nghĩ sẽ tự build một cái.

Đợt vừa rồi trong dự án có yêu cầu phải làm 1 cái web widget như vậy, mình đã phải research trên mạng và học được khá nhiều vấn đề hay ho và muốn chia sẻ cùng các bạn.

 

Web widget là gì?

Web widget là một thành phần nhỏ trên website (component), nó cho phép hiện thị dữ liệu của bạn trên các website của khách hàng khi họ nhúng ember code của bạn trên site của họ.

Một widget thông thường là sự kết hợp giữa html, javascript & css. Và thông thường mã nguồn cái phần này khá rối rắm và phức tạp.

Tuy nhiên việc chúng ta cần làm là ẩn cái mớ hỗn độn kia ở phía sau (xử lý ở trong 1 file script độc lập), và đưa ra một đoạn mã nhúng sao cho chúng dễ dàng nhất để người dùng có thể tích hợp nhanh chóng trên website của họ

Ví dụ một đoạn ember code như sau

<script src="http://thuyvk.com/widget/script.js" type="text/javascript"></script>
<div id="example-widget-container"></div>

Khi bạn nhúng đoạn ember code này vào website, script.js sẽ thực thi khi DOM load và đẩy dữ liệu trả về vào thẻ div #example_widget_container

 

Cô lập code.

Bởi vì bạn không thể nào đoán được trên website khách hàng sẽ sử dụng những đoạn mã javascript hay thư viện jquery... nào. Do vậy chúng ta cần phải có một cách để đảm bảo script của chúng ta sinh ra khi nhúng vào site của khách hàng không gây lỗi.

Để làm việc này, chúng ta hãy để toàn bộ mã nguồn trong một anonymos function. Những biến và và hàm xử lý trong này sẽ không gây xung đột với các phần còn lại trên website của khách hàng.

Các bạn xem ví dụ dưới đây:

var foo = "Hello World!";
document.write("<p>Before our anonymous function foo means '" + foo + '".</p>');

(function() {
    // The following code will be enclosed within an anonymous function
    var foo = "Goodbye World!";
    document.write("<p>Inside our anonymous function foo means '" + foo + '".</p>');
})(); // We call our anonymous function immediately

document.write("<p>After our anonymous function foo means '" + foo + '".</p>');

Ở ví dụ trên, khi chạy các bạn sẽ thấy giá trị biến foo trong hàm anonymos sẽ hoàn toàn độc lập và không ảnh hưởng đến  biến foo của toàn trang.

Một chú ý quan trọng nữa là trong hàm anonymos của chúng ta, luôn phải khai báo var với các biến sử dụng. Lý do thì các bạn có thể xem thêm ở đây http://www.javascripttoolbox.com/bestpractices/#var

Tải jQuery

Code widget chủ yếu là Javascript, và các bạn thường sẽ sử dụng jQuery để hỗ trợ việc viết code nhanh hơn so với viết Javascript thông thường. Chúng ta sẽ không thể biết được trên website khách hàng có sẵn jQuery hay chưa, và liệu version có đúng với cái mình cần hay không? 

Do vậy chúng ta phải tiến hành kiểm tra và load jQuery trước.

(function () {

    // Localize jQuery variable
    var jQuery;

    /******** Load jQuery if not present *********/
    if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.4.2') {
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type", "text/javascript");
        script_tag.setAttribute("src",
            "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
        if (script_tag.readyState) {
            script_tag.onreadystatechange = function () { // For old versions of IE
                if (this.readyState == 'complete' || this.readyState == 'loaded') {
                    scriptLoadHandler();
                }
            };
        } else { // Other browsers
            script_tag.onload = scriptLoadHandler;
        }
        // Try to find the head, otherwise default to the documentElement
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
    } else {
        // The jQuery version on the window is the one we want to use
        jQuery = window.jQuery;
        main();
    }

    /******** Called once jQuery has loaded ******/
    function scriptLoadHandler() {
        // Restore $ and window.jQuery to their previous values and store the
        // new jQuery in our local jQuery variable
        jQuery = window.jQuery.noConflict(true);
        // Call our main function
        main();
    }

    /******** Our main function ********/
    function main() {
        jQuery(document).ready(function ($) {
            // We can use jQuery 1.4.2 here
            
        });
    }

})(); // We call our anonymous function immediately

Ở hàm trên khi chạy sẽ tiến hành kiểm tra trên website được tích hợp ember code đã có jQuery chưa, và có đúng version không (các bạn có thể bỏ qua đoạn check version nếu không cần thiết). Khi trên web hiện tại chưa có sẽ tiến hành tải jQuery về bằng cách tạo 1 script element có src đến thư viện jQuery cần dùng.

Những đoạn mã chúng ta viết trong widget sẽ sử dụng jQuery, do vậy chúng ta cần chắc chắn thư viện đã tải xong. Bằng cách định nghĩa hàm scriptLoadHandler sẽ được gọi khi các thư viện được load completely, với hầu hết các trình duyệt như Chrome, Firefox, Opera.. chúng ta chỉ cần gán scriptLoadHandler vào thuộc tính onload của script element

script_tag.onload = scriptLoadHandler;

Với thằng IE thì nó lại dựa vào readyState, onreadystatechange

if (script_tag.readyState) {
            script_tag.onreadystatechange = function () { // For old versions of IE
                if (this.readyState == 'complete' || this.readyState == 'loaded') {
                    scriptLoadHandler();
                }
            };
        }

Một vấn đề nữa cần chú ý là ta phải đảm bảo thư viện jQuery của widget tải về sẽ làm việc tốt các version khác nếu có trên website khách hàng, do vậy trong hàm scriptLoadHandler ta thêm như sau:

jQuery = window.jQuery.noConflict(true);

Cuối cùng, trong hàm scriptLoadHandler, ta gọi hàm main(), trong hàm này ta sẽ viết các xử lý cho widget

 /******** Called once jQuery has loaded ******/
    function scriptLoadHandler() {
        // Restore $ and window.jQuery to their previous values and store the
        // new jQuery in our local jQuery variable
        jQuery = window.jQuery.noConflict(true);
        // Call our main function
        main();
    }

    /******** Our main function ********/
    function main() {
        jQuery(document).ready(function ($) {
            // We can use jQuery 1.4.2 here
            $('#example-widget-container').html('<h1>Hello World</h1>');
        });
    }

 

Tải CSS

Ở ví dụ trên ta thấy sau khi hàm Javascript thực thi sẽ trả về HTML Content vào thẻ div #example-widget-container. Chúng ta sẽ cần tải thêm CSS về nữa để tạo giao diện cho widget.

 function main() {
        jQuery(document).ready(function ($) {
            //CSS
            var css_link = $("<link>", {
                rel: "stylesheet",
                type: "text/css",
                href: "http://thuyvk.com/content/StyleSheet1.css"
            });
            css_link.appendTo('head');

            //HTML
            $('#example-widget-container').html('<h1>Hello World</h1>');
        });
    }

Trong file StyleSheet chúng ta sẽ viết CSS để style cho các thẻ HTML trả về.

Tuy nhiên cũng có một vấn đề cần chú ý là việc đặt tên class hoặc id cho các html element các bạn đặt sao cho khó có thể trùng để tránh bị ảnh hưởng đến style của trang.

Kinh nghiệm của mình là đặt class sao cho dài và nguy hiểm, ví dụ: .thuyvk-widget-abc-xyz hoặc #thuyvk-webwidget-abc-xyz. Việc đặt dài và thêm các tiền tố sẽ tránh được việc bị trùng.

 

Tổng kết.

Ở ví dụ trên Widget đơn giản chỉ là trả về 1 đoạn static HTML &CSS để hiện thị trên website khách hàng.

Tuy nhiên thực tế phần xử lý này sẽ cần tương tác với server như đẩy dữ liệu về server khi người dùng tương tác hoặc lấy dữ liệu từ server dưới dạng JSON để hiện thị ra, mình sẽ nói thêm vấn đề này ở phần sau.

Các bạn có thể download ví dụ đầy đủ của phần này ở dưới đây

 

Download Source

Related Post


Tìm hiểu những tính năng mới của Javascript trong phiên bản ES6
Thursday, August 25, 2016
ECMAScript 6/ES6 là phiên bản mới nhất của bộ tiêu chuẩn ECMAScript – một bộ đặc tả tiêu chuẩn dành cho Javascript do Hiệp hội các nhà sản xuất máy tính Châu Âu (European Computer Manufacturers Association – ECMA) đề xuất. Phiên bảnECMAScript phổ biến ở thời điểm hiện tại (đầu 2015), và được hầu hết các trình duyệt hỗ trợ là ES5 và ES5.1 (ra mắt vào khoảng năm 2009 và 2011)
Tạo Date range picker với bootstrap datepicker
Tuesday, July 26, 2016
Hôm nay mình phải làm 1 chức năng nhỏ trong tìm kiếm, trong đó có 2 option chọn ngày CheckIn & CheckOut sử dụng Datepicker, yêu cầu là ngày CheckIn phải lớn hơn hoặc bằng ngày hiện tại, và ngày CheckOut phải lớn hơn ngày CheckIn, không cho phép chọn ngược về quá khứ. Yêu cầu có vậy thôi nhưng mò phát khùng mất 1 buổi, và mò ra rồi nên share cho bạn nào cần copy luôn phát cho nhanh
Search

Đăng ký nhận bài mới


Category

Blog Archive