ดึกมากถึงเธรด แต่เทคนิคที่ฉันใช้ pre-Angular คือการใช้ประโยชน์จาก JSON และความยืดหยุ่นของ JS ในการอ้างอิงคีย์การรวบรวมแบบไดนามิกและใช้ข้อเท็จจริงที่ไม่สามารถเปลี่ยนแปลงได้ของสภาพแวดล้อม (ชื่อโฮสต์เซิร์ฟเวอร์ภาษาเบราว์เซอร์ปัจจุบัน เป็นต้น) เป็นอินพุตเพื่อเลือกแบ่งแยก / ต้องการชื่อคีย์ต่อท้ายภายในโครงสร้างข้อมูล JSON
สิ่งนี้ไม่เพียง แต่นำไปใช้กับบริบทของสภาพแวดล้อม (ต่อ OP) แต่บริบทใด ๆ (เช่นภาษา) เพื่อให้ i18n หรือความแปรปรวนอื่น ๆ ที่จำเป็นพร้อมกันและ (ในอุดมคติ) ภายในรายการการกำหนดค่าเดียวโดยไม่ต้องทำซ้ำ
ในประมาณ 10 LINES VANILLA JS
ตัวอย่างที่เรียบง่าย แต่สุดคลาสสิก: URL ปลายทางของ API ปลายทางในไฟล์คุณสมบัติที่จัดรูปแบบ JSON ซึ่งแตกต่างกันไปตามสภาพแวดล้อมที่ (natch) เซิร์ฟเวอร์โฮสต์จะแตกต่างกัน:
...
'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/'
},
...
กุญแจสำคัญในฟังก์ชั่นการเลือกปฏิบัติเป็นเพียงชื่อโฮสต์ของเซิร์ฟเวอร์ในคำขอ
โดยปกติสามารถรวมกับคีย์เพิ่มเติมตามการตั้งค่าภาษาของผู้ใช้:
...
'app': {
'NAME': 'Ferry Reservations',
'NAME@fr': 'Réservations de ferry',
'NAME@de': 'Fähren Reservierungen'
},
...
ขอบเขตของการเลือกปฏิบัติ / การกำหนดค่าตามความชอบสามารถถูก จำกัด อยู่ที่แต่ละคีย์ (ตามด้านบน) โดยที่คีย์ "base" จะถูกเขียนทับเฉพาะในกรณีที่มีคีย์ + ต่อท้ายที่ตรงกันสำหรับอินพุตไปยังฟังก์ชัน - หรือโครงสร้างทั้งหมดและโครงสร้างนั้นเอง แยกวิเคราะห์ซ้ำสำหรับการเลือก / การต่อท้ายการกำหนดลักษณะที่ตรงกัน:
'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'
},
ดังนั้นหากผู้ใช้ที่เข้าชมเว็บไซต์การผลิตมีการตั้งค่าภาษาเยอรมัน ( de ) การตั้งค่าด้านบนจะยุบไปที่:
'help': {
'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': 'customer.service@productionwebsite.com'
},
ฟังก์ชั่นการตั้งค่า / การเลือกปฏิบัติที่มีมนต์ขลังเช่นไรฟังก์ชั่นการเขียนใหม่ของ JSON มีลักษณะอย่างไร ไม่มาก:
// 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);
};
};
ในการใช้งานของเราซึ่งรวมถึงเว็บไซต์ Angular และ pre-Angular เราเพียงแค่บูตการกำหนดค่าไว้ล่วงหน้าก่อนการเรียกทรัพยากรอื่น ๆ โดยการวาง JSON ภายในการปิด JS ที่ดำเนินการด้วยตนเองรวมถึงฟังก์ชัน prefer () และคุณสมบัติพื้นฐานของชื่อโฮสต์และ รหัสภาษา (และยอมรับคำต่อท้ายเพิ่มเติมใด ๆ ที่คุณอาจต้องการ):
(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]) ] );
ไซต์มุมฉากตอนนี้จะมีหน้าต่างที่ยุบ (ไม่มีคีย์ @ ต่อท้าย) หน้าต่าง app_propsเพื่ออ้างถึง
ไซต์ Angular เป็นขั้นตอน bootstrap / init เพียงแค่คัดลอกวัตถุอุปกรณ์ประกอบฉากที่หล่นลงไปใน $ rootScope และ (ทางเลือก) ทำลายมันจากขอบเขตทั่วโลก / หน้าต่าง
app.constant('props',angular.copy(window.app_props || {})).run( function ($rootScope,props) { $rootScope.props = props; delete window.app_props;} );
จะถูกฉีดเข้าไปในคอนโทรลเลอร์ในภายหลัง:
app.controller('CtrlApp',function($log,props){ ... } );
หรือถูกอ้างถึงจากการโยงในมุมมอง:
<span>{{ props.help.blurb }} {{ props.help.email }}</span>
เตือน? อักขระ @ ไม่ใช่การตั้งชื่อตัวแปร / คีย์ JS / JSON ที่ถูกต้อง แต่ได้รับการยอมรับแล้ว หากเป็นการดีลเลอร์ให้เปลี่ยนการประชุมที่คุณชอบเช่น "__" (ขีดล่างคู่) ตราบใดที่คุณยังยึดติดอยู่
เทคนิคนี้สามารถนำไปใช้กับฝั่งเซิร์ฟเวอร์ซึ่งเชื่อมต่อกับ Java หรือ C # แต่ประสิทธิภาพ / ความกะทัดรัดของคุณอาจแตกต่างกันไป
อีกทางหนึ่งฟังก์ชั่น / การประชุมอาจเป็นส่วนหนึ่งของสคริปต์คอมไพล์ส่วนหน้าของคุณเพื่อให้ JSON เต็มทุกสภาพแวดล้อม / ภาษาทั้งหมดเต็มไปด้วยอารมณ์ไม่เคยส่งผ่านสาย
UPDATE
เราได้พัฒนาการใช้เทคนิคนี้เพื่ออนุญาตให้มีคำต่อท้ายหลายรายการเพื่อหลีกเลี่ยงการถูกบังคับให้ใช้คอลเลกชัน (คุณยังสามารถทำได้ตามที่คุณต้องการ) และเพื่อให้เป็นไปตามลำดับของคำต่อท้ายที่ต้องการ
ตัวอย่าง (ดูที่การทำงานjsFiddle ):
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 (การใช้งานพื้นฐาน) ชอบคีย์ '@dev' ทิ้งกุญแจอื่น ๆ ที่ต่อท้ายทั้งหมด
3ชอบ '@dev' มากกว่า '@fr', ชอบ '@ dev & fr' มากกว่าคนอื่น ๆ ทั้งหมด
4 (เหมือนกับ 3 แต่ชอบ '@fr' มากกว่า '@dev')
5ไม่มีคำต่อท้ายที่ต้องการลดลงคุณสมบัติต่อท้ายทั้งหมด
มันทำได้โดยการให้คะแนนแต่ละคุณสมบัติที่ต่อท้ายและส่งเสริมมูลค่าของคุณสมบัติที่ต่อท้ายกับคุณสมบัติที่ไม่ได้ต่อท้ายเมื่อวนซ้ำคุณสมบัติและค้นหาส่วนต่อท้ายที่มีคะแนนสูงกว่า
ประสิทธิภาพบางอย่างในเวอร์ชันนี้รวมถึงการลบการพึ่งพา JSON ไปเป็นแบบถ่ายสำเนาลึกและเรียกใช้เฉพาะวัตถุที่อยู่รอดในรอบการให้คะแนนที่ระดับความลึก:
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'
ใน'serve'
- ถ้าคุณวางไว้ในการตั้งค่านาฬิกาภายใต้การ'gruntfile'
เป็นtasks: ['ngconstant:development']
- คุณจะไม่ต้องเริ่มต้นใหม่grunt serve
เมื่อคุณปรับปรุงตัวแปรพัฒนาใน gruntfile