2011-12-07 25 views
6

Tôi hiện đang làm việc một plugin có biến cài đặt khá sâu (3-4 cấp ở một số nơi). Theo mẫu jQuery Plugin được chấp nhận chung, tôi đã triển khai một cách đơn giản để người dùng chỉnh sửa cài đặt nhanh chóng bằng cách sử dụng ký hiệu sau:Plugin jQuery - Sửa đổi tùy chọn sâu

$('#element').plugin('option', 'option_name', 'new_value'); 

Đây là mã tương tự với cách tôi đang sử dụng cho phương pháp tùy chọn.

option: function (option, value) { 
    if (typeof (option) === 'string') { 
     if (value === undefined) return settings[option]; 

     if(typeof(value) === 'object') 
      $.extend(true, settings[option], value); 
     else 
      settings[option] = value; 
    } 

    return this; 
} 

Bây giờ xem xét rằng tôi có một biến các thiết lập như sau:

var settings = { 
    opt: false, 
    another: { 
     deep: true 
    } 
}; 

Nếu tôi muốn thay đổi deep cài đặt tôi phải sử dụng các ký hiệu sau:

$('#element').plugin('option', 'another', { deep: false }); 

Tuy nhiên, vì trong thực tế, cài đặt của tôi có thể sâu 3-4 độ, tôi cảm thấy ký hiệu sau sẽ hữu ích hơn:

$('#element').plugin('option', 'another.deep', false); 

Tuy nhiên, tôi không chắc chắn về khả năng này, cũng như cách thực hiện. Là một nỗ lực đầu tiên tôi đã cố gắng "đi qua" đến tùy chọn được đề cập và đặt nó, nhưng nếu tôi đặt biến vượt qua của mình, nó sẽ không đặt biến nó tham chiếu trong biến cài đặt gốc.

option: function (option, value) { 
    if (typeof (option) === 'string') { 
     if (value === undefined) return settings[option]; 

     var levels = option.split('.'), 
      opt = settings[levels[0]]; 
     for(var i = 1; i < levels.length; ++i) 
      opt = opt[levels[i]]; 

     if(typeof(value) === 'object') 
      $.extend(true, opt, value); 
     else 
      opt = value; 
    } 

    return this; 
} 

Để nói rằng một cách khác: Bằng cách đặt opt sau khi di chuyển, thiết lập nó thực sự đề cập đến trong biến settings là không thay đổi sau khi mã này chạy.

Tôi xin lỗi vì câu hỏi dài, mọi trợ giúp đều được đánh giá cao. Cảm ơn!


EDIT

Như một nỗ lực thứ hai tôi có thể làm điều đó bằng eval() như vậy:

option: function (option, value) { 
    if (typeof (option) === 'string') { 
     var levels = option.split('.'), 
      last = levels[levels.length - 1]; 

     levels.length -= 1; 

     if (value === undefined) return eval('settings.' + levels.join('.'))[last]; 

     if(typeof(value) === 'object') 
      $.extend(true, eval('settings.' + levels.join('.'))[last], value); 
     else 
      eval('settings.' + levels.join('.'))[last] = value; 
    } 

    return this; 
} 

Nhưng tôi thực sự muốn xem có ai có thể chỉ cho tôi một cách để không sử dụng eval. Vì đây là chuỗi đầu vào của người dùng nên tôi không muốn chạy eval() vì nó có thể là bất kỳ thứ gì. Hoặc cho tôi biết nếu tôi bị hoang tưởng, và nó không gây ra vấn đề gì cả.

Trả lời

2

Vấn đề bạn đang chạy vào đây đi xuống đến sự khác biệt giữa các biến trỏ đến đối tượng và các biến cho các loại khác như Strings.2 biến thể trỏ đến cùng Object, nhưng không phải với cùng String:

var a = { foo: 'bar' }; 
    var b = 'bar'; 
    var a2 = a; 
    var b2 = b; 
    a2.foo = 'hello world'; 
    b2 = 'hello world'; 
    console.log(a.foo); // 'hello world' 
    console.log(b); // 'bar' 

đang traversal của bạn hoạt động tốt cho đến khi lặp cuối cùng của vòng lặp, tại thời điểm đó opt là một biến chứa cùng giá trị deep bên trong đối tượng settings.opt.another. Thay vào đó, cắt vòng lặp của bạn ngắn và sử dụng các yếu tố cuối cùng của levels như một key, như

var settings = { 
    another: { 
     deep: true 
    } 
    }; 

    var levels = 'another.deep'.split('.') 
    , opt = settings; 

    // leave the last element 
    var i = levels.length-1; 

    while(i--){ 
    opt = opt[levels.shift()]; 
    } 
    // save the last element in the array and use it as a key 
    var k = levels.shift(); 
    opt[k] = 'foobar'; // settings.another.deep is also 'foobar' 

Ở giai đoạn này opt là một con trỏ đến cùng Object như settings.anotherk là một String với giá trị 'deep'

+0

Tuyệt vời, sự nhầm lẫn về tài liệu tham khảo có những gì đã được giải quyết vấn đề. Cảm ơn cho sạch nó lên cho tôi; Tôi có một phương pháp làm việc bây giờ nhờ vào câu trả lời của bạn. – Chad

0

Làm thế nào về việc sử dụng eval thay vì truyền tải?

var settings = { 
opt: false, 
    another: { 
deep: true, 

    } 
}; 

var x = "settings.another"; 
eval(x).deep = false; 
alert(settings.another.deep); 
+1

Tôi đã cố gắng tránh sử dụng 'eval' trên chuỗi đầu vào của người dùng, vì sử dụng nó theo cách này làm cho plugin của tôi chấp nhận javascript được tiêm ... – Chad

+0

Không có bảo mật nào ở phía trình duyệt. Người dùng có thể chạy bất kỳ js nào họ muốn và gửi bất kỳ truy vấn nào. –

0

Được xây dựng trong jQuery $().extend() không chính xác những gì bạn cần?

http://api.jquery.com/jQuery.extend/

* lưu ý phương pháp chữ ký thứ hai với agument đầu tiên của true thực hiện một hợp nhất sâu ...

+0

Đúng, nhưng điều đó có nghĩa là anh ta sẽ phải sử dụng cú pháp mà anh ta hy vọng sẽ thay thế ở đây. Mục tiêu là truy cập các biến đó với ký hiệu chấm trong một đối số chuỗi cho hàm. –

+0

Giống như Daniel đã nói, tôi đang sử dụng phương pháp mở rộng nếu người dùng vượt qua một đối tượng, tuy nhiên họ phải vượt qua một đối tượng cho các thiết lập sâu. Tôi đang cố gắng cho phép họ tùy chọn chuỗi. – Chad

Các vấn đề liên quan