Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 好男人视频社区精品免费,亚洲天堂三区,欧美做爰猛烈床戏大尺度

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          若依如何在頁面中添加水印,添加水印方法

          若依如何在頁面中添加水印,添加水印方法

          常在工作實踐中,可能會遇到添加水印的情況,如何在頁面中添加水印呢?如下圖的效果


          實現思路可以利用Watermark實現添加水印的功能

          Watermark通常是指嵌入在頁面中的半透明圖像或文字,用于標識頁面所有權或版權信息。在若依Ruoyi-Vue中集成Watermark,可以采用以下思路:

          1. 選擇合適的Watermark庫:目前流行的Watermark庫包括watermark-dom、html2canvas等。
          2. 在Vue組件中引入并使用Watermark庫:根據項目需求,選擇合適的Watermark庫并將其引入Vue組件中。
          3. 配置Watermark參數:設置Watermark的文字內容、位置、大小、顏色等參數。
          4. 動態生成Watermark圖像:利用Watermark庫提供的功能,動態生成Watermark圖像。
          5. 將Watermark圖像添加到頁面中:將生成的Watermark圖像添加到頁面DOM結構中,使其覆蓋在頁面內容之上。

          實現步驟

          引入Watermark庫

          首先,需要在項目中引入Watermark庫。本文推薦使用watermark-dom庫,該庫使用簡單,易于擴展。可以使用以下命令安裝watermark-dom庫:

          npm install watermark-dom

          或者在package.json文件dependencies節點增加watermark-dom依賴。

          "watermark-dom": "2.3.0"

          2. 配置Watermark參數

          在Vue組件中,引入并配置watermark-dom庫。例如,在App.vue組件中可以添加如下代碼

           
                  watermark_id: 'wm_div_id',          //水印總體的id
                  watermark_prefix: 'mask_div_id',    //小水印的id前綴
                  watermark_txt:"測試水印",             //水印的內容
                  watermark_x:20,                     //水印起始位置x軸坐標
                  watermark_y:20,                     //水印起始位置Y軸坐標
                  watermark_rows:0,                   //水印行數
                  watermark_cols:0,                   //水印列數
                  watermark_x_space:100,              //水印x軸間隔
                  watermark_y_space:50,               //水印y軸間隔
                  watermark_font:'微軟雅黑',           //水印字體
                  watermark_color:'black',            //水印字體顏色
                  watermark_fontsize:'18px',          //水印字體大小
                  watermark_alpha:0.15,               //水印透明度,要求設置在大于等于0.005
                  watermark_width:100,                //水印寬度
                  watermark_height:100,               //水印長度
                  watermark_angle:15,                 //水印傾斜度數
                  watermark_parent_width:0,      //水印的總體寬度(默認值:body的scrollWidth和clientWidth的較大值)
                  watermark_parent_height:0,     //水印的總體高度(默認值:body的scrollHeight和clientHeight的較大值)
                  watermark_parent_node:null     //水印插件掛載的父元素element,不輸入則默認掛在body上

          動態生成Watermark圖像

          在AppMain.vue文件引入水印模塊,示例如下:如果想要在單一頁面使用,也可以在自己想要的頁面中添加

          家好, 我是徐小夕, 之前一直在分享可視化低代碼的一些實踐, 圍繞 H5-Dooring 零代碼搭建平臺也輸出了很多技術文章, 最近2.7.0 版本也順利迭代完成, 這里詳細分享一下 H5-Dooring 無代碼搭建平臺技術方案.

          • H5-Dooring 開源版本
          • 可視化低代碼技術集合
          • H5-Dooring在線體驗

          Dooring無代碼產品技術演進

          兩年前我設計了H5-Dooring的第一個開源版本, 之后陸陸續續迭代了兩年, github star已達到6.5k+, 也找到了很多志同道合的小伙伴, 一起研發Dooring系的搭建產品, 如:

          • h5-dooring | 可視化搭建解決方案
          • mitu-editor | 開源圖片編輯器
          • v6.dooring | 可視化大屏搭建平臺
          • dooringx | 可視化搭建框架

          image.png

          從技術設計和產品規劃上, 這幾年也總結摸索出了一些經驗和實踐, 接下來我就和大家一起分享一下H5-Dooring 的技術架構設計與演進.

          image.png

          底層搭建協議標準化

          我們都知道任何低代碼或者零代碼搭建產品都非常注重底層搭建協議, 這些產品通常會設計一套向上兼容且可擴展的DSL結構, 來實現頁面元件的標準化配置, 并支持元件的向上擴展.

          image.png

          上面這張圖是我在設計 V6.Dooring 可視化大屏搭建平臺的編輯器架構圖, 這里的底層搭建協議可以認為是 搭建基礎, 也就是我們常說的 “經濟基礎決定上層建筑”.

          在設計H5-Dooring 搭建平臺前, 我也參考了很多標準化軟件數據協議, 給我啟發最大的就是 ODATA, 它是微軟于2007年發起的開放協議, 主要由以下幾部分組成:

          • 「核心協議」: 主要定義了開放數據協議的核心語義和行為

          image.png

          • 「URL規范」: 主要定義了一系列推薦(非強制)采用的構建用于訪問OData服務中的數據和模型的URL的規則

          image.png

          • 「通用格式定義語言(CSDL)」: 它定義了OData服務的「EDM」模型的一種XML格式的表現形式

          image.png

          • 「擴展的巴科斯范式(ABNF)」: 定義了構建OData請求和響應URL「巴科斯范式」

          image.png

          為了讓可視化搭建平臺的組件數據標準化且可擴展, 這里我分享一下H5-DooringSchema設計.

          image.png

          Schema 分兩部分:

          • editData 組件可編輯屬性的數組
          • config 組件真正消費的數據

          editData 詳解

          editData 是 組件屬性可編輯項的數組, 每一項里面包含了如下字段:

          • key 屬性名
          • name: 屬性名的中文顯示
          • type: 屬性的可編輯類型
          • isCrop(可選)
          • cropRate(可選)
          • range(type 為'Radio'或'Select'時的選項數組)
          • 后期可能會擴展(詳細結構可參考Dooring 開源版本)

          keyname 都可以按照組件屬性的語義來定, 這里值得一提的是 type. 不同屬性的值類型不同, 所以我們編輯項的 type 也不同, 所有的類型如下:

          • Upload 上傳組件
          • Text 文本框
          • RichText 富文本
          • TextArea 多行文本
          • Number 數字輸入框
          • DataList 列表編輯器
          • FileList 文件列表編輯器
          • InteractionData 交互設置
          • Color 顏色面板
          • MutiText 多文本
          • Select 選擇下拉框
          • Radio 單選框
          • Switch 開關切換
          • CardPicker 卡片面板
          • Table 表格編輯器
          • Pos 坐標編輯器
          • FormItems 表單設計器

          更詳細的介紹可以訪問 dooring 開發文檔

          config 詳解

          config 本質上是一個對象, 也就是組件所能暴露出來的屬性集合, 和 editData 數組每一項的key 一致, 如下:

          {
              cpName: 'Header',
              logoText: '',
              fontSize: 20,
              color: 'rgba(47,84,235,1)',
              height: 60,
              fixTop: false,
              menuList: [
                {
                  id: '1',
                  title: '首頁',
                  link: '/'
                },
                {
                  id: '2',
                  title: '產品介紹',
                  link: '/'
                },
              ]
            }
          

          我們通過以上的設計規范, 就可以輕松制作一個可實時編輯的低代碼組件:

          image.png

          可以在Dooring官方文檔體驗: 低代碼組件案例

          搭建模式多元化

          最開始設計H5-Dooring的時候為了最大限度的降低用戶的搭建成本, 我采用了智能網格布局的方式來搭建頁面, 用戶只需要在二維空間像搭積木一樣選擇適合的組件就可以快速的制作頁面:

          這樣雖然可以降低用戶的搭建難度, 并能滿足一部分受眾的搭建需求, 比如說簡單的官網, 活動頁面制作,下面是一個搭建的比較有代表性的例子:

          但是對于平臺方, 為了滿足更多場景的頁面深度制作, 就必須提供不同場景不同行業的組件物料, 這將對研發帶來巨大的壓力(雖然也一直在添加新組件).

          另一方面, 目前上很多H5活動制作平臺基本上都采用的自由布局的模式搭建, 好處就是可以最大限度的還原設計稿, 滿足更靈活的搭建需求, 缺點就是使用成本比網格布局的模式要高, 還會涉及圖層的概念.

          當然綜合評估下來, 確實很有必要給一部分用戶提供自由布局的模式, 所以在技術層我設計同時兼容網格布局自由布局的搭建方案. 當用戶在搭建時, 可以輕松選擇自己適合的搭建模式:

          image.png

          同時為了滿足自由布局下組件的層級管理, 我又設計了圖層管理面板和圖層操作, 來快速的管理頁面元素, 當然圖層管理面板網格布局 也同樣有一定積極作用, 比如快捷的操作組件.

          可擴展的插件系統

          在前面提到了可視化搭建平臺的統一搭建協議搭建模式, 在這兩個核心要素完成之后, 我們就很容易的去設計我們的插件系統.

          image.png

          從插件系統的本質來看, 核心價值是對頁面操作的整個周期里為頁面賦能, 而頁面的本質是數據(也就是DSL集).

          image.png

          所以只要有標準的數據規范, 我們自定義的插件就可以很輕松的來對頁面進行賦能, 類似于各種技術里面的中間件. 下面是一個例子:

          {
              "pageConfig": {
                  "allowOverlap": "freedom",
                  "isLogin": false,
                  "bgColor": "rgba(16,20,29,1)",
                  "bgSize": "100%",
                  "title": "H5-Dooring官網"
              },
              "tpl": [
                  {
                      "id": "276059",
                      "item": {
                          "category": "base",
                          "config": {
                              "cpName": "XButton",
                              "id": "",
                              "bgColor": "rgba(22,40,212,1)",
                              "width": 190,
                              "marginTop": 0,
                              "round": 16,
                              "text": "按鈕",
                              "fontSize": 15,
                              "color": "rgba(255,255,255,1)",
                              "animation": "none",
                              "animationTurn": 1,
                              "delay": 0,
                              "interaction": {
                                  "type": "link",
                                  "title": "",
                                  "params": "",
                                  "content": "",
                                  "height": 300,
                                  "width": 300,
                                  "okText": "",
                                  "cancelText": "",
                                  "onOk": "",
                                  "btnColor": "rgba(20,54,226,100)"
                              }
                          },
                          "h": 23,
                          "type": "XButton"
                      },
                      "point": {
                          "w": 24,
                          "h": 23,
                          "x": 0,
                          "y": 0,
                          "i": "276059",
                          "moved": false,
                          "static": false,
                          "isBounded": true
                      },
                      "status": "inToCanvas"
                  },
                  {
                      "id": "260487",
                      "item": {
                          "category": "base",
                          "config": {
                              "cpName": "LongText",
                              "id": "",
                              "text": "我是長文本有一段故事,dooring可視化編輯器無限可能,趕快來體驗吧,騷年們,奧利給~",
                              "color": "rgba(60,60,60,1)",
                              "fontSize": 14,
                              "indent": 0,
                              "lineHeight": 1.8,
                              "textAlign": "left",
                              "bgColor": "rgba(255,255,255,0)",
                              "padding": 0,
                              "radius": 0
                          },
                          "h": 36,
                          "type": "LongText"
                      },
                      "point": {
                          "w": 24,
                          "h": 36,
                          "x": 0,
                          "y": 23,
                          "i": "260487",
                          "moved": false,
                          "static": false,
                          "isBounded": true
                      },
                      "status": "inToCanvas"
                  }
              ]
          }
          

          上面是H5-Dooring生成的一個頁面DSL結構, 如果我們要對頁面元素進行統計分析, 或者實現出碼, 國際化, PSD解析轉化等功能, 只需要對數據結構進行分析和處理即可.

          image.png

          所以說在H5-Dooring平臺實現自定義的插件還是非常容易的, 也是低代碼或者無代碼需要重點規劃的一個環節.

          可擴展的組件編輯器

          H5-Dooring平臺的組件編輯器主要是對組件屬性進行編輯,比如:

          • 基本樣式
          • 交互設置
          • 動畫設置

          當然還有全局的數據源配置. 如下:

          image.png

          同時由于我們的組件數據協議高度統一, 所以如果想擴展屬性配置, 也非常容易, 我們只需要按照數據協議添加屬性即可:

          image.png

          同理, 「v6.dooring」 也采用相似的架構, 所以我們可以輕松擴展組件的屬性:

          image.png

          有關可視化大屏搭建平臺的技術實踐可以參考我的另一篇文章 從零設計可視化大屏搭建引擎

          多端搭建支持

          image.png

          由于Dooring的技術棧采用React, 并實現了標準的數據協議層, 所以我們可以利用類似 Taro 等跨平臺框架實現多端搭建, 對于我們常用的媒介如移動端, Pad和PC端, 目前編輯器也提供了快捷的切換模式:

          image.png

          所以我們可以輕松的實現不同端的搭建, 實現原理本質上是通過切換畫布大小, 并同比例更新元素的計量衡.

          圖層管理, 讓設計更高效

          圖層管理模塊也是在Dooring支持了自由布局之后才上線的功能. 因為我們頁面中組件的數據結構中包含統一的物理信息:

          • 層級
          • 可見性
          • 類別
          • 大小顏色等外觀
          • 事件 / 交互 / 動畫

          image.png

          所以我們只需要分析頁面的組件集合, 就可以輕松的渲染出頁面中的元素圖層信息:

          image.png

          有了圖層的概念我們其實可以做很多有用的事情, 比如:

          • 多選組件
          • 編輯組件
          • 刪除組件
          • 鎖定組件

          后面 Dooring 也會基于圖層能力迭代更多提高用戶搭建銷效率的功能.

          低代碼組件 & 模版生態

          Dooring 的迭代中花了大部分精力在優化用戶搭建體驗和協議標準化上, 對于組件物料的豐富上, 我也做了一些設計, 最近也發布了一套低代碼組件庫的原型:

          image.png

          我們可以輕松的像寫 React 組件一樣來實現低代碼組件, 并支持線上實時編輯, 一個基本的例子如下:

          import styles from './index.less';
          import React, { memo, useState } from 'react';
          import { MenuOutlined } from '@ant-design/icons';
          import { IHeaderConfig } from './schema';
          
          const Header=memo((props: IHeaderConfig)=> {
            const {
              cpName,
              bgColor,
              logo,
              logoText,
              fontSize,
              color,
              showMenuBtn,
              menuColor,
              height,
            }=props;
            const [showMenu, setShowMenu]=useState(false);
            const toggleMenu=()=> {
              setShowMenu(!showMenu);
            };
            return (
              <header
                className={styles.header}
                style={{ backgroundColor: bgColor, height: height + 'px' }}
              >
                <div className={styles.logo}>
                  <img src={logo && logo[0] && logo[0].url} alt={logoText} />
                </div>
                <div className={styles.title} style={{ fontSize, color }}>
                  {logoText}
                </div>
                {showMenuBtn && (
                  <>
                    <div
                      className={styles.menuIconWrap}
                      onClick={toggleMenu}
                      style={{ color: menuColor, borderColor: menuColor }}
                    >
                      <MenuOutlined />
                    </div>
                  </>
                )}
              </header>
            );
          });
          
          export default Header;

          通過這種標準化的方式, 我們可以給 Dooring 平臺提供更為豐富的組件物料.

          除了基礎物料組件之外, 為了從更大粒度提高用戶搭建的效率, 我提供了模版功能, 我們可以把重復的區塊可復用的頁面保存為模版:

          image.png

          我們可以在編輯器頁面輕松將頁面保存為模版, 并自動生成海報封面:

          image.png

          基于網頁生成封面的方式也很簡單, 我這里采用的是 dom-to-image 這個庫, 當然搭建也可以使用html2canvas.

          表單設計器 & 數據收集分析能力

          表單編輯器的實現思路我之前也寫過一些分享, 這里和大家再介紹一下核心的一些思路.

          動態表單開發的一般思路

          「1. 靜態化配置列表」

          靜態化配置列表是最傳統的表單配置方式之一,基本思路就是利用母表來生成配置項,進而實現表單配置。類似于以下方式:

          早期的網站配置就是類似于這種呢方案實現的,比如說我們要定制網站的主色,網站某些組件是否可見,是一種比較簡單的方式。但是缺點是每增加一個配置屬性,都要開發人員重新編寫一個字段配置代碼,這種方式在表單開發中非常不靈活,而且對代碼層有強依賴性,所以只適合做小型配置系統。比如個人網站,簡單的自定義表單。

          「2. 基于json schema的動態表單配置」

          基于「json schema」的動態表單配置有兩種實現方案, 一種就是支持在線修改json文件從而實現定制化,另一種就是完全無代碼操作,但是前提都需要提供一套通用的表單模版。類似于如下案例:

          此種方案可以實現基本的表單自治。也是本文主要實現的方案。至于在線編寫json文件的方案。筆者之前也也過成熟的方案,具體可以參考:基于jsoneditor二次封裝一個可實時預覽的json編輯器組件(react版)

          「3. 支持在線coding的混合式表單設計」 支持「在線編程」的混合式表單設計方案是終極方案,也是目前流行的無代碼化平臺的思想之一。一方面它提供了基于「json schema」的動態表單配置, 對于一些強定制的,需要在線設計組件方案的模式,采用在線編程,實時打包成動態組件的方式,最后根據平臺的組件約定來實現組件庫的方式。如下圖所示:

          在線代碼編輯可以使用「react-codemirror2」或者 「react-monaco-editor」插件來實現。至于在線打包,我們用「nodejs」完全可以實現,筆者在做「Dooring」項目的在線下載代碼時就用到了該方案,感興趣的可以了解一下。

          可視化領域中的表單引擎

          可視化領域一方面強調的是圖形(可視化)的設計,一方面是動態表單。比如說我們想傻瓜式的改變一張圖的數據,屬性,交互等,我們需要通過表單這一橋梁來實現:

          所以我們需要設計一款適合公司產品的“表單引擎”,來動態根據圖形組件的類型渲染不同表單配置。這塊思想也是表單設計器要解決的問題之一。在下面的文章中我們會詳細介紹實現過程。

          從零實現一款動態表單設計器

          在實現表單設計器之前,我們先來整理一下思路和需求。在筆者的最初草圖中,它長這樣:

          從草圖中我們可以提取到如下任務信息:

          • 定義一套表單組件庫
          • 確定表單全局屬性配置
          • 實現表單操作curd(增刪查改)

          我們這里總結了幾個常用的表單組件如下:

          • 單選框
          • 復選框
          • 單行文本
          • 多行文本
          • 下拉框
          • 文件上傳
          • 日期框
          • 數值輸入框

          以上這些基本滿足我們的日常開發需求,其次我們還可以開發數據源表單組件,列表組件,比如dooring實現的那樣:


          類似的還有顏色面板這些,我們可以更具業務需求自行定制。

          在完成表單組件庫之后,我們就需要根據配置項動態渲染了。也有兩種實現思路,一種就是類似于多條件判斷,如下:

          {
            item.type==='Number' &&
            <Form.Item label={item.name} name={item.key}>
              <InputNumber min={1} max={item.range && item.range[1]} step={item.step} />
            </Form.Item>
          }
          {
            item.type==='Text' &&
            <Form.Item label={item.name} name={item.key}>
              <Input />
            </Form.Item>
          }
          {
            item.type==='TextArea' &&
            <Form.Item label={item.name} name={item.key}>
              <TextArea rows={4} />
            </Form.Item>
          }
          

          這樣做雖然可行,也有很多成熟系統采用該方案,但是一旦表單變多,比如一個頁面有幾十個甚至上百個表單項,那么我們將渲染「m」 *** n**次(m為表單組件類型數,n為配置項個數)。另一種方式筆者看來是比較優雅的,可以將復雜度降低到O(n),也就是筆者常用的對象法。思路大至如下:「將表單組件的類型作為對象的屬性,屬性值為對應的表單組件,這樣遍歷的時候只需要對應上對象的具體類型即可。」 代碼如下:

          // 維護表單控件, 提高form渲染性能
          const BaseForm={
              "Text": (props)=> {
                  const { label, placeholder, onChange }=props
                  return <Cell title={label}>
                              <Input type="text" placeholder={placeholder} onChange={onChange} /> 
                         </Cell>
              },
              "Number": (props)=> {
                  const { label, placeholder, onChange }=props
                  return <Cell title={label}>
                              <Input type="number" placeholder={placeholder} onChange={onChange} /> 
                         </Cell>
              }
          }
          
          //  動態渲染表單
          {
              formData.map((item, i)=> {
                  let FormItem=BaseForm[item.type]
                  return <div className={styles.formItem} key={i}>
                            <FormItem {...item} />
                        </div>
              })
          }
          

          是不是很優雅呢?后期我們只需要在「BaseForm」里維護表單組件即可,而且還可以基于「BaseForm」對表單進行包裝,實現動態刪除,編輯等功能。如下:

          image.png

          包裝后的代碼如下:

          <div>
            <div className={styles.disClick}><FormItem {...item} /></div>
            <div className={styles.operationWrap}>
                <span onClick={handleEditItem}><EditOutlined /></span>
                <span onClick={handleDelItem}><MinusCircleOutlined /></span>
            </div>
          </div>
          

          接下來我們看看表單的全局屬性,通過實際分析我們可以知道表單有如下外觀:

          • 表單標題
          • 表單背景圖片
          • 表單背景顏色
          • 提交按鈕樣式

          所以他們因該成為表單設計的通用屬性,如下圖所示:

          image.png

          以上的表單通過「H5-Dooring」設計而來。當然我們可以利用它設計更加自定的表單頁面。

          最后一個比較使用的需求就是api定制,一般公司可能需要將用戶的錄入數據收集到自己的平臺,那么這個時候我們提供一個api表單提交接口積極很有必要了,上面筆者也展示過,實現很簡單,就是配置里多一個api的文本框即可。

          利用H5-Dooring開發一款表單設計平臺

          在H5編輯器「Dooring」的實現中,我們可以做抽象,每一個頁面組件可以看成特定的表單組件,如下圖:

          我們可以利用「dooring」的能力對表單平臺進行拖拽,樣式設計,數據錄入等等操作,感興趣的朋友可以基于「Dooring」設計思路改造成自己的表單設計平臺。

          對于數據收集能力, 可以參考我的另一篇文章:

          前端如何一鍵生成多維度數據可視化分析報表

          協同支持

          之前 H5-Dooring 是采用 socket 來實現雙向通信的, 不同的用戶如何想協作搭建, 可以通過 共享的json文件 或者 socket 來實現. 不過最新市面上也出了非常不錯的協作方案, 大家也可以參考一下, 這塊的功能設計目前我們正在確定方案.

          出碼能力

          目前 Dooring 支持2種出碼方式:

          • 生成編譯代碼
          • 生成源碼

          image.png

          以上就是我們需要做的在線實時打包下載代碼的工作流,由于nodejs是單線程的,為了不阻塞進程我們可以采用父子進程通信的方式和異步模型來處理復雜耗時任務,為了通知用戶任務的完成狀況, 我們可以用socket做雙向通信。在當前的場景下就是代碼編譯壓縮完成之后,通知給瀏覽器,以便瀏覽器顯示下載狀態彈窗。一共有三種狀態:「進行中」「已完成」「失敗」。對應如下圖所示界面:

          至于為什么沒有出現下載失敗的狀態,不要問我,問就是沒有失敗過(完了,找虐了)。

          以上就是「H5-Dooring」實時編譯下載的工作流設計,至于線上更多的實際需求,我們也可以參考以上設計去實現,接下來筆者來具體介紹實現過程。

          2. 「nodejs」如何使用父子進程

          我們要想實現一個自動化工作流, 要考慮的一個關鍵問題就是任務的執行時機以及以何種方式執行. 因為用戶下載代碼之前需要等H5頁面打包編譯壓縮完成之后才能下載, 而這個過程需要一定的時間(8-30s), 所以我們可以認定它為一個耗時任務.

          當我們使用「nodejs」作為后臺服務器時, 由于「nodejs」本身是單線程的,所以當用戶請求傳入「nodejs」時, 「nodejs」不得不等待這個"耗時任務"完成才能進行其他請求的處理, 這樣將會導致頁面其他請求需要等待該任務執行結束才能繼續進行, 所以為了更好的用戶體驗和流暢的響應,我們不得不考慮多進程處理. 好在nodejs設計支持子進程, 我們可以把耗時任務放入子進程中來處理,當子進程處理完成之后再通知主進程. 整個流程如下圖所示:

          「nodejs」有3種創建子進程的方式,這里筆者簡單介紹一下「fork」的方式。使用方式如下:

          // child.js
          function computedTotal(arr, cb) {
              // 耗時計算任務
          }
          
          // 與主進程通信
          // 監聽主進程信號
          process.on('message', (msg)=> {
            computedTotal(bigDataArr, (flag)=> {
              // 向主進程發送完成信號
              process.send(flag);
            })
          });
          
          // main.js
          const { fork }=require('child_process');
          
          app.use(async (ctx, next)=> {
            if(ctx.url==='/fetch') {
              const data=ctx.request.body;
              // 通知子進程開始執行任務,并傳入數據
              const res=await createPromisefork('./child.js', data)
            }
            
            // 創建異步線程
            function createPromisefork(childUrl, data) {
              // 加載子進程
              const res=fork(childUrl)
              // 通知子進程開始work
              data && res.send(data)
              return new Promise(reslove=> {
                  res.on('message', f=> {
                      reslove(f)
                  })
              })  
            }
            
            await next()
          })
          

          在H5-Dooring線上打包的工作流中,我們會用到「child_process」「exec」方法,來解析并執行命令行指令。至于父子進程的更多應用,大家可以自行探索。

          3. 使用「child_process」的「exec」實現解析并執行命令行指令

          在上面介紹的「dooring」工作流中,我們知道為了實現實時打包,我們需要一個「H5 Template」項目,作為打包的母版,當用戶點擊下載時,會將頁面的「json schema」數據傳給「node服務器」「node服務器」再將「json schema」進行「數據清洗」最后生成「template.json」文件并移動到「H5 Template」母版中,此時母版拿到數據源并進行打包編譯,最后生成可執行文件。

          以上的過程很關鍵, 這里筆者畫個大致的流程圖:

          為了實現以上過程,我們需要兩個關鍵環節:

          1. 將用戶配置的數據進行處理并生成json文件,然后移動到「H5 Template」母版中
          2. 在母版中自動執行打包編譯腳本

          第一個環節很好實現,我們只需要用「nodejs」「fs」模塊生成文件到指定目錄即可,這里筆者重點介紹第二個環節的實現。

          當我們將json數據生成到「H5 Template」中之后,就可以進行打包了,但是這個過程需要自動化的去處理,不能像我們之前啟動項目一樣,手動執行「npm start」或者「yarn start」。我們需要程序自動幫我們執行這個命令行指令,筆者在查「nodejs API」突然發現了「child_process」「exec」方法,可以用來解析指令,這個剛好能實現我們的需求,所以我們開始實現它。代碼如下:

          import { exec } from 'child_process'
          const outWorkDir=resolve(__dirname, '../h5_landing')
          const fid=uuid(8, 16)
          const cmdStr=`cd ${outWorkDir} && yarn build ${fid}`
          
          // ...exec相關代碼
          const filePath=resolve(__dirname, '../h5_landing/src/assets/config.json')
          const res=WF(filePath, data)
          
          exec(cmdStr, function(err,stdout,stderr){
            if(err) {
              // 錯誤處理
            } else {
              // 成功處理
            }
          })
          

          以上代碼我們不難理解,我們只需要定義好打包的指令字符串(方式和命令行操作幾乎一致),然后傳入給「exec」的第一個參數,他就會幫我們解析字符串并執行對應的命令行指令。在執行完成之后,我們可以根據回調函數(第二個參數)里的參數值來判斷執行結果。整個過程是異步的,所以我們不用擔心阻塞問題,為了實時反饋進度,我們可以用「socket」來將進度信息推送到瀏覽器端。

          4. 「http://socket.io」實現消息實時推送

          在上面介紹的 「exec實現解析并執行命令行指令」 中還有一些細節可以優化,比如代碼執行進程的反饋,執行狀態的反饋。因為我們用的是異步編程,所以請求不會一直等待,如果不采取任何優化措施,用戶是不可能知道何時代碼打包編譯完成, 也不知道代碼是否編譯失敗,所以這個時候會采取幾種常用的放案:

          • 客戶端請求長輪詢
          • postmessage消息推送
          • websocket雙向通信

          很明顯使用「websocket雙向通信」會更適合本項目。這里我們直接使用社區比較火的「http://socket.io」.由于官網上有很多使用介紹,這里筆者就不一一說明了。我們直接看業務里的代碼使用:

          // node端
          exec(cmdStr, function(err,stdout,stderr){
            if(err) {
              console.log('api error:'+stderr);
              io.emit('htmlFail', { result: 'error', message: stderr })
            } else {
              io.emit('htmlSuccess', { result: dest, message: stderr })
            }
          })
          
          // 瀏覽器端
          const socket=io(serverUrl);
          // ...省略其他業務代碼
          useEffect(()=> {
            socket.on('connect', function(){
              console.log('connect')
            });
            socket.on('htmlFail', function(data){
              // ...
            });
            socket.on('disconnect', function(e){
              console.log('disconnect', e)
            });
          }, [])
          

          這樣我們就能實現服務器任務流的狀態實時反饋給瀏覽器端了。

          5. 使用「jszip」實現服務端壓縮文件并支持前端下載「zip」包

          實現前端下載功能其實也很簡單,因為用戶配置的H5項目包含了各種資源,比如「css,js,html,image」,所以為了提高下載性能和便捷性我們需要把整個網站打包,生成一個「zip」文件供用戶下載。原理就是使用「jszip」將目錄壓縮,然后返回壓縮后的路徑給到前端,前端采用a標簽進行下載。至于如何實現目錄遍歷壓縮和遍歷讀取目錄, 這里筆者就不說了,感興趣的可以參考筆者其他的nodejs 的文章。

          場景化應用落地

          跌跌撞撞的迭代了2年多, 目前已經基本可以使用Dooring搭建大部分的場景應用了, 比如:

          • 企業官網
          • H5營銷頁面
          • web簡歷
          • 問卷調查
          • 信息流頁面
          • 活動聚合頁面

          等等, 后期會擴展更多的場景, 持續迭代, 滿足更多用戶的深度定制需求.

          后期規劃

          目前Dooring 已經完成了幾個關鍵性的能力:

          • 多模式搭建能力
          • 出碼能力
          • 數據源(動態數據源和靜態數據源)
          • 表單設計能力
          • 組件 / 模版 應用流
          • 國際化
          • 多端搭建(PC, H5, iPad)

          后期會從搭建效率資源生態 這兩個維度繼續迭代, 比如:

          • PSD導入
          • 移動進度控制
          • 營銷組件豐富
          • 智能模版推薦
          • 參數化自動生成頁面
          • 以應用為單位的應用搭建平臺
          • 埋點和監控系統搭建

          血來潮有想改進下工作效率,在代碼開發過程中同事經常問這個錯誤是哪里觸發的,這不是我寫的我也只能一個一個調試定位到是哪個存儲過程,于是想到了我之前的存儲過程顯示源碼的玩意,又進行了改進,直接搜索存儲過程內容。
          切換到要搜索的數據庫

          
          SELECT  top 30 OBJECT_NAME(sm.object_id) AS ProcedureName,
                 OBJECT_DEFINITION(sm.object_id) AS ProcedureDefinition,*
          FROM sys.sql_modules AS sm
          WHERE OBJECT_DEFINITION(sm.object_id) LIKE '%搜索的關鍵詞%'
          

          不過搜索后是一行顯示,顯然不行的,還需要開發一個工具,讓他能完整顯示每行,方便執行測試
          于是整了個web版本

          image.png

          但是還是感覺不得勁,想開發zure data studio的擴展。
          ,但是開發思路是不知道怎么在存儲過程的右鍵菜單插入,于是在azure data studio的擴展中進行搜索 search
          原來有人做了類似的工具,支持緩存搜索和 熱連接接搜索
          不過操作交互不太舒服,是快捷鍵彈出對話框,選中了一個結果其他結果就看不到了,還不如我網頁版的方便。
          另外此插件的功能介紹:
          緩存模式建議在打算改代碼的模式不要使用,否則可能導致生產事故。
          快捷鍵ctrl+t是緩存模式
          ctrl+shift+t 無緩存模式
          https://github.com/MikhailProfile/SearchEverywhere/issues

          我的web版本實現邏輯也是很簡單,因為用的 web core api,不打算套view,直接字符串拼接

              private static string FormatMultiResultAsHtml2(JArray arrs)
                  {
                      
                      
          
                      
                      string html="";
                      for (int a=0; a < arrs.Count; a++)
                      {
                          string title=arrs[a]["title"] +"";
                          string contents=arrs[a]["content"]+"";
                          int lineNum=1;
                          string linetag="結果" + (a + 1);
                          html +=@"
                       <div class=""result"" 
                      <h3> " +title+"|"+ HttpUtility.HtmlEncode(linetag) + @"</h3>
                      <p onclick=""toggleDetails(this)"">展開/收縮</p>
                      <div class=""result-details"">
                       <code> ";
                          html +=contents.Replace("\n", "<br>");
                          
                          html +=@"</code>
                      </div>
                       </div>";
          
          
                      }
          
                      string html1=@"
          <!DOCTYPE html>
          <html lang=""en"">
          <head>
              <meta charset=""UTF-8"">
              <meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
              <style>
                  .results-container {
                      display: flex;
                      flex-wrap: wrap;
                  }
                  .result {
                      flex: 0 0 98%;
                      margin: 2px;
                      padding: 10px;
                      border: 1px solid #ccc;
                      cursor: pointer;
                  }
                  .result-details {
                      display: none;
                  }
              </style>
          </head>
          <body>
              <div class=""results-container"">
               " + html + @"
              </div>
          
              <script>
                  function toggleDetails(element) {
                      element=element.parentNode;
                      var details=element.querySelector('.result-details');
                      if (details.style.display==='none' || details.style.display==='') {
                          details.style.display='block';
                      } else {
                          details.style.display='none';
                      }
                  }
              </script>
          </body>
          </html>
          ";
          
                      return html1;
                  }
          

          然后

             html=FormatMultiResultAsHtml2(ARR);
                          html=html.Replace(content, "<font color='red'><b>" + content + "</b></font>");
          
                      }
          
                      
                      return Content(html, "text/html", Encoding.UTF8);
          

          切換數據庫問題,這個我嘗試過似乎不能指定數據庫只能直接切換數據庫源了。
          傳遞之前的連接字符串,然后進行修改設置回去。


          主站蜘蛛池模板: 国产一区高清视频| 国产乱码精品一区二区三区四川人| 国产精品高清视亚洲一区二区| 一区在线免费观看| 亚洲色精品三区二区一区| 国产成人片视频一区二区| 四虎在线观看一区二区| 亚洲一区二区三区国产精品无码| 亚洲一区二区三区香蕉| 波多野结衣一区二区三区aV高清| 秋霞鲁丝片一区二区三区| 亚洲中文字幕一区精品自拍| 久久人做人爽一区二区三区| 无码人妻AV免费一区二区三区| 亚洲国产成人一区二区三区| 东京热无码一区二区三区av| 一区二区三区福利| 无码少妇一区二区浪潮av| 国产a久久精品一区二区三区| 尤物精品视频一区二区三区| 狠狠做深爱婷婷久久综合一区| 无码一区18禁3D| 国产肥熟女视频一区二区三区| 无码人妻精一区二区三区| 日本一区二区三区久久| 日韩一区二区在线观看| 国产激情无码一区二区三区| 中文字幕一区二区三区乱码| 美女啪啪一区二区三区| 99精品国产高清一区二区| 亚洲一区综合在线播放| 国产精品夜色一区二区三区| 国产一区二区草草影院| 福利一区二区在线| 国产一区玩具在线观看| 一区二区三区观看免费中文视频在线播放 | 久夜色精品国产一区二区三区| 亚洲一区二区高清| 无码国产精品一区二区免费3p| 国产美女一区二区三区| 国产女人乱人伦精品一区二区 |