基於fis3的組件可視化道路

来源:http://www.cnblogs.com/chuaWeb/archive/2016/09/23/component_preview.html
-Advertisement-
Play Games

首先說明一下,即使不熟悉fis3,閱讀文本應該也會有所收穫。 本文以fis-parser-imweb-tplv2插件為模板插件,目的不在於使用哪個模板,而是組件可視化的實現思路,不必擔心。 先說說模板插件 首先說明一下,我們的項目使用的fis3自帶的mod.js做模塊化開發。 fis-parser- ...


  首先說明一下,即使不熟悉fis3,閱讀文本應該也會有所收穫。

  本文以fis-parser-imweb-tplv2插件為模板插件,目的不在於使用哪個模板,而是組件可視化的實現思路,不必擔心。

 

先說說模板插件

  首先說明一下,我們的項目使用的fis3自帶的mod.js做模塊化開發。

  fis-parser-imweb-tplv2插件是同事在imweb待著的時候寫的。模板使用和jsp寫法一致,文件類型為tpl類型

<div class="tips">
    <em>
      <i class="triangle"></i>
      <a class="close" href="javascript:void(0)" title="關閉"></a>
    </em>
    <strong><%=content%></strong>
    <a href=<%=linkUrl%> title=<%=linkTxt%> target="<%=target%>"> <%=linkTxt%> ></a>
</div>

  實現源碼也比較簡單易懂。fis3的配置

    .match(/\/(.+)\.tpl$/, { // js 模版一律用 .tpl 作為尾碼
        isMod: true,
        rExt: 'js',
        id: '$1.tpl',
        url: '$0.tpl',
        moduleId: '$1.tpl',
        release: '$0.tpl', // 發佈的後的文件名,避免和同目錄下的 js 衝突
        parser: fis.plugin('imweb-tplv2')
    })

  最終生成的模塊化的.tpl.js文件如下

define('common/module/rightsideBar/rightsideBar.tpl', function(require, exports, module) {

  return  function (it, opt) {
      it = it || {};
      with(it) {
          var _$out_= [];
          _$out_.push('<div class="right-sidebar"><a href="javascript:void(0)" class="right-sidebar-unregistered-close"></a><a id="rsidereg" href="/register.html?channel=pcgwzc3" class="right-sidebar-unregistered" style="visibility:', (isLogin ?'hidden' :'visible'), '"><span class="right-sidebar-unregistered-content"></span></a><a href="http://wpa.b.qq.com/cgi/wpa.php?ln=2&amp;uin=4008225538" class="right-sidebar-item right-sidebar-item3" target="_blank"><span class="right-sidebar-item1-content"></span></a><a href="javascript:void(0)" class="right-sidebar-item right-sidebar-item2"><span class="right-sidebar-item2-content"></span><div class="right-sidebar-item-tip--code"> <img src="', '/static/pc-dev/common/module/topBar/top_wx.png', '"> <i class="right-sidebar-item-tip--code-tri"><i></i></i></div></a><a href="javascript:void(0)" class="right-sidebar-item right-sidebar-item3"><span class="right-sidebar-item3-content"></span><div class="right-sidebar-item-tip--code"> <img src="', '/static/pc-dev/common/module/topBar/top_app.png', '"> <i class="right-sidebar-item-tip--code-tri"><i></i></i></div></a><a href="javascript:void(0)" id="rjsq" class="right-sidebar-item right-sidebar-item4" target="_blank"><span class="right-sidebar-item4-content"></span></a><a href="javascript:window.scrollTo(0,0)" class="right-sidebar-item right-sidebar-item5" style="display: none;"><span class="right-sidebar-item5-content"></span></a></div>');
        return _$out_.join('');
      }
  }

});

  fis3打包前和打包後的文件結構更改

  

  使用也比較簡單

var tpl_rightsideBar = require('rightsideBar.tpl');
tpl_rightsideBar(opt);//opt是需要傳遞進去的對象。詳細查看rightsideBar.tpl.js的源碼對應的it參數

  當然,我們封裝一個組件不可能直接去使用這個tpl。而是提供一個外部組件函數,然後傳遞參數到這個組件函數中,組件函數不僅渲染頁面(即插入組件dom),還處理相關的邏輯。如上面的rightsideBar.js就是為外部提供一個組件函數。rightsideBar組件比較簡單,只需要傳遞一個父節點即可,不需要其他外部數據來做處理。部分源碼

/**
 * @author chua
 * @date 2016-5-9
 * @description 首頁右側導航欄組件,依賴模版 rightsideBar.tpl,rightsideBar.scss;

 * @實例化:rightsideBar = new rightsideBar(dom, datas);
 * @param dom {Dom} 為頭部組件父級節點,將根據情況append模版,生成頭部節點;
 * @param datas {json} 初始化組件的數據,數據格式如下
 */

/*
 * @require './rightsideBar.scss';
 */
var tpl_rightsideBar = require('./rightsideBar.tpl');
function rightsideBar(cont,opt) {
    this.cont = $(cont);
    this.opt = opt;
    this.init();
};
rightsideBar.prototype.renderHTML = function() {
    //渲染前處理...
    this.cont.empty().append(tpl_rightsideBar(this.opt));
};
rightsideBar.prototype.bindEvent = function() {
    //綁定事件
    this.cont.on('click', '.xxx', function() {
        //處理內容...
    });
};
rightsideBar.prototype.init = function() {
    this.renderHTML();
    this.bindEvent();
}
return rightsideBar;

  rightsideBar.js會被當做模塊來編譯(我們在fis-conf.js中配置的),最終編譯出來後外面會被define包裹。

define('common/module/rightsideBar/rightsideBar', function(require, exports, module) {
    //代碼正文
    ...

  rightsideBar.prototype.init = function() {
      this.renderHTML();
      this.bindEvent();
  }
  
  return rightsideBar;

});

   使用方法也比較簡單

       html:
       <div class="js-rightsideBar"></div>
  
      js:
      var rightsideBar = require('/common/module/rightsideBar/rightsideBar.js');
      new rightsideBar($('.js-rightsideBar'));

 

  而我們的所有組件都放在一個組件文件夾module中,每一個組件一個文件夾(當然頁可以是多個類似的組件放在一起,公用資源),文件夾下麵放置所有這個組件相關的資源。如上圖rightsideBar這個組件。

  那麼如何做組件可視化?有幾個過程是必須要做的

  1.需要遍歷module中所有的組件(即遍歷每一個組件下麵的.js文件,一個組件文件夾下有多個js文件,表明這個組件文件夾下有多個組件,只是為了公用組件資源才放在了同一個組件下),提取出其中的使用樣例(從註釋代碼中提取,所以必須要規定這段demo代碼的規則)。

  2.必須在每一個組件的註釋中寫demo代碼。

  3.將提取的demo代碼寫入指定的組件可視化文件中,隨fis編譯成目標文件(最終在網上打開這個文件就能預覽各個組件的demo了)。

  在上面的基礎上,改如何實現組價的可視化?

 

第一階段的組件可視化

  第一階段的組件可視化使用node+fis的方式實現。原理是在fis編譯之前使用node執行一個腳本,這個腳本完成遍歷組件、提取demo代碼、生成組件可視化目標文件。然後在使用fis編譯打包,啟動服務後在網上訪問即可。之所以第一階段這麼做的原因有兩點:鄙人比較熟悉node但是對fis插件編寫不太熟悉,不敢確定使用fis插件方式是否可行;其次上頭希望能在短期內能看到一定效果。先看一下工程結構目錄,v_components文件夾里包含了所有用來生成組件可視化文件的工具文件,node執行腳本為index.js

  

  工程源文件點擊這裡

  實現步驟:

  1.規定文件註釋代碼中"@example"和"@example end"之間的字元串被認為是組件demo代碼。

/**
   * @author chua
   * @date 2016-5-9
   * @description 首頁右側導航欄組件,依賴模版 rightsideBar.tpl,rightsideBar.scss;基於jQuery和jquery.cookie.js
  
   * @實例化:rightsideBar = new rightsideBar(dom, datas);
   * @param dom {Dom} 為頭部組件父級節點,將根據情況append模版,生成頭部節點;
   * @param datas {json} 初始化組件的數據,數據格式如下
  
   *
   * @example
       html:
       <div class="js-rightsideBar"></div>
  
      js:
       var rightsideBar = require('/common/module/rightsideBar/rightsideBar.js');
      new rightsideBar($('.js-rightsideBar'));
  
      @example end
   */

   其中html:後面跟著的是html代碼,js:後面跟著的是js執行代碼。註意不要出現不符合代碼格式的字元,"html:"、"js:"分別為html代碼段和js代碼段開始的標誌。其後的代碼分別要嚴格按照html和js的格式要求書寫

  

  2.為了簡化和配置更加靈活。我添加了config.json和wrap.html兩個文件來配合主文件index.js文件。

  

  其中index.js文件作用是作為node腳本運行,最終生成最新的v_components.html。v_components.css和v_components.js是給v_component.html使用的,畢竟組件可視化需要一些展示和交互

  config.json的作用是希望能夠配置組件的一些屬性,讓其更靈活,移植性更加。目前只支持一個配置:組件的目錄 (建議使用相對路徑,否則在index.js中可能找不到)

{
    "modulePath": "../common/module/"
}

  warp.html是用來生成v_components.html的模板文件。裡面包含了v_components.html文件需要的樣式文件和腳本文件。這個文件也是根據實際情況配置

<!DOCTYPE html>
<html>
<head>
    <title>組件可視化</title>
    <link rel="import" href="/common/html/meta.html?__inline">
    <link rel="stylesheet" type="text/css" href="/common/css/common.scss" />
    <link rel="stylesheet" type="text/css" href="v_components.css" />
    <script type="text/javascript" src="/common/dep/mod.js" data-loader></script>
    <script type="text/javascript" src="/common/dep/jquery.js" data-loader></script>
    <script type="text/javascript" src="/common/js/common.js" data-loader></script>
    <script type="text/javascript" src="v_components.js" data-loader></script>
</head>
<body>    
</body>
</html>

 

  3.主程式index.js讀取配置文件config.json中配置的組件目錄遍歷每一個組件(裡面的js文件),提取註釋中的demo代碼,以wrap.html為模板,將html代碼插入為節點,將js腳本插入到script節點中。

var fs = require('fs');
...
var writerStream = fs.createWriteStream('v_components.html');
var regs = {
    'wraphtml': /^([\s\S]*<(body)>[\s\S]*)(<\/\2>[\s\S]*)$/,
    //懶惰匹配到第一個*/
    'example': /\/\*\*([\s\S]*)@example[\s\S]*?html:([\s\S]*?)js:([\s\S]*?)@example end([\s|\S]*?)\*\//,//懶惰匹配第一個*/
    ...
};

fs.readFile('config.json', function(err, data){
    ...
    root = obj.modulePath;
    if(datas){
        loopModule();
    }    
})
fs.readFile('wrap.html', function(err, data){                        
    ...
    datas = data.toString();
    if(root){
        loopModule();
    }    
});
//遍歷所有模塊文件
function loopModule(){
    fs.readdir(root, function(err, ffiles){
        ...
        //遍歷所有組件
        ffiles.forEach(function(ffile){
            ...
            fs.readdir(root + ffile, function (err, files){
                ...
                files.forEach(function(file){//處理每一個模塊文件中的模塊並找到組件主文件(js文件)
                    if(regs.jsfile.test(file)){
                        ...
                        fs.readFile(pa, function(err, data){
                            ...
                            if(match = data.toString().match(regs.example)){//匹配demo代碼段
                                //截取相關信息並添加相關節點
                                ...
                                innerRightT += '<div class="right-side-top-item' + (count == 0? ' visible': '') + '" data-mod="'+ file +'">' + match[2] + '</div>';
                                innerJs += match[3] + ";";//js腳本都放在innerJs中
                                count++;
                            }
                            
                            if(subModLeng == 0){//處理完所有子模塊才能說明處理完了整個模塊文件夾
                                unDomoduleLength--;
                            }                            
                            if(unDomoduleLength == 0){//處理完所有的模塊後,最後寫入文件
                                var innerBody = warpText(innerLeftWrap, innerLeft) 
                                    + warpText(innerRightWrap, warpText(innerRightTWrap, innerRightT) + warpText(innerRightBWrap, innerRightB))
                                    + warpText(jsWrap, innerJs);

                                //使用utf8編碼寫入數據
                                writerStream.write(datas.replace(regs.wraphtml, '$1' + innerBody + '$3'), 'UTF8');
                                //標記文件結尾
                                writerStream.end();
                            }                                
                        });
                    }
                    
                })
            });
        })
    })
}
//用數組wrapArr包裹inner並返回包裹結果
function warpText(wrapArr, inner){...}
//將str字元串轉換成HTML格式
function transToHtml(str){...}
View Code

  最終在v_components目錄下執行:node index

  生成v_components.html文件

  在pc目錄下fis3編譯:fis3 release dev

  在和pc同級的目錄下麵生成pc-dev文件夾

  在pc-dev目錄下執行:node server

  打開瀏覽器訪問:http://localhost:3000/v_components/v_components.html

  

  左側是所有的組件的列表,點擊之能看到每一個組件的展示效果。我很醜,但是我很有內涵

 

第二階段的組件可視化——fis3插件

  之前說過要將組件可視化做成fis插件,隨fis編譯一起編譯打包,不用在手動執行node生成相應文件。主要面臨的問題是:如何讓組件更加通用?這裡面幾個需要考慮的點

  1.如何從組件代碼的註釋中提取出demo代碼段。

  這裡我使用了下麵的正則來匹配

/\/\*\*([\s\S]*)@example[\s\S]*?(html:([\s\S]*?)js:([\s\S]*?))@example end([\s|\S]*?)\*\//,//懶惰匹配第一個*/

  匹配文件註釋中‘@example’和‘@example end’之間的代碼。如

/**
   * @example
       html:
       <div class="js-rightsideBar"></div>
  
      js:
       var rightsideBar = require('/common/module/rightsideBar/rightsideBar.js');
      new rightsideBar($('.js-rightsideBar'));
  
      @example end
   */

  這個部分本來想做成可以配置的,但是覺得沒有太大的意義,就預設使用這個正則來匹配組件中的demo代碼。

 

  2.插件需要那些參數,是的插件更加靈活

  下麵是最終確定下來的參數(路徑都配置絕對路徑)

            wrap: '/v_components/wrap.html',//組件可視化原型文件,用來包裹組件可視化代碼
            url: '/v_components.html', //目標文件
            COMPath: '/common/module',//組件集合目錄
            moduleListInstead: 'instead of modules',//使用模塊列表節點替換當前文本
            moduleViewInstead: 'instead of view htmls',//使用模塊視圖列表節點替換當前文本
            moduleCommentsInstead: 'instead of commnets',//使用模塊註釋列表節點替換當前文本
            moduleJsInstead: 'instead of js'//使用js腳本節點替換當前文本

  當前文件的目錄結構

  

  其中wrap對應的文件wrap.html作用非常重要。後面四個參數moduleXXXInstead對應的值必須在wrap.html中能夠找到,然後使用插件拼裝好的數據來替換他。wrap.html源碼如下

<!DOCTYPE html>
<html>
<head>
    <title>組件可視化</title>
    ...
</head>
<body>    
<div class="left-side">instead of modules</div>
<div class="right-side">
    <div class="right-side-top">instead of view htmls</div>
    <div class="right-side-bottom">instead of commnets</div>
</div>
...
<script type="text/javascript">instead of js</script>
</body>
</html>

   最終執行fis後上面黑色粗體文字全部被替換

<!DOCTYPE html>
<html>
<head>
    <title>組件可視化</title>
    ...
</head>
<body>    
<div class="left-side"><div data-mod="financialsBar">financialsBar</div><div data-mod="financialsSmlBar">financialsSmlBar</div><div data-mod="rightsideBar">rightsideBar</div></div>
<div class="right-side">
    <div class="right-side-top"><div data-mod="financialsBar">
      <!-- 新手 -->
      <div class="js-financialsBar1"></div>
      <!-- 活期 -->
      <div class="js-financialsBar2"></div>
      <!-- 定期 -->
      <div class="js-financialsBar3"></div>
  
      </div><div data-mod="financialsSmlBar">
      <!-- 定期理財 -->
      <div class="js-financialsSmlBar1"></div>
      <!-- 債權轉讓 -->
      <div class="js-financialsSmlBar2"></div>
      </div><div data-mod="rightsideBar">
       <div class="js-rightsideBar"></div>
  
      </div></div>
    <div class="right-side-bottom"><div data-mod="financialsBar"><div >樣例:<div>html:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;新手&nbsp;--&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div&nbsp;class="js-financialsBar1"&gt;&lt;/div&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!--&nbsp;活期&nbsp;--&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div&nbsp;class="js-financialsBar2"&gt;&lt;/div......</div>
</div>
...
<script type="text/javascript">var financialsBar = require('common/module/financialsBar/financialsBar');
      new financialsBar($('.js-financialsBar1'), {
          "type": "novice",
          "bdid": 1,
          "name": "農優寶A1231213",
          "title": "新手專享",
          "term": 1,
          "annualrate": 0.09,
          "interestRaise": 0.005,
          "surplusAmount": 30000,
          "projectScale": 50000,
          "status": "RZZ",
          "packStatus": "QGZ",
          "releaseDate": 425132121,
          "nowDate": 45641231321,
          "surplusBuyCount":1,
          'productType': 'NYB',
          'delayTime': 0
      });
      ...
    </script>
</body>
</html>
View Code

   來自相同的組件的DOM節點的屬性值data-mod相同

  fis-conf.js的配置片段

    .match('::package', {
        prepackager: fis.plugin('component-preview',{
            wrap: '/v_components/wrap.html',//組件可視化原型文件,用來包裹組件可視化代碼
            url: '/v_components.html', //目標文件
            COMPath: '/common/module',//組件集合目錄
            moduleListInstead: 'instead of modules',//使用模塊列表節點替換當前文本
            moduleViewInstead: 'instead of view htmls',//使用模塊視圖列表節點替換當前文本
            moduleCommentsInstead: 'instead of commnets',//使用模塊註釋列表節點替換當前文本
            moduleJsInstead: 'instead of js'//使用js腳本節點替換當前文本
        })
    })

  更詳細的demo查看fis3_component_preview_demo

  最終效果同第一階段的組件可視化效果一樣     

 

  實現原理:

  

  完整的插件源碼查看fis3-prepackager-component-preview

   

  如果覺得本文不錯,請點擊右下方【推薦】!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 效果圖: 網頁佈局 <p>操作成功</p> <strong>5</strong><span>秒後回到主頁</span><a href="javascript:history.back();">返回</a> 任務: 1.打開網頁後,如果不做任何操作則返回到一個新的頁面 var num=document ...
  • 效果圖: 任務: 1. 滑鼠移到不同行上時背景色改為色值為 #f2f2f2,移開滑鼠時則恢復為原背景色 #fff var tr=document.getElementsByTagName("tr"); for(var i= 0;i<tr.length;i++) { bgcChange(tr[i]); ...
  • 一、html5新特性 常用語義標簽:nav footer header section mark 功能標簽 video audio iframe canvas(畫布和繪圖功能) input新type:url/number/range/Date(date, month, week, time等)/se ...
  • 這是要實現的效果圖: 一.HTML頁面佈局 <!-- HTML頁面佈局 --><ul class="tab_menu"> <li class="selected">房產</li> <li>家居</li> <li>二手房</li></ul><div class="tab_box"> <div> 275 ...
  • <!DOCTYPE>到底是個神馬? 前兩天和朋友談到<!DOCTYPE>,今天將網上學習到的資料在這裡整理一下 因為HTML5的風靡人們慢慢的弱化了對<!DOCTYPE>的理解,但是現在還是有很多的面試官在問這個問題,所以還是有必要對其瞭解一下,以便以後有些許談資。 1.<!DOCTYPE>有神馬作 ...
  • [1]原理介紹 [2]數字加減 [3]元素尺寸 [4]內容滾動 ...
  • 這兩天整個技術圈都炸鍋了,微信小程式(微信應用號)發佈內測,首批200家收到邀請,但是沒受邀請的同學,也不用擔心,下麵介紹一下解決方法。 首先需要下載ide,昨天只需要下載0.9版本的編輯器並替換文件就行了,但是可能微信那邊修複了,導致不可用。現在我們要準備兩個版本:0.7盒0.9的版本,我測試過了 ...
  • [1]原理簡介 [2]範圍圈定 [3]大小改變 [4]代碼優化 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...