基于fis3的组件可视化道路

chua1989 chua1989     2022-08-06     762

关键词:

  首先说明一下,即使不熟悉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‘: /^([sS]*<(body)>[sS]*)(</2>[sS]*)$/,
    //懒惰匹配到第一个*/
    ‘example‘: //**([sS]*)@example[sS]*?html:([sS]*?)js:([sS]*?)@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代码段。

  这里我使用了下面的正则来匹配

//**([sS]*)@example[sS]*?(html:([sS]*?)js:([sS]*?))@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

   

  如果觉得本文不错,请点击右下方【推荐】!

基于react-grid-layout实现可视化拖拽

参考技术A做前端的小伙伴们可能会经常遇到做一个自定义dashboard这样的需求。那么什么是自定义dashboard呢?自定义dashboard其实就是一个自定义面板,用户能够在面板上自由的拖拽,新增,删除组件。组件可以是各种echarts图形,... 查看详情

一行代码完成定时任务调度,基于quartz的ui可视化操作组件gzy.quartz.mui

...过第一个版本,有兴趣的可以去看看: NETCore基于Quartz的UI可视化操作组件GZY.Quartz.MUI简介GitHub开源地址:l2999019/GZY.Quartz.MUI:基于Quartz的轻量级,注入化的UI组件 总而言之,这个组件主要想做的就是:像swaggerUI一样,项目入侵量小,仅需要... 查看详情

又一款基于vue的数据可视化组件库,github上star超1.4k,太酷炫

参考技术A组件库名称:DataV项目地址:https://github.com/DataV-Team/DataV光看截图就知道太酷炫了,而且根本不需要担心拿在手里会不会用,官方的文档也是非常详细非常多的组件可以选择,但是相对于收费版的阿里云datav还是很不错... 查看详情

在基于vue的组件库内使用storybook搭建组件使用文档

StorybookforVue介绍:storybook是一个可视化组件展示平台,该工具可让开发者独立的创建可以交互展示的UI组件,能有组织和高效地构建UI组件。官网安装:npminstall@storybook/vue-S修改package.json,配置一个scripts。{"scripts":{"storybook":"start-sto... 查看详情

fis3+vue+pdf.js制作预览pdf文件或其他

...为这对于我来说应该是一个好的开始,以此励志在技术的道路上越走越远。  看过了多多少少的技术博客,给自己带来了很多技术上的收获,也因此在想什么时候自己也可以赠人玫瑰,手留余香呢?终于时候到了...哈哈  首... 查看详情

dap可视化组件升级开发说明

DAP数据分析平台是公司数据治理分析方案的重要部分,通过结合MDM主数据平台和ESB企业服务总线在进行企业数据治理、数仓建设、数据分析方面提供全面的支持,通过ESB流程实现数据传输、构建数仓,实现了业务数据... 查看详情

基于php语言laravel+layui数据可视化平台(代码片段)

项目介绍一款PHP语言基于Laravel5.8、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,框架自... 查看详情

基于echarts+百度地图+three.js的数据可视化系统(代码片段)

上周重构项目数据统计部分写了几篇echarts相关的文章,重构的后台前端框架改用Vue,关于Vue中引用Echarts及可能遇到的问题的文章如下所示:VUE中使用Echarts图表VUE父组件异步获取数据,子组件接收的值为空VUE渲染e... 查看详情

使用navicate可视化组件编写图表之间关系

一使用navicate1.选择模型2.空白区域,右键新建表3.设计完各个表中的字段,设计表之间的关系设计好外键,这是会在两个表之间存在一条关系线4.设计关系端,那是1,那是n的关系基于xxx表,设计为1端,... 查看详情

基于php语言thinkphp6+layui数据可视化平台(代码片段)

项目介绍一款PHP语言基于ThinkPhp6.x、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,框架自... 查看详情

Leaflet - 基于两个标记实时绘制道路路径

】Leaflet-基于两个标记实时绘制道路路径【英文标题】:Leaflet-Drawroadpathinreal-timebasedontwomarker【发布时间】:2016-06-2913:22:13【问题描述】:这是基于两个标记绘制道路路径的应用示例抱歉,我无法搜索创建此教程的教程,因为我... 查看详情

基于车路协同技术的智慧高速系统架构分析

...方的数据并进行综合研判,为各方提供高速公路数字可视化、交通状况安全预警、协调联动、应急指挥、大数据分析决策支持等服务。2.2 查看详情

基于php语言laravel9+layui数据可视化平台(代码片段)

项目介绍一款PHP语言基于Laravel9.x、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,框架自... 查看详情

基于python/flask框架的双色球数据采集(爬虫)及大数据可视化平台设计与实现

基于Python/Flask框架的双色球数据采集及可视化平台项目简介项目说明项目技术项目演示项目获取项目简介前几天看到,有位老哥中了双色球,往大街上一摊。神经兮兮的说:“终于不用上班了”。我也想神经兮兮的说... 查看详情

qtquick和widgets的对比

概念:QtQuick:QML类型和功能的标准库QtQuick模块:提供可视化组件,模型视图支持,动画框架以及用于构建用户界面的更多功能。QtQuickControls:基于QtQuick的可重用UI组件库。QtQuick1基于GraphicsViewQtQuick2基于SceneGraph的技术,独立的渲染... 查看详情

matlab点云处理(二十八):基于格网法与平面拟合的道路点云与非道路点云分割

...组成。1算法概述算法原理比较简单,主要分为两部分:基于格网法提取非道路点云和初始道路点云基于平面拟合提取道路点云算法流程如下:对输入点云在xoy 查看详情

datav

...m/DataV-Team/DataV文档地址贴几个Demo图DataV是一个基于Vue数据可视化组件库,类阿里DataV,提供SVG的边框及装饰,图表,飞线图等组件,简单易用。主要的组件类型SVG的边框,主要用于提升页面效果,一个边框组件仅几k到十几k,后... 查看详情

基于 Web 的 json 编辑器组件 [关闭]

】基于Web的json编辑器组件[关闭]【英文标题】:web-basedjsoneditorcomponent[closed]【发布时间】:2012-01-0721:36:42【问题描述】:我正在寻找一个允许以某种可视方式(树/网格)编辑json文档的HTML/javascript组件。商业组件也是一种选择。... 查看详情