以真實項目作為背景,先說一下前端的技術選型:Bootstrap 3.3 + JQuery,標准的企業后台開發框架。當前產品對表單操作提出了優化需求,現在需要一個二級聯動的下拉框組件,通過一個大類去動態篩選目標項,數據從服務端接口獲取。在下圖的例子中:通過選擇領域再選擇開發語言。我選擇引入bootstrap-select這個下拉框組件來進行二次封裝。(展示代碼以偽代碼為主)

先做個原型
1 <div> 2 <div> 3 <select id="domains" multiple></select> 4 </div> 5 <div> 6 <select id="languages" multiple></select> 7 </div> 8 </div>
<script> var domains = null; //元數據 var languages = null; //元數據 $(function () { $('#domains').selectpicker(); //初始化組件 $('#languages').selectpicker(); //初始化組件 $('#domains').on('changed.bs.select', function (e, clickedIndex, isSelected, previousValue) { //篩選聯動的languages //刷新render languages控件的數據 $('#languages').selectpicker('refresh'); });//綁定domains更新事件 $.ajax({ //從服務端獲取domain數據 success: (function (data) { domains = data; //創建options $('#domains').selectpicker('refresh');//刷新控件 }) }) $.ajax({ //從服務端獲取language數據 success: (function (data) { languages = data; //創建options $('#languages').selectpicker('refresh');//刷新控件 }) }) }); /** * * 獲取已選擇的開發語言 * * */ var getSelectedLanguages = function () { var selectOptions = $('#languages').selectpicker().val(); return selectOptions.map(function (val) { //通過options獲取對應language }); } </script>
以上的代碼,其實已經實現了業務上的需求。即便后端用了Thymeleaf作為模板引擎,將以上兩段代碼作為fragment引入需要的頁面中,它已經可以成為業務“組件”。但它真的算是組件級的重用嗎?
1.domains、languages、getSelectedLanguages其實已經在污染了命名空間。
2.它沒有一個生命周期的概念。
3.它的重用方式只是代碼片段的重用。
封裝一下?
<script> var LanguageSelector = { domains: null, languages: null, init: function () { $('#domains').selectpicker(); //初始化組件 $('#languages').selectpicker(); //初始化組件 $('#domains').on('changed.bs.select', function (e, clickedIndex, isSelected, previousValue) { //篩選聯動的languages //刷新render languages控件的數據 $('#languages').selectpicker('refresh'); }); //綁定domains更新事件 }, render: function () { $.ajax({ //從服務端獲取domain數據 success: (function (data) { domains = data; LanguageSelector.renderDomains(); }) }) $.ajax({ //從服務端獲取language數據 success: (function (data) { languages = data; LanguageSelector.renderLanguages(); }) }) }, reset: function () { //重置組件 }, renderDomains: function () { //通過元數據向控件提供數據 }, renderLanguages: function () { //通過元數據向控件提供數據 }, getSelectedLanguages: function () { var selectOptions = $('#languages').selectpicker().val(); return selectOptions.map(function (val) { //通過options獲取對應language }); } }; </script>
LanguageSelector.init();
LanguageSelector.render();
LanguageSelector.reset();
LanguageSelector.getSelectedLanguages();
簡單地進行了封裝,就有組件LanguageSelector。我們能對這個業務組件進行生命周期管理並且將生命周期交給使用者管理。將這個組件以一個“黑盒”的形式發布出去並不是單純的代碼片段復用。
Object or Instance?
使用LanguageSelector object 還是 LanguageSelector's instance?這是實際業務跟開發節奏來考量。在頁面只需有單一控件的情況下,使用object無疑對組件開發以及使用復雜度來說是最優解。但對於需要多個相同控件的情況下,我們只能選擇使用instance的方式,進而擁有進一步的封裝——HTML與JS解耦,更靈活的參數化配置。
總結
前端業務組件的開發,主要是對真實業務的共性的理解和細節與領域的隔離,然后再從現有的技術基礎上開發,再根據不同的業務場景進行功能迭代。
因為我之前一直在做游戲服務端開發,對現代前端的框架沒有做進一步了解和使用,使用的也是當前工作的技術棧。根據工作的點滴,把真實業務剝離后寫下本文以拋磚引玉。
