Rất muộn với chủ đề, nhưng một kỹ thuật tôi đã sử dụng, trước Angular, là tận dụng JSON và tính linh hoạt của JS để tham chiếu động các khóa bộ sưu tập và sử dụng các sự kiện không thể thay đổi của môi trường (tên máy chủ lưu trữ, ngôn ngữ trình duyệt hiện tại , v.v.) làm đầu vào để phân biệt chọn lọc / thích các tên khóa có hậu tố trong cấu trúc dữ liệu JSON.
Điều này không chỉ cung cấp bối cảnh môi trường triển khai (trên mỗi OP) mà bất kỳ bối cảnh tùy ý nào (như ngôn ngữ) để cung cấp i18n hoặc bất kỳ phương sai nào khác được yêu cầu đồng thời, và (lý tưởng) trong một bảng kê khai cấu hình duy nhất, không trùng lặp và rõ ràng.
GIỚI THIỆU VỀ 10 DÒNG VANILLA JS
Ví dụ quá đơn giản nhưng cổ điển: URL cơ sở điểm cuối API trong tệp thuộc tính được định dạng JSON thay đổi theo từng môi trường trong đó (natch) máy chủ lưu trữ cũng sẽ thay đổi:
...
'svcs': {
'VER': '2.3',
'API@localhost': 'http://localhost:9090/',
'API@www.uat.productionwebsite.com': 'https://www.uat.productionwebsite.com:9090/res/',
'API@www.productionwebsite.com': 'https://www.productionwebsite.com:9090/api/res/'
},
...
Chìa khóa cho chức năng phân biệt đối xử chỉ đơn giản là tên máy chủ trong yêu cầu.
Điều này, một cách tự nhiên, có thể được kết hợp với một khóa bổ sung dựa trên cài đặt ngôn ngữ của người dùng:
...
'app': {
'NAME': 'Ferry Reservations',
'NAME@fr': 'Réservations de ferry',
'NAME@de': 'Fähren Reservierungen'
},
...
Phạm vi của phân biệt đối xử / ưu tiên có thể được giới hạn trong các khóa riêng lẻ (như trên) trong đó khóa "cơ sở" chỉ được ghi đè nếu có khóa khớp + hậu tố cho các đầu vào của hàm - hoặc toàn bộ cấu trúc và chính cấu trúc đó phân tích đệ quy để phù hợp với hậu tố phân biệt đối xử / ưu tiên:
'help': {
'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.',
'PHONE': '808-867-5309',
'EMAIL': 'coder.jen@lostnumber.com'
},
'help@www.productionwebsite.com': {
'BLURB': 'Please contact Customer Service Center',
'BLURB@fr': 'S\'il vous plaît communiquer avec notre Centre de service à la clientèle',
'BLURB@de': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': 'customer.service@productionwebsite.com'
},
Vì vậy, nếu người dùng truy cập vào trang web sản xuất có Đức ( de ) thiết lập tuỳ chọn ngôn ngữ, cấu hình trên sẽ sụp đổ đến:
'help': {
'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': 'customer.service@productionwebsite.com'
},
Hàm viết lại JSON ưa thích / phân biệt đối xử như vậy trông như thế nào? Không nhiều:
// prefer(object,suffix|[suffixes]) by/par/durch storsoc
// prefer({ a: 'apple', a@env: 'banana', b: 'carrot' },'env') -> { a: 'banana', b: 'carrot' }
function prefer(o,sufs) {
for (var key in o) {
if (!o.hasOwnProperty(key)) continue; // skip non-instance props
if(key.split('@')[1]) { // suffixed!
// replace root prop with the suffixed prop if among prefs
if(o[key] && sufs.indexOf(key.split('@')[1]) > -1) o[key.split('@')[0]] = JSON.parse(JSON.stringify(o[key]));
// and nuke the suffixed prop to tidy up
delete o[key];
// continue with root key ...
key = key.split('@')[0];
}
// ... in case it's a collection itself, recurse it!
if(o[key] && typeof o[key] === 'object') prefer(o[key],sufs);
};
};
Trong các triển khai của chúng tôi, bao gồm các trang web Angular và pre-Angular, chúng tôi chỉ cần khởi động lại cấu hình trước các lệnh gọi tài nguyên khác bằng cách đặt JSON trong một bao đóng JS tự thực thi, bao gồm hàm prefer () và cung cấp các thuộc tính cơ bản của tên máy chủ và mã ngôn ngữ (và chấp nhận bất kỳ hậu tố tùy ý bổ sung nào bạn có thể cần):
(function(prefs){ var props = {
'svcs': {
'VER': '2.3',
'API@localhost': 'http://localhost:9090/',
'API@www.uat.productionwebsite.com': 'https://www.uat.productionwebsite.com:9090/res/',
'API@www.productionwebsite.com': 'https://www.productionwebsite.com:9090/api/res/'
},
...
/* yadda yadda moar JSON und bisque */
function prefer(o,sufs) {
// body of prefer function, broken for e.g.
};
// convert string and comma-separated-string to array .. and process it
prefs = [].concat( ( prefs.split ? prefs.split(',') : prefs ) || []);
prefer(props,prefs);
window.app_props = JSON.parse(JSON.stringify(props));
})([location.hostname, ((window.navigator.userLanguage || window.navigator.language).split('-')[0]) ] );
Một trang web trước Angular bây giờ sẽ có một cửa sổ được thu gọn (không có hậu tố @) .app_props để tham khảo.
Một trang web Angular, như một bước bootstrap / init, chỉ cần sao chép đối tượng đạo cụ đã chết vào $ rootScope và (tùy chọn) phá hủy nó từ phạm vi toàn cầu / cửa sổ
app.constant('props',angular.copy(window.app_props || {})).run( function ($rootScope,props) { $rootScope.props = props; delete window.app_props;} );
để sau đó được tiêm vào bộ điều khiển:
app.controller('CtrlApp',function($log,props){ ... } );
hoặc được đề cập từ các ràng buộc trong quan điểm:
<span>{{ props.help.blurb }} {{ props.help.email }}</span>
Hãy cẩn thận? Ký tự @ không phải là cách đặt tên biến / khóa JS / JSON hợp lệ, nhưng cho đến nay vẫn được chấp nhận. Nếu đó là một công cụ thỏa thuận, hãy thay thế cho bất kỳ quy ước nào bạn thích, chẳng hạn như "__" (gạch dưới gấp đôi) miễn là bạn tuân thủ.
Kỹ thuật này có thể được áp dụng phía máy chủ, được chuyển sang Java hoặc C # nhưng hiệu quả / độ gọn của bạn có thể thay đổi.
Cách khác, hàm / quy ước có thể là một phần của tập lệnh biên dịch mặt trước của bạn, do đó, JSON toàn môi trường / tất cả ngôn ngữ hoàn toàn không bao giờ được truyền qua dây.
CẬP NHẬT
Chúng tôi đã phát triển việc sử dụng kỹ thuật này để cho phép nhiều hậu tố vào một khóa, để tránh bị buộc phải sử dụng các bộ sưu tập (bạn vẫn có thể, sâu như bạn muốn), và cũng để tôn vinh thứ tự của các hậu tố ưa thích.
Ví dụ (cũng xem jsFiddle hoạt động ):
var o = { 'a':'apple', 'a@dev':'apple-dev', 'a@fr':'pomme',
'b':'banana', 'b@fr':'banane', 'b@dev&fr':'banane-dev',
'c':{ 'o':'c-dot-oh', 'o@fr':'c-point-oh' }, 'c@dev': { 'o':'c-dot-oh-dev', 'o@fr':'c-point-oh-dev' } };
/*1*/ prefer(o,'dev'); // { a:'apple-dev', b:'banana', c:{o:'c-dot-oh-dev'} }
/*2*/ prefer(o,'fr'); // { a:'pomme', b:'banane', c:{o:'c-point-oh'} }
/*3*/ prefer(o,'dev,fr'); // { a:'apple-dev', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*4*/ prefer(o,['fr','dev']); // { a:'pomme', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*5*/ prefer(o); // { a:'apple', b:'banana', c:{o:'c-dot-oh'} }
1/2 (sử dụng cơ bản) thích các phím '@dev', loại bỏ tất cả các khóa có hậu tố khác
3 thích '@dev' hơn '@fr', thích '@ dev & fr' hơn tất cả những người khác
4 (giống như 3 nhưng thích '@fr' hơn '@dev')
5 không có hậu tố ưa thích, giảm TẤT CẢ các thuộc tính hậu tố
Nó thực hiện điều này bằng cách cho điểm từng thuộc tính có hậu tố và phát huy giá trị của thuộc tính có hậu tố thành thuộc tính không có hậu tố khi lặp qua các thuộc tính và tìm hậu tố có điểm cao hơn.
Một số tính hiệu quả trong phiên bản này, bao gồm loại bỏ sự phụ thuộc vào JSON vào bản sao sâu và chỉ đệ quy vào các đối tượng tồn tại trong vòng ghi điểm ở độ sâu của chúng:
function prefer(obj,suf) {
function pr(o,s) {
for (var p in o) {
if (!o.hasOwnProperty(p) || !p.split('@')[1] || p.split('@@')[1] ) continue; // ignore: proto-prop OR not-suffixed OR temp prop score
var b = p.split('@')[0]; // base prop name
if(!!!o['@@'+b]) o['@@'+b] = 0; // +score placeholder
var ps = p.split('@')[1].split('&'); // array of property suffixes
var sc = 0; var v = 0; // reset (running)score and value
while(ps.length) {
// suffix value: index(of found suffix in prefs)^10
v = Math.floor(Math.pow(10,s.indexOf(ps.pop())));
if(!v) { sc = 0; break; } // found suf NOT in prefs, zero score (delete later)
sc += v;
}
if(sc > o['@@'+b]) { o['@@'+b] = sc; o[b] = o[p]; } // hi-score! promote to base prop
delete o[p];
}
for (var p in o) if(p.split('@@')[1]) delete o[p]; // remove scores
for (var p in o) if(typeof o[p] === 'object') pr(o[p],s); // recurse surviving objs
}
if( typeof obj !== 'object' ) return; // validate
suf = ( (suf || suf === 0 ) && ( suf.length || suf === parseFloat(suf) ) ? suf.toString().split(',') : []); // array|string|number|comma-separated-string -> array-of-strings
pr(obj,suf.reverse());
}
'ngconstant:development'
trong'serve'
- nếu bạn đặt nó trong cấu hình đồng hồ dưới'gruntfile'
nhưtasks: ['ngconstant:development']
- bạn sẽ không cần phải khởi động lạigrunt serve
khi bạn cập nhật các biến phát triển trong gruntfile.