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 国产无遮挡又黄又爽高清视,亚洲国产精品综合久久一线,国产大陆xxxx做受视频

          整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線:

          使用Electron構(gòu)建跨平臺(tái)的抓取桌面程序

          使用Electron構(gòu)建跨平臺(tái)的抓取桌面程序

          用Electron構(gòu)建跨平臺(tái)的抓取桌面程序

          談起桌面應(yīng)用開(kāi)發(fā)技術(shù), 我們會(huì)想到.Net下的WinForm, Java下的JavaFX以及Linux下的QT. 這些技術(shù)對(duì)于Web應(yīng)用程序員來(lái)說(shuō)一般比較陌生, 因?yàn)榇蠖郬eb應(yīng)用程序員的開(kāi)發(fā)技能是前端的JavaScript和后端的Java,PHP等語(yǔ)言.

          如果Web應(yīng)用程序員想開(kāi)發(fā)桌面應(yīng)用怎么辦? 主流的桌面應(yīng)用開(kāi)發(fā)技術(shù)的學(xué)習(xí)曲線不低, 上手比較困難. 而Electron的出現(xiàn)給Web應(yīng)用程序員帶來(lái)了福音.

          Electron簡(jiǎn)介:

          Electron 是 Github 發(fā)布跨平臺(tái)桌面應(yīng)用開(kāi)發(fā)工具,支持 Web 技術(shù)開(kāi)發(fā)桌面應(yīng)用開(kāi)發(fā),其本身是基于 C++ 開(kāi)發(fā)的,GUI 核心來(lái)自于 Chrome,而 JavaScript 引擎使用 v8...

          簡(jiǎn)單的說(shuō), Electron平臺(tái)就是用Javascript把UI和后臺(tái)邏輯打通, 后臺(tái)主進(jìn)程使用NodeJs豐富的API完成復(fù)雜耗時(shí)的邏輯, 而UI進(jìn)程則借助Chrome渲染html完成交互.

          我之前使用SpringBoot開(kāi)發(fā)了一套市長(zhǎng)信箱抓取Web應(yīng)用. 由于沒(méi)服務(wù)器部署, 所以我現(xiàn)在想把同樣的功能移植到桌面端, 作成一個(gè)桌面應(yīng)用. 對(duì)于開(kāi)發(fā)平臺(tái)我有以下需求:

          1. 能利用我現(xiàn)有的技術(shù)棧: Web前端JavaScript, 服務(wù)端的Java或者NodeJs.
          2. 能跨平臺(tái), 既能編譯成Mac下的DMG安裝程序,又能編譯成windows平臺(tái)下的exe文件, 滿(mǎn)足不足場(chǎng)景的使用.

          而Electron作為開(kāi)發(fā)平臺(tái)正好能滿(mǎn)足我的這些需求, 通過(guò)一天的摸索, 我完成了這個(gè)桌面應(yīng)用, 并最終打包出Mac平臺(tái)下的DMG安裝文件. 工程代碼: https://github.com/ybak/watcher

          下面將介紹我是如何使用Electron平臺(tái)開(kāi)發(fā)這個(gè)桌面應(yīng)用.

          回顧: 市長(zhǎng)信箱郵件抓取Web應(yīng)用

          動(dòng)手之前, 我先分析一下之前所做的抓取Web應(yīng)用. 它的架構(gòu)如下:

          應(yīng)用分可為四部分:

          1. 抓取程序:使用Java的OkHttp作為Http請(qǐng)求類(lèi)庫(kù)獲取網(wǎng)頁(yè)內(nèi)容,并交給Jsoup進(jìn)行解析, 得到郵件內(nèi)容.
          2. 數(shù)據(jù)庫(kù):用Mysql實(shí)現(xiàn), 用來(lái)保存抓取后的網(wǎng)頁(yè)內(nèi)容, 并提供檢索查詢(xún)服務(wù).
          3. 靜態(tài)交互頁(yè)面:一個(gè)簡(jiǎn)單的HTML頁(yè)面, 使用jQuery發(fā)起ajax與后端交互, 并使用handlebar作為展示模板.
          4. 通信: 使用SpringBoot提供了交互所需的API(搜索服務(wù),全量抓取和更新郵件).

          設(shè)計(jì): 使用Electron構(gòu)建抓取桌面應(yīng)用

          將要實(shí)現(xiàn)的桌面應(yīng)用, 同樣也需要需要完成這四部分的工作. 我做了以下設(shè)計(jì):

          Electron主進(jìn)程借助NodeJs豐富的生態(tài)系統(tǒng)完成網(wǎng)頁(yè)抓取與數(shù)據(jù)存儲(chǔ)與搜索的功能, UI進(jìn)程則完成頁(yè)面的渲染工作.

          1. 抓取程序: 使用NodeJs的Request, cheerio, async完成.
          2. 數(shù)據(jù)庫(kù): 使用NodeJs下的nedb存儲(chǔ), 作為應(yīng)用內(nèi)嵌數(shù)據(jù)庫(kù)可以方便的集成進(jìn)桌面應(yīng)用.
          3. UI: 使用HTML與前端JavaScript類(lèi)庫(kù)完成, 重用之前Web應(yīng)用中的靜態(tài)頁(yè)面.
          4. 通信: 使用Electron提供的IPC,完成主進(jìn)程與UI進(jìn)程的通信.

          實(shí)現(xiàn): 使用Electron構(gòu)建抓取桌面應(yīng)用

          1. 抓取程序的實(shí)現(xiàn):

          市長(zhǎng)信箱郵件多達(dá)上萬(wàn)封, JavaScript異步的特點(diǎn), 會(huì)讓人不小心就寫(xiě)出上千并發(fā)請(qǐng)求的程序, 短時(shí)間內(nèi)大量試圖和抓取目標(biāo)服務(wù)器建立連接的行為會(huì)被服務(wù)器拒絕服務(wù), 從而造成抓取流程失敗. 所以抓取程序要做到:

          1. tcp連接復(fù)用
          2. 并發(fā)頻率可控

          我使用以下三個(gè)NodeJs組件:

          1. Request http客戶(hù)端, 利用了底層NodeJs的Http KeepAlive特性實(shí)現(xiàn)了tcp連接的復(fù)用.
          2. async 控制請(qǐng)求的并發(fā)以及異步編程的順序性.
          3. cheerio html的解析器.

          代碼: crawlService.js

          //使用request獲取頁(yè)面內(nèi)容
          request('http://12345.chengdu.gov.cn/moreMail', (err, response, body)=> {
           if (err) throw err;
           //使用cheerio解析html
           var $=cheerio.load(body),
           totalSize=$('div.pages script').html().match(/iRecCount=\d+/g)[0].match(/\d+/g)[0];
           ......
           //使用async控制請(qǐng)求并發(fā), 順序的抓取郵件分頁(yè)內(nèi)容
           async.eachSeries(pagesCollection, function (page, crawlNextPage) {
           pageCrawl(page, totalPageSize, updater, crawlNextPage);
           })
          });
          

          2. 數(shù)據(jù)庫(kù)的實(shí)現(xiàn):

          抓取后的內(nèi)容存儲(chǔ)方式有較多選擇:

          1. 文本文件
          2. 搜索引擎
          3. 數(shù)據(jù)庫(kù)

          文本文件雖然保存簡(jiǎn)單, 但不利于查詢(xún)和搜索, 顧不采用.

          搜索引擎一般需要獨(dú)立部署, 不利于桌面應(yīng)用的安裝, 這里暫不采用.

          獨(dú)立部署的數(shù)據(jù)庫(kù)有和搜索引擎同樣的問(wèn)題, 所以像連接外部Mysql的方式這里也不采用.

          綜合考慮, 我需要一種內(nèi)嵌數(shù)據(jù)庫(kù). 幸好NodeJs的組件非常豐富, nedb是一個(gè)不錯(cuò)的方案, 它可以將數(shù)據(jù)同時(shí)保存在內(nèi)存和磁盤(pán)中, 同時(shí)是文檔型內(nèi)嵌數(shù)據(jù)庫(kù), 使用mongodb的語(yǔ)法進(jìn)行數(shù)據(jù)操作.

          代碼: dbService.js

          //建立數(shù)據(jù)庫(kù)連接
          const db=new Datastore({filename: getUserHome()+'/.electronapp/watcher/12345mails.db', autoload: true});
          ......
          //使用nedb插入數(shù)據(jù)
          db.update({_id: mail._id}, mail, {upsert: true}, function (err, newDoc) {});
          ......
          //使用nedb進(jìn)行郵件查詢(xún)
          let match={$regex: eval('/' + keyword + '/')}; //關(guān)鍵字匹配
          var query=keyword ? {$or: [{title: match}, {content: match}]} : {};
          db.find(query).sort({publishDate: -1}).limit(100).exec(function (err, mails) {
           event.sender.send('search-reply', {mails: mails});//處理查詢(xún)結(jié)果
          });
          

          3. UI的實(shí)現(xiàn):

          桌面應(yīng)用的工程目錄如圖:

          我將UI頁(yè)面放到static文件夾下. 在Electron的進(jìn)行前端UI開(kāi)發(fā)和普通的Web開(kāi)發(fā)方式一樣, 因?yàn)镋lectron的UI進(jìn)程就是一個(gè)Chrome進(jìn)程. Electron啟動(dòng)時(shí), 主進(jìn)程會(huì)執(zhí)行index.js文件, index.js將初始化應(yīng)用的窗口, 設(shè)置大小, 并在窗口加載UI入口頁(yè)面index.html.

          代碼:index.js

          function createMainWindow() {
           const win=new electron.BrowserWindow({
           width: 1200,
           height: 800
           });//初始應(yīng)用窗口大小
           win.loadURL(`file://${__dirname}/static/index.html`);//在窗口中加載頁(yè)面
           win.openDevTools();//打開(kāi)chrome的devTools
           win.on('closed', onClosed);
           return win;
          }
          

          在UI頁(yè)面開(kāi)發(fā)的過(guò)程中, 有一點(diǎn)需要注意的是: 默認(rèn)情況下頁(yè)面會(huì)出現(xiàn)jQuery, require等組件加載失敗的情況, 這是因?yàn)闉g覽器window加載了NodeJs的一些方法, 和jQuery類(lèi)庫(kù)的方法沖突. 所以我們需要做些特別的處理, 在瀏覽器window中把這些NodeJs的方法刪掉:

          代碼:preload.js

          // 解決require沖突導(dǎo)致jQuery等組件不可用的問(wèn)題
          window.nodeRequire=require;
          delete window.require;
          delete window.exports;
          delete window.module;
          // 解決chrome調(diào)試工具devtron不可用的問(wèn)題
          window.__devtron={require: nodeRequire, process: process}
          

          4. 通信的實(shí)現(xiàn):

          在Web應(yīng)用中, 頁(yè)面和服務(wù)的通信都是通過(guò)ajax進(jìn)行, 那我們的桌面應(yīng)用不是也可以采用ajax的方式通信? 這樣理論雖然上可行, 但有一個(gè)很大弊端: 我們的應(yīng)用需要打開(kāi)一個(gè)http的監(jiān)聽(tīng)端口, 通常個(gè)人操作系統(tǒng)都禁止軟件打開(kāi)http80端口, 而打開(kāi)其他端口也容易和別的程序造成端口沖突, 所以我們需要一種更優(yōu)雅的方式進(jìn)行通信.

          Electron提供了UI進(jìn)程和主進(jìn)程通信的IPC API, 通過(guò)使用IPC通信, 我們就能實(shí)現(xiàn)UI頁(yè)面向NodeJs服務(wù)邏輯發(fā)起查詢(xún)和抓取請(qǐng)求,也能實(shí)現(xiàn)NodeJs服務(wù)主動(dòng)向UI頁(yè)面通知抓取進(jìn)度的更新.

          使用Electron的IPC非常簡(jiǎn)單.

          首先, 我們需要在UI中使用ipcRenderer, 向自定義的channel發(fā)出消息.

          代碼: app.js

          const ipcRenderer=nodeRequire('electron').ipcRenderer;
          //提交查詢(xún)表單
          $('form.searchForm').submit(function (event) {
           $('#waitModal').modal('show');
           event.preventDefault();
           ipcRenderer.send('search-keyword', $('input.keyword').val());//發(fā)起查詢(xún)請(qǐng)求
          });
          ipcRenderer.on('search-reply', function(event, data) {//監(jiān)聽(tīng)查詢(xún)結(jié)果
           $('#waitModal').modal('hide');
           if (data.mails) {
           var template=Handlebars.compile($('#template').html());
           $('div.list-group').html(template(data));
           }
          });
          

          然后, 需要在主進(jìn)程執(zhí)行的NodeJs代碼中使用ipcMain, 監(jiān)聽(tīng)之前自定義的渠道, 就能接受UI發(fā)出的請(qǐng)求了.

          代碼: crawlService.js

          const ipcMain=require('electron').ipcMain;
          ipcMain.on('search-keyword', (event, arg)=> {
           ....//處理查詢(xún)邏輯
          });
          ipcMain.on('start-crawl', (event, arg)=> {
           ....//處理抓取邏輯
          });
          

          桌面應(yīng)用打包

          解決完以上四個(gè)方面的問(wèn)題后, 剩下的程序?qū)懫饋?lái)就簡(jiǎn)單了. 程序調(diào)試完后, 使用electron-builder, 就可以編譯打包出針對(duì)不同平臺(tái)的可執(zhí)行文件了.

          最近筆者終于把H5-Dooring的后臺(tái)管理系統(tǒng)初步搭建完成, 有了初步的數(shù)據(jù)采集和數(shù)據(jù)分析能力, 接下來(lái)我們就復(fù)盤(pán)一下其中涉及的幾個(gè)知識(shí)點(diǎn),并一一闡述其在Dooring H5可視化編輯器中的解決方案. 筆者將分成3篇文章來(lái)復(fù)盤(pán), 主要解決場(chǎng)景如下: 如何使用JavaScript實(shí)現(xiàn)前端導(dǎo)入和導(dǎo)出excel文件(H5編輯器實(shí)戰(zhàn)復(fù)盤(pán)) 前端如何基于table中的數(shù)據(jù)一鍵生成多維度數(shù)據(jù)可視化分析報(bào)表 * 如何實(shí)現(xiàn)會(huì)員管理系統(tǒng)下的權(quán)限路由和權(quán)限菜單

          以上場(chǎng)景也是前端工程師在開(kāi)發(fā)后臺(tái)管理系統(tǒng)中經(jīng)常遇到的或者即將遇到的問(wèn)題, 本文是上述介紹中的第一篇文章, 你將收獲: 使用JavaScript實(shí)現(xiàn)前端導(dǎo)入excel文件并自動(dòng)生成可編輯的Table組件 使用JavaScript實(shí)現(xiàn)前端基于Table數(shù)據(jù)一鍵導(dǎo)出excel文件 * XLSXjs-export-excel基本使用

          正文

          本文接下來(lái)的內(nèi)容素材都是基于H5可視化編輯器(H5-Dooring)項(xiàng)目的截圖, 如果想實(shí)際體驗(yàn), 可以訪問(wèn)H5-Dooring網(wǎng)站實(shí)際體驗(yàn). 接下來(lái)我們直接開(kāi)始我們的方案實(shí)現(xiàn).

          1. 使用JavaScript實(shí)現(xiàn)前端導(dǎo)入excel文件并自動(dòng)生成可編輯的Table組件

          在開(kāi)始實(shí)現(xiàn)之前, 我們先來(lái)看看實(shí)現(xiàn)效果.

          1.1 實(shí)現(xiàn)效果

          導(dǎo)入excel文件并通過(guò)antdtable組件渲染table:

          編輯table組件:

          保存table數(shù)據(jù)后實(shí)時(shí)渲染可視化圖表:

          以上就是我們實(shí)現(xiàn)導(dǎo)入excel文件后, 編輯table, 最后動(dòng)態(tài)生成圖表的完整流程.

          1.2 實(shí)現(xiàn)一鍵導(dǎo)入excel文件并生成table表格

          導(dǎo)入excel文件的功能我們可以用javascript原生的方式實(shí)現(xiàn)解析, 比如可以用fileReader這些原生api,但考慮到開(kāi)發(fā)效率和后期的維護(hù), 筆者這里采用antdUpload組件XLSX來(lái)實(shí)現(xiàn)上傳文件并解析的功能. 由于我們采用antdtable組件來(lái)渲染數(shù)據(jù), 所以我們需要手動(dòng)將解析出來(lái)的數(shù)據(jù)轉(zhuǎn)換成table支持的數(shù)據(jù)格式.大致流程如下:

          所以我們需要做的就是將Upload得到的文件數(shù)據(jù)傳給xlsx, 由xlsx生成解析對(duì)象, 最后我們利用javascript算法將xlsx的對(duì)象處理成ant-table支持的數(shù)據(jù)格式即可. 這里我們用到了FileReader對(duì)象, 目的是將文件轉(zhuǎn)化為BinaryString, 然后我們就可以用xlsxbinary模式來(lái)讀取excel數(shù)據(jù)了, 代碼如下:

          // 解析并提取excel數(shù)據(jù)
          let reader=new FileReader();
          reader.onload=function(e) {
            let data=e.target.result;
            let workbook=XLSX.read(data, {type: 'binary'});
            let sheetNames=workbook.SheetNames; // 工作表名稱(chēng)集合
            let draftObj={}
            sheetNames.forEach(name=> {
              // 通過(guò)工作表名稱(chēng)來(lái)獲取指定工作表
              let worksheet=workbook.Sheets[name]; 
              for(let key in worksheet) {
                // v是讀取單元格的原始值
                if(key[0] !=='!') {
                  if(draftObj[key[0]]) {
                    draftObj[key[0]].push(worksheet[key].v)
                  }else {
                    draftObj[key[0]]=[worksheet[key].v]
                  }
                }
              }
            });
            // 生成ant-table支持的數(shù)據(jù)格式
            let sourceData=Object.values(draftObj).map((item,i)=> ({ key: i + '', name: item[0], value: item[1]}))
          

          經(jīng)過(guò)以上處理, 我們得到的sourceData即是ant-table可用的數(shù)據(jù)結(jié)構(gòu), 至此我們就實(shí)現(xiàn)了表格導(dǎo)入的功能.

          1.3 table表格的編輯功能實(shí)現(xiàn)

          table表格的編輯功能實(shí)現(xiàn)其實(shí)也很簡(jiǎn)單, 我們只需要按照antd的table組件提供的自定義行和單元格的實(shí)現(xiàn)方式即可. antd官網(wǎng)上也有實(shí)現(xiàn)可編輯表格的實(shí)現(xiàn)方案, 如下:

          大家感興趣的可以研究一下. 當(dāng)然自己實(shí)現(xiàn)可編輯的表格也很簡(jiǎn)單, 而且有很多方式, 比如用columnrender函數(shù)來(lái)動(dòng)態(tài)切換表格的編輯狀態(tài), 或者使用彈窗編輯等都是可以的.

          1.4 根據(jù)編輯的table數(shù)據(jù)動(dòng)態(tài)生成圖表

          根據(jù)table數(shù)據(jù)動(dòng)態(tài)生成圖表這塊需要有一定的約定, 我們需要符合圖表庫(kù)的數(shù)據(jù)規(guī)范, 不過(guò)我們有了table數(shù)據(jù), 處理數(shù)據(jù)規(guī)范當(dāng)然是很簡(jiǎn)單的事情了, 筆者的可視化庫(kù)采用antvf2實(shí)現(xiàn), 所以需要做一層適配來(lái)使得f2能消費(fèi)我們的數(shù)據(jù).

          還有一點(diǎn)就是為了能使用多張圖表, 我們需要對(duì)f2的圖表進(jìn)行統(tǒng)一封裝, 使其成為符合我們應(yīng)用場(chǎng)景的可視化組件庫(kù).

          我們先看看f2的使用的數(shù)據(jù)格式:

          const data=[
            { genre: 'Sports', sold: 275 },
            { genre: 'Strategy', sold: 115 },
            { genre: 'Action', sold: 120 },
            { genre: 'Shooter', sold: 350 },
            { genre: 'Other', sold: 150 }
          ];
          

          此數(shù)據(jù)格式會(huì)渲染成如下的圖表:

          所以說(shuō)我們總結(jié)下來(lái)其主要有2個(gè)緯度的指標(biāo), 包括它們的面積圖, 餅圖, 折線圖, 格式都基本一致, 所以我們可以基于這一點(diǎn)封裝成組件的可視化組件, 如下:

          import { Chart } from '@antv/f2';
          import React, { memo, useEffect, useRef } from 'react';
          import ChartImg from '@/assets/chart.png';
          
          import styles from './index.less';
          import { IChartConfig } from './schema';
          
          interface XChartProps extends IChartConfig {
            isTpl: boolean;
          }
          
          const XChart=(props: XChartProps)=> {
            const { isTpl, data, color, size, paddingTop, title }=props;
            const chartRef=useRef(null);
            useEffect(()=> {
              if (!isTpl) {
                const chart=new Chart({
                  el: chartRef.current || undefined,
                  pixelRatio: window.devicePixelRatio, // 指定分辨率
                });
          
                // step 2: 處理數(shù)據(jù)
                const dataX=data.map(item=> ({ ...item, value: Number(item.value) }));
          
                // Step 2: 載入數(shù)據(jù)源
                chart.source(dataX);
          
                // Step 3:創(chuàng)建圖形語(yǔ)法,繪制柱狀圖,由 genre 和 sold 兩個(gè)屬性決定圖形位置,genre 映射至 x 軸,sold 映射至 y 軸
                chart
                  .interval()
                  .position('name*value')
                  .color('name');
          
                // Step 4: 渲染圖表
                chart.render();
              }
            }, [data, isTpl]);
            return (
              <div className={styles.chartWrap}>
                <div className={styles.chartTitle} style={{ color, fontSize: size, paddingTop }}>
                  {title}
                </div>
                {isTpl ? <img src={ChartImg} alt="dooring chart" /> : <canvas ref={chartRef}></canvas>}
              </div>
            );
          };
          
          export default memo(XChart);
          

          當(dāng)然其他的可視化組件也可以用相同的模式封裝,這里就不一一舉例了. 以上的組件封裝使用reacthooks組件, vue的也類(lèi)似, 基本原理都一致.

          2. 使用JavaScript實(shí)現(xiàn)前端基于Table數(shù)據(jù)一鍵導(dǎo)出excel文件

          同樣的, 我們實(shí)現(xiàn)將table數(shù)據(jù)一鍵導(dǎo)出為excel也是類(lèi)似, 不過(guò)方案有所不同, 我們先來(lái)看看在Dooring中的實(shí)現(xiàn)效果.

          2.1 一鍵導(dǎo)出為excel實(shí)現(xiàn)效果


          以上就是用戶(hù)基于后臺(tái)采集到的數(shù)據(jù), 一鍵導(dǎo)出excel文件的流程, 最后一張圖是生成的excel文件在office軟件中的呈現(xiàn).

          2.2 使用javascript實(shí)現(xiàn)一鍵導(dǎo)出excel文件功能

          一鍵導(dǎo)出功能主要用在H5-Dooring的后臺(tái)管理頁(yè)面中, 為用戶(hù)提供方便的導(dǎo)出數(shù)據(jù)能力. 我們這里導(dǎo)出功能也依然能使用xlsx來(lái)實(shí)現(xiàn), 但是綜合對(duì)比了一下筆者發(fā)現(xiàn)有更簡(jiǎn)單的方案, 接下來(lái)筆者會(huì)詳細(xì)介紹, 首先我們還是來(lái)看一下流程:

          很明顯我們的導(dǎo)出流程比導(dǎo)入流程簡(jiǎn)單很多, 我們只需要將table的數(shù)據(jù)格式反編譯成插件支持的數(shù)據(jù)即可. 這里筆者使用了js-export-excel來(lái)做文件導(dǎo)出, 使用它非常靈活,我們可以自定義: 自定義導(dǎo)出的excel文件名 自定義excel的過(guò)濾字段 * 自定義excel文件中每列的表頭名稱(chēng)

          由于js-export-excel支持的數(shù)據(jù)結(jié)構(gòu)是數(shù)組對(duì)象, 所以我們需要花點(diǎn)功夫把table的數(shù)據(jù)轉(zhuǎn)換成數(shù)組對(duì)象, 其中需要注意的是ant的table數(shù)據(jù)結(jié)構(gòu)中鍵對(duì)應(yīng)的值可以是數(shù)組, 但是js-export-excel鍵對(duì)應(yīng)的值是字符串, 所以我們要把數(shù)組轉(zhuǎn)換成字符串,如[a,b,c]變成'a,b,c', 所以我們需要對(duì)數(shù)據(jù)格式進(jìn)行轉(zhuǎn)換, 具體實(shí)現(xiàn)如下:

          const generateExcel=()=> {
              let option={};  //option代表的就是excel文件
              let dataTable=[];  //excel文件中的數(shù)據(jù)內(nèi)容
              let len=list.length;
              if (len) {
                  for(let i=0; i<len; i++) {
                      let row=list[i];
                      let obj:any={};
                      for(let key in row) {
                          if(typeof row[key]==='object') {
                              let arr=row[key];
                              obj[key]=arr.map((item:any)=> (typeof item==='object' ? item.label : item)).join(',')
                          }else {
                              obj[key]=row[key]
                          }
                      }
                      dataTable.push(obj);  //設(shè)置excel中每列所獲取的數(shù)據(jù)源
                  }
              }
              let tableKeys=Object.keys(dataTable[0]);
              option.fileName=tableName;  //excel文件名稱(chēng)
              option.datas=[
                    {
                      sheetData: dataTable,  //excel文件中的數(shù)據(jù)源
                      sheetName: tableName,  //excel文件中sheet頁(yè)名稱(chēng)
                      sheetFilter: tableKeys,  //excel文件中需顯示的列數(shù)據(jù)
                      sheetHeader: tableKeys,  //excel文件中每列的表頭名稱(chēng)
                    }
              ]
              let toExcel=new ExportJsonExcel(option);  //生成excel文件
              toExcel.saveExcel();  //下載excel文件
            }
          

          注意, 以上筆者實(shí)現(xiàn)的方案對(duì)任何table組件都使用, 可直接使用以上代碼在大多數(shù)場(chǎng)景下使用. 至此, 我們就實(shí)現(xiàn)了使用JavaScript實(shí)現(xiàn)前端導(dǎo)入和導(dǎo)出excel文件的功能.

          所以, 今天你又博學(xué)了嗎?

          最后

          以上教程筆者已經(jīng)集成到H5-Dooring中,對(duì)于一些更復(fù)雜的交互功能,通過(guò)合理的設(shè)計(jì)也是可以實(shí)現(xiàn)的,大家可以自行探索研究。

          地址:H5-Dooring | 一款強(qiáng)大的H5編輯器

          如果想學(xué)習(xí)更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數(shù)據(jù)可視化等前端知識(shí)和實(shí)戰(zhàn),歡迎在《趣談前端》一起學(xué)習(xí)討論,共同探索前端的邊界。

          鄒個(gè)人站點(diǎn):http://www.itzoujie.com/

          不懂后端的前端不是一個(gè)大前端,不懂后端的前端會(huì)大大限制你的發(fā)展空間,所以小鄒在網(wǎng)上找了一篇不錯(cuò)的文章來(lái)分享給大伙,這里說(shuō)一下,小鄒的個(gè)人站點(diǎn)技術(shù)棧是(node+express+vue+mysql),跟這篇文章的技術(shù)棧略有不同,當(dāng)然站點(diǎn)里面涉及的組件庫(kù)和小程序等,小鄒這里就不一一說(shuō)了。好了,下面直接開(kāi)始分享:

          技術(shù)棧

          Vue + vuex + element-ui + webpack + nodeJs + koa2 + mongodb

          目錄結(jié)構(gòu)講解

          說(shuō)明:

          • build - webpack的配置文件
          • code - 放置代碼文件
          • config - 項(xiàng)目參數(shù)配置的文件
          • logs - 日志打印文件
          • node_modules - 項(xiàng)目依賴(lài)模塊
          • public - 項(xiàng)目靜態(tài)文件的入口 例如: public下的 demo.html文件, 可通過(guò) localhost:3000/demo.html 訪問(wèn)
          • static - 靜態(tài)資源文件
          • .babelrc - babel編譯
          • postcss.config.js - css后處理器配置

          build 文件講解

          說(shuō)明:

          • build.js - 執(zhí)行webpack編譯任務(wù), 還有打包動(dòng)畫(huà) 等等
          • get-less-variables.js - 解析less文件, 賦值less全局變量
          • style-loader.js - 樣式loader配置
          • vue-config.js - vue配置
          • webpack.base.conf.js - webpack 基本通用配置
          • webpack.dev.conf.js - webpack 開(kāi)發(fā)環(huán)境配置
          • webpack.prod.conf.js - webpack 生產(chǎn)環(huán)境配置

          code 文件

          1.admin - 后臺(tái)管理界面源碼

          src - 代碼區(qū)域:

          1. components - 組件
          2. filters - 過(guò)濾器
          3. font - 字體/字體圖標(biāo)
          4. images - 圖片
          5. router - 路由
          6. store - vuex狀態(tài)管理
          7. styles - 樣式表
          8. utils - 請(qǐng)求封裝
          9. views - 頁(yè)面模塊
          10. App.vue - app組件
          11. custom-components.js - 自定義組件導(dǎo)出
          12. main.js - 入口JS
          13. index.html - webpack 模板文件

          2.client - web端界面源碼

          跟后臺(tái)管理界面的結(jié)構(gòu)基本一樣。

          3.server - 服務(wù)端源碼

          說(shuō)明:

          1. controller: 所有接口邏輯代碼
          2. middleware: 所有的中間件
          3. models: 數(shù)據(jù)庫(kù)model
          4. router: 路由/接口
          5. app.js: 入口
          6. config.js: 配置文件
          7. index.js: babel編譯
          8. mongodb.js: mongodb配置

          其他文件

          • config - 項(xiàng)目參數(shù)配置的文件
          • logs - 日志文件
          • public - 項(xiàng)目靜態(tài)文件的入口
          • static - 靜態(tài)資源文件
          • .babelrc - babel編譯
          • postcss.config.js - css后處理器配置

          后臺(tái)管理

          開(kāi)發(fā)中用的一些依賴(lài)模塊

          • vue/vue-router/vuex - Vue全家桶
          • axios - 一個(gè)現(xiàn)在主流并且很好用的請(qǐng)求庫(kù) 支持Promise
          • qs - 用于解決axios POST請(qǐng)求參數(shù)的問(wèn)題
          • element-ui - 餓了么出品的vue2.0 pc UI框架
          • babel-polyfill - 用于實(shí)現(xiàn)瀏覽器不支持原生功能的代碼
          • highlight.js / marked- 兩者搭配實(shí)現(xiàn)Markdown的常用語(yǔ)法
          • js-md5 - 用于登陸時(shí)加密
          • nprogress - 頂部加載條

          components

          這個(gè)文件夾一般放入常用的組件, 比如 Loading組件等等。

          views

          所有模塊頁(yè)面。

          store

          vuex 用來(lái)統(tǒng)一管理公用屬性, 和統(tǒng)一管理接口。

          登陸

          登陸是采用 jsonwebtoken方案 來(lái)實(shí)現(xiàn)整個(gè)流程的。

          1. jwt.sign(payload,secretOrPrivateKey,[options,callback]) 生成TOKEN

          2. jwt.verify(token,secretOrPublicKey,[options,callback]) 驗(yàn)證TOKEN

          3.獲取用戶(hù)的賬號(hào)密碼。

          4.通過(guò) jwt.sign 方法來(lái)生成token:

          5.每次請(qǐng)求數(shù)據(jù)的時(shí)候通過(guò) jwt.verify 檢測(cè)token的合法性 jwt.verify(token,secret)。

          權(quán)限

          通過(guò)不同的權(quán)限來(lái)動(dòng)態(tài)修改路由表。

          通過(guò) vue的 鉤子函數(shù) beforeEach 來(lái)控制并展示哪些路由, 以及判斷是否需要登陸。

          通過(guò)調(diào)用 getUserInfo方法傳入 token 獲取用戶(hù)信息, 后臺(tái)直接解析 token 獲取里面的信息返回給前臺(tái)。

          通過(guò)調(diào)用 setRoutes方法 動(dòng)態(tài)生成路由。

          axios 請(qǐng)求封裝,統(tǒng)一對(duì)請(qǐng)求進(jìn)行管理

          面包屑 / 標(biāo)簽路徑

          • 通過(guò)檢測(cè)路由來(lái)把當(dāng)前路徑轉(zhuǎn)換成面包屑。
          • 把訪問(wèn)過(guò)的路徑儲(chǔ)存在本地,記錄下來(lái),通過(guò)標(biāo)簽直接訪問(wèn)。

          上面介紹了幾個(gè)主要以及必備的后臺(tái)管理功能,其余的功能模塊 按照需求增加就好

          前臺(tái)

          前臺(tái)展示的頁(yè)面跟后臺(tái)管理界面差不多, 也是用vue+webpack搭建,基本的結(jié)構(gòu)都差不多。

          server端

          權(quán)限

          主要是通過(guò) jsonwebtoken 的verify方法檢測(cè) cookie 里面的 token 驗(yàn)證它的合法性。

          日志是采用 log4js 來(lái)進(jìn)行管理的, log4js 算 nodeJs 常用的日志處理模塊,用起來(lái)額也比較簡(jiǎn)單。

          log4js 的日志分為九個(gè)等級(jí),各個(gè)級(jí)別的名字和權(quán)重如下:

          1.圖。

          2.設(shè)置 Logger 實(shí)例的類(lèi)型 logger=log4js.getLogger('cheese')。

          3.通過(guò) Appender 來(lái)控制文件的 名字、路徑、類(lèi)型 。

          4.配置到 log4js.configure。

          5.便可通過(guò) logger 上的打印方法 來(lái)輸出日志了 logger.info(JSON.stringify(currTime:當(dāng)前時(shí)間為${Date.now()}s ))。

          定制書(shū)寫(xiě)規(guī)范(API)

          設(shè)計(jì)思路

          當(dāng)應(yīng)用程序啟動(dòng)時(shí)候,讀取指定目錄下的 js 文件,以文件名作為屬性名,掛載在實(shí)例 app 上,然后把文件中的接口函數(shù),擴(kuò)展到文件對(duì)象上。

          讀取出來(lái)的便是以下形式:

          app.controller.admin.other.markdown_upload_img

          便能讀取到 markdown_upload_img 方法。

          在把該形式的方法賦值過(guò)去就行:

          router.post('/markdown_upload_img',app.controller.admin.other.markdown_upload_img)
          


          通過(guò) mongoose 鏈接 mongodb

          封裝返回的send函數(shù)

          通過(guò) koa-static 管理靜態(tài)文件入口

          注意事項(xiàng):

          1. cnpm run server 啟動(dòng)服務(wù)器 //沒(méi)裝cnpm的使用npm命令

          2.啟動(dòng)時(shí),記得啟動(dòng)mongodb數(shù)據(jù)庫(kù),賬號(hào)密碼 可以在 server/config.js 文件下進(jìn)行配置

          3. db.createUser({user:"cd",pwd:"123456",roles:[{role:"readWrite",db:'test'}]})(mongodb 注冊(cè)用戶(hù))

          4. cnpm run dev:admin 啟動(dòng)后臺(tái)管理界面

          5.登錄后臺(tái)管理界面錄制數(shù)據(jù)

          6.登錄后臺(tái)管理時(shí)需要在數(shù)據(jù)庫(kù) 創(chuàng)建 users 集合注冊(cè)一個(gè)賬號(hào)進(jìn)行登錄

          7. cnpm run dev:client 啟動(dòng)前臺(tái)頁(yè)面


          主站蜘蛛池模板: eeuss鲁片一区二区三区| 国产精品视频分类一区| 亚洲综合无码一区二区| 韩国一区二区三区视频| 亚洲一区二区三区在线观看蜜桃| 成人区人妻精品一区二区三区| 成人精品视频一区二区三区 | 无码国产精品一区二区免费I6| 国产波霸爆乳一区二区| 亚洲免费一区二区| 亚洲一区日韩高清中文字幕亚洲| 激情久久av一区av二区av三区| 中文字幕一区在线观看视频| 香蕉久久一区二区不卡无毒影院 | 狠狠做深爱婷婷久久综合一区| 99精品国产高清一区二区| 亚洲AV午夜福利精品一区二区| 亚洲国模精品一区| 中文字幕人妻无码一区二区三区| 日本人真淫视频一区二区三区| 精品中文字幕一区二区三区四区| 国产成人一区二区三区免费视频| 亚洲sm另类一区二区三区| 欧美成人aaa片一区国产精品| 亚洲一区二区三区国产精华液| 精品国产一区AV天美传媒| 亚洲一区二区三区亚瑟| 亚洲av无码一区二区三区人妖 | 亚洲无线码一区二区三区| 中文字幕一精品亚洲无线一区| 精品国产日产一区二区三区| 日韩一区二区电影| AA区一区二区三无码精片| 中文字幕av人妻少妇一区二区| 无码一区二区三区AV免费| 精品国产一区二区三区在线| 日韩一区二区在线观看| 国产内射在线激情一区| 日韩免费一区二区三区在线| 免费高清av一区二区三区| 一区二区三区在线免费|