當前位置:首頁 » 網頁前端 » 前端wiki
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

前端wiki

發布時間: 2023-05-03 06:03:35

① python/java/web前端需要哪個編程資料

Python、Java和Web前端都需要相應的編程資料來學習和提高編程能耐余亂力,以下是一些常用的編程資料:

Python編程資料:

《Python編毀運程從入門到實踐》

《Python核心編程》

《Python Cookbook》

Python官方文檔

Python編程網站(如Python官網、Python教程網等)

Java編程資料:

《Java編程思想》

《Effective Java》

《Head First Java》

Java官方文檔

Java編程網站(如Java官網、Java教程網等)

Web前端編程資料:

《JavaScript高級程序設計》

《CSS權威指南》

《HTML5權威指南》

MDN Web文檔

Web前端編程網站(昌檔如W3School、Bootstrap中文網等)

以上是一些常用的編程資料,但不限於此,還有很多其他的資料可以供大家學習和參考。

② 女生適合學習前端開發嗎

前端開發不僅適合女生學,根據我們以前的學員,學前端的絕大部分都是女生。而且,而且女生學習it也首選前端。
女生從事前端開發是比較適合的,隨著工業互聯網時代的到來,前端開發的邊界會不斷得到拓展,崗位附加值也會有所提升,隨著越來越多的企業紛紛實現業務雲端化,未來前端開發人員的就業渠道也會逐漸得到拓展。
雖然前端開發的初期學習難度相對較低,但是前端開發的知識量還是比較大的,在移動互聯網時代,前端開發的邊界開始逐漸向移動端拓展,而在雲計算和大數據的推動下,前端開發的邊界也在逐漸從前端向後端覆蓋,所以也把當前的前端稱為「大前端」。
當前在IT互聯網行業內,相對於後端開發來說,不少女生更願意從事前端開發,雖然前端開發通常都屬於應用級開發,對於從業者的演算法設計能力沒有更多的要求,但是前端開發的工作量並不低,這一點也要引起足夠的重視。

③ 什麼是基於數據驅動的前端框架

首先,「數據驅動」 是一種編程範式(Programming Paradigm),相似的有很多,詳情可以參考這里:https://en.wikipedia.org/wiki...
如果只談前端,那麼問題就會簡化很多,一般來說,會比較 「數據驅動」 與 「事件驅動」。數據驅動思想的出現一定程度上彌補了事件驅動的不足。
先說事件驅動,一個很典型的例子就是 jQuery。用 jQuery 開發的頁面執行初期就像這樣:
通過特定的選擇器查找到需要操作的節點 -> 給節點添加相應的事件監聽

響應用戶操作,效果是這樣:
用戶執行某事件(點擊,輸入,後退等等) -> 調用 JavaScript 來修改節點

這種模式,對於業務需求簡單的頁面來說沒什麼問題。只是現在前端越來越復雜,光用這樣的模式已經滿足不了很多大型項目的需求。另一方面,找節點和修改節點這件事兒,效率本身就很低。因此出現了數據驅動模式,我們就拿其中的一種,MVVM 來舉例子,執行初期就像這樣:
讀取模板,同時獲得數據,並建立 VM(view-model) 的抽象層 -> 在頁面進行填充

要注意的是,MVVM 對應了三個層,M - Model,可以簡單的理解為數據層;V - View,可以理解為視圖,或者網頁界面;VM - ViewModel,一個抽象層,簡單來說可以認為是 V 層中抽象出的數據對象,並且可以與 V 和 M 雙向互動(一般實現是基於雙向綁定,雙向綁定的處理方式在不同框架中不盡相同)。
針對用戶的操作,大致是這樣:
用戶執行某個操作 -> 反饋到 VM 處理(可以導致 Model 變動) -> VM 層改變,通過綁定關系直接更新頁面對應位置的數據

總結一下,可以簡單的這么去理解:數據驅動不是操作節點的,而是通過虛擬的抽象數據層來直接更新頁面。我覺得,主要就是因為這一點,數據驅動框架才得以有較快的運行速度(因為不需要去折騰節點),並且可以應用到大型項目。

④ 前端性能-減少Http請求

依據性能黃金法則,80%的時間花費在了Images,scripts,stylesheets,Flash等Http請求上,我們需沖老要花費在這塊的時間,這些技散圓升術包括使用image maps,css sprites,inline images,和合並javascript與stylesheets

如果你頁面上有很多帶鏈接的圖片,image maps(圖片地圖)是一種減少Http請求數量的方式。一個image maps允許你在單張圖片上放置相關的多個鏈接地址,用戶點擊圖片上不同的區域,跳轉到不同的鏈接頁面;
有兩種類型的image maps,一種是server-side image maps, 這種maps,所有的點擊都請求同一個URL,並且參數附帶用戶點擊點的x,y坐標;另一種是Client-side image maps,這種更加常用,因為用戶點擊不同的區域,請求不同的URL;如下

-- image map詳細資料可查看
https://en.wikipedia.org/wiki/Image_map
-- client-side image maps的實例
https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_areamap

俗稱雪碧圖,具體怎麼做應腔態該都知道;說說它的益處吧,它不僅減少了Http請求數,而且相對image maps更加靈活,因為image map要求使用的圖片要求圖形有順序,單sprites不需要;
另外一般人都認為合並圖片會比分開的圖片總量的大小要來的大,因為合並後的圖片有格外增加的空白區域,事實上合並的圖片反而趨於更小,因為合並的圖片相對分開的圖片減少了存儲的信息開銷,比如顏色表,格式形式等;

使用data:URL 協議使你的頁面直接包含圖像而不需要任何Http請求是可能的,但瀏覽器直到ie8才支持;格式如下

data:不單單能使用於內聯圖片,任務一個指定URL的地方都能使用它,包括script和a 標簽;
因為data:URLs內嵌於頁面中,所以在不同頁面訪問中並不會緩存他們,從而增大頁面的大小,一種聰明的做法是通過外聯css和內容圖片作為背景圖設置來使內嵌圖片隨著css一塊被緩存,在多個頁面都使用到這個內嵌圖片的情況下,是值得這么做的,比如網站logo;

-- 如何生成圖片的base64編碼
使用一些在線工具,比如這個 http://www.pjhome.net/web/html5/encodeDataUrl.htm ;
或者使用google chrome開發者工具,在 chrome 下新建一個窗口,然後把要轉化的圖片直接拖入瀏覽器,打開控制台,點 Source,點擊圖片,右側就會顯示該圖片的 base64 編碼

理想狀態下,把一個網頁上引用的多個script腳本合並成一個,把引用的多個樣式文件合並成一個,以此來減少http請求數,一般合並後還會有另一個步驟來減少文件大小,叫做壓縮;

-- 如何合並
一般使用grunt或者gulp打包工具的童鞋都知道,都能輕松做到;

⑤ 一路走來,都有哪些字體

在產品的設計過程中,設計師總是期望最後產品展示的效果能與自己設計稿一模一樣,但最後屏幕呈現出的效果多少會與設計稿有所出入。

這時設計會向前端抱怨屏幕敏蔽顯示的效果與自己的設計不符,前端也表示很無辜,這是按照設計要求實現的,怎麼能怪我?信碰

可能對大多數用戶來說,沒法一眼識別哪裡存在差距,但細微差距的集合,對用戶的整體感官差距完全是不同的。這些細微差距體現在很多方面,其中,字體就是一個糾結的地方,很難說清,但影響又無處不在。

字體的分類、歷史

首先,先來介紹一下字體的分類和歷史,在西方國家的字母體系,分成兩大字族:

serif(襯線字體)
sans serif(無襯線字體)

英文字體

襯線字(如圖中的 Times New Roman)是指在字的筆畫開始及結束的地方有額外的裝飾,而且筆畫的粗細會因直橫的不同而有所不同。起始和結束裝飾的不同,能設計出不同風格的字體。

無襯線體(如圖中的 Helvetica),沒有這些額外的裝飾,而且筆畫粗細差不多。字形更加趨於理性,用戶很難從字體的外形看出字體要表達的性格,感情。

中文字體

在中文字體中,宋體是比較標準的 serif 字體,襯線的特徵比較明顯。

無襯線字(如圖中的思源黑體)就沒有這些額外裝飾,而且筆畫粗細大致上是差不多。

字體的特點、如何選擇

介紹了字體的分類和歷史,接下來就是考慮具體使用的場景,如何選擇合適的字體呢?

在平面印刷,雜志,企業 Logo 中,需要考慮:

表達的性格和感情
引起他人的關注,吸引眼球
因此,往往會使用 特殊的襯線體或者特殊設計字體。

在電子屏幕的場景下,更多的考慮:

清晰度
長時間下,是否容易視覺疲勞
不同字體大小是否會影響字體清晰度
在這些因素的考慮下,無襯線體沒有邊角的修飾,結構簡單清晰,在同等字型大小下,無襯線的字體看上去比有襯線更大,結構更清晰的特性,更加適合屏幕。也不會因為字體本身結構筆劃,影響文字內容的情感態度表達。無襯線體帶來的性格,立場就是中性的,在需要大量排版閱讀的文字網站中,就像空氣一樣,我們不會在意文字本身設計的影響。因此,更應該使用 無襯線體。

不同瀏覽器如何實現字體的技術

字體的選擇,這是設計階段需要考慮的事情,但如何做到屏幕顯示和設計一樣呢?我們需要了解不同瀏覽器實現顯示的一些原理技術。

先介紹一下點陣字體與矢量字體:

點陣字體

點陣字體也叫點陣圖字體,其中每個字形都以一滑拿談組二維像素信息表示。

由於點陣圖的原故,點陣字體很難進行縮放,特定的點陣字體只能清晰地顯示在相應的字型大小下。但對於 12-16px 這樣小的漢字,點陣字體常常比其它類型的字體在屏幕上更好的顯示效果。

常見的點陣字體有 bdf,pcf,fnt,hbf 等格式。

對於常見的計算機操作系統,字體的顯示演算法需要一些字體的信息來優化屏幕顯示效果,英文稱為 hinting。漢字由於筆畫復雜,所以 hinting 的方式與西文截然不同。使用在漢字字體中嵌入預先製作的點陣點陣圖既可以有效地避免 hinting 演算法帶來的計算開銷,同時屏幕上顯示的漢字邊緣清晰,易於閱讀。

矢量字體

矢量字體中每一個字形是通過數學曲線來描述的,它包含了字形邊界上的關鍵點,連線的導數信息等,字體的渲染引擎通過讀取這些數學矢量,然後進行一定的數學運算來進行渲染。

這類字體的好處是字體可以無限放大而不產生變形。

矢量字體主要包括 Type1 和 TrueType 等幾類。

系統的偏好

Windows

默認是使用很重的 hinting,直到 DirectWrite 開始才禁用 horizontal hinting
字體渲染強調文字的銳利和清晰
在操作系統介面和網頁正文等小字型大小的地方比較清晰,但大幅犧牲字體的原貌
Mac OS X

完全不用 hinting 信息,只在 vertical 方向做一些 autohint
字體渲染強調忠實字體設計,最大化保留字體的外形
邊緣平滑是為了更好地傳遞字體設計中的曲線等細節,而小字型大小時顯得模糊也是在此方針下的妥協
最佳實現

考慮到 css 的「優雅降級」原則,默認我們先把 Mac OS 的字體放在最前面,中文 "PingFang SC-light",英文 "Helvetica Neue",降級備用字體 "Hiragino Sans GB" 和 "Helvetica",最後考慮基礎 Windows 系統自帶的字體 "Microsoft YaHei" 和 "Arial"。

font-family:"PingFangSC-light","Helvetica Neue",「Hiragino Sans GB」,「Helvetica」,「Microsoft YaHei」,「Arial」
1
2
1
2
字體設計是整個界面設計的一部分,我們很難意識到它的重要性,就像我們不會在意空氣和水,但它的作用不容忽視。

參考鏈接

hunting引用

更多專業前端知識,請上 【猿2048】www.mk2048.com
原文鏈接:https://www.mk2048.com/blog/blog.php?id=0bhb2jjakj&title=%E4%B8%80%E8%B7%AF%E8%B5%B0%E6%9D%A5%E7%9A%84%E2%80%9C%E5%AD%97%E4%BD%93%E2%80%9D
打開CSDN,閱讀體驗更佳

熱門推薦 大學一路走來,學習互聯網全靠這幾個網站,最終拿下了一把offer
大佬原來都是這樣煉成的
繼續訪問
互聯網行業一路走來的小計(持續更新中.......)
用過的代碼編譯器、插件和圖標樣式
繼續訪問

vue,一路走來(2)--路由vue-router
安裝Mint UI cnpm install mint-ui --save 如果你的項目會用到 Mint UI 里較多的組件,最簡單的方法就是把它們全部引入。此時需要在入口文件 main.js 中: 自己覺得mint-ui的文件介紹不是很詳細,簡單介紹一下我遇到的問題吧! 1.Swipe 輪播圖:記得一定要給個高度 <!--輪播圖--> <div clas...
繼續訪問
OC Extension Font(字體宏定義)
一直覺得自己寫的不是技術,而是情懷,一個個的教程是自己這一路走來的痕跡。靠專業技能的成功是最具可復制性的,希望我的這條路能讓你們少走彎路,希望我能幫你們抹去知識的蒙塵,希望我能幫你們理清知識的脈絡,希望未來技術之巔上有你們也有我。 很多人在開發過程中會針對公司的需求都會對字體做一個宏定義的封裝。方便日後的使用。下面簡單的寫一下。 #ifndef FontHeader_h #define FontHeader_h //kFont #define kFont_10 [UIFont systemFontOfS
繼續訪問

分享一組矢量圖標–UX圖標字體庫
科技日新月異的今天,市面上各種解析度、各種顯示精度的顯示設備層出不窮,在不同精度不同解析度的顯示設備下圖標的應用展現出現了不同要求;如設計師為iphone 3gs設計的圖標在iphone4下的展現就顯得很糟糕了。我們為pc端產品設計的圖標到平板電腦上顯示(new ipad)上展現就不盡人意了。那這么多的顯示設備,那麼多的圖標尺寸設計師難道要一個一個去優化去設計嗎?
繼續訪問
Linux gvim 編輯器修改配色方案、字體、字型大小
1. gvim相比於vim,目前知道gvim是可以單獨窗口運行的,像gedit一樣。vim打開的文件貌似只能顯示在終端內。但是二者安裝的位置以及配置文件是很有聯系的,暫時的感覺是gvim是對vim的封裝,對vim配置文件的修改也影響到gvim。(都僅僅是感覺而已,說錯不要拍磚) 2. 通過apt-get install vim-gtk安裝gvim後,發現原生態的配色有點慘不忍睹,遂即g...
繼續訪問
win7字體放大不放大窗口_放大不確定的未來
win7字體放大不放大窗口 介紹 (Introction) A little while back, I wrote an article for Data Driven Investor. It addressed a subject that one might rightly say should be off-limits for public discussion today, an...
繼續訪問
一段字體CSS
花開了就歡喜,花謝了就放棄,陪你一路走來滿心歡喜,是因為風景也是因為你。 1. 工作室介紹2. 工作室成員介紹 Name: KinaSex: FemaleBirth: 1984.6.8 Location: ShanghaiLiking: Designing, drawing and writingDream: Hav
繼續訪問
後台界面設計之表單設計規范參考
前言 在後台界面設計之表格設計規范參考一文中,我們對表格中內容的布局、數據的展示、操作項的羅列進行了詳細的講解,本文將對表單的設計規范做一個參考性的建議。 表單是中後台系統最常見的元素模塊之一,承載了各個流程中信息數據的錄入使命。提高信息數據錄入的效率可以加速用戶達成目標的時間與降低操作成本。 一般要求在錄入前盡可能的使用戶理解信息錄入的目的與預測並判斷需要錄入的信息內容,在錄入過程中盡可能的減少輸錯概率並幫助用戶快速達成,在錄入後即時糾錯提示並避免繁復操作等。 1.基本樣式 1.1 顏色 使用色彩系統設定
繼續訪問

Android開發未來的出路何在
Android開發的現狀 目前,移動開發已經處於飽和的階段,Android開發也不如當年盛況,已經不再像前幾年前那麼火爆。正如一種編程語言如果經歷過盛極一時,那麼必然有這樣的一條曲線,像我們學的正弦曲線先急速上升,然後到達頂點,然後再下降,最後再趨近一個平穩的值。 可以看到,從2016年的下半年開始,移動互聯網基本處於緩慢發展的階段,很多大佬稱之為互聯網的下半場。如果移動互聯網的前半場是粗放式的強...
繼續訪問

SaaS前世今生:老樹開新花
戳藍字「CSDN雲計算」關注我們哦!作者 |文東海出品 | CSDN雲計算(ID:CSDNcould)2019年3月26日,Adobe和微軟宣布,兩家公司准備展開一項合...
繼續訪問
CSDN 一路走好 之Wiki與Blog
CSDN一路走來,從無到有,慢慢地,慢慢地,他什麼都要做了頻道開的一天天多,但是定位呢?開起來了,火幾天,滅了。長久來,就累積了不少垃圾,如前文所述。今天來說說Wiki,Wiki是個好東西,但是CSDN用來做什麼呢?就擺個程序放在那裡,是不是浪費,坦白地說,很多人就三分鍾熱度,,今天戳幾筆明天戳幾筆,後天走人了到後來,這個Wiki就成了個垃圾站,徒勞地浪費了帶寬 和 伺服器。來,隨便抓個頁面佐
繼續訪問
Sublime Text 3 全程詳細圖文原創教程
Sublime Text 3 全程詳細圖文原創教程(持續更新中。。。) 一、 前言 使用Sublime Text 也有幾個年頭了,版本也從2升級到3了,但猶如寒天飲冰水,冷暖盡自知。最初也是不知道從何下手,滿世界地查找資料,但能查閱到的資料,苦於它們的零碎、片面,不夠系統和全面,所以一路走來,耗費了本人大量的時間和精力。所以蒙生了寫這篇《Sublime Text 3
繼續訪問
OC 基礎 Label
一直覺得自己寫的不是技術,而是情懷,一個個的教程是自己這一路走來的痕跡。靠專業技能的成功是最具可復制性的,希望我的這條路能讓你們少走彎路,希望我能幫你們抹去知識的蒙塵,希望我能幫你們理清知識的脈絡,希望未來技術之巔上有你們也有我。 1.常用屬性 屬性 注釋 frame 約束 text 文本內容 numberOfLines 設置行數 textColor 文本顏色 backgroundColor 背景顏色 font 文字大小 textAlignment 對齊方式 en
繼續訪問
[Android] 環境配置之正式版Android Studio 1.0
昨天看見 Android Studio 1.0 正式版本發布了;心裡挺高興的。 算是忠實用戶了吧,從去年開發者大會一開始出現 AS 後就開始使用了;也是從那時開始就基本沒有用過 Eclipse 了;一路走來,遇到過 BUG ,也不斷的去國外找資源 找解決辦法。總的來說挺好的;有些回憶。 這里不講具體的源碼編輯,只是講怎麼下載配置直至簡單的使用。
繼續訪問
webpack
parcel開發第三方包的時候用的比較多,webpack做項目的時候用的比較多遇到的問題:ES6導入語法import在瀏覽器中報錯,不兼容ES6疑問:這里js文件要在src下,不能在src的js下,否則報錯,why解決: 因為webpack默認的入口是src/index.js文件 所以要改的話,得進行配置,後面會涉及到怎麼配置。在webpack.config.js配置文件中,通過entry節點指定打包的入口。通過output節點指定打包的出口。
繼續訪問

最新發布 iText7高級教程之html2pdf——5.自定義標簽和CSS應用
假設我們想向不同的人發送邀請函。和,html文件內容如下:
繼續訪問

React 編寫網頁聊天界面(仿釘釘)
React 編寫網頁聊天界面(仿釘釘)
繼續訪問

5-前端筆記-CSS-Emmet語法
Emmet語法
繼續訪問
前端
操作系統
Mac

⑥ 微信小程序開發用什麼語言

建議:

微信小程序用戶javascript開發的,你可以看看官網的demo

https://mp.weixin.qq.com/debug/wxadoc/dev/index.html

⑦ 前端可以直接拿到wx.config需要的簽名之類的嗎

config({
debug: true, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會列印。
appId: '', // 必填,公眾號的唯一標識
timestamp: , // 必填,生成簽名的時間戳
nonceStr: '', // 必填,生成簽名的隨機串
signature: '',// 必填,簽名,見附錄1
jsApiList: [] // 必填,需要使用的JS介面列表,所有JS介面列表見附錄2
});
其中主要獲取signature這個參數,官方文檔地址 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115

獲取signature主要分四部

1、使用APPID和APPSecret獲取access_token;
2、使用access_token獲取jsapi_ticket ;
3、用時間戳、隨機數、jsapi_ticket和要訪問的url按照簽名演算法拼接字元串;
4、對第三步的字元串進行SHA1加密,得到簽名。
注意事項:
1、簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
2、簽名用的url必須是調用JS介面頁面的完整URL。
3、出於安全考慮,開發者必須在伺服器端實現簽名的邏輯。
第一步:獲取access_token(需要在伺服器上 )
/**
* 微信小程序獲取accessToken
*
* @author Mr.Wen
* @time 2017年8月28日
*/
public class GetAccessTokenUtil {
// 網頁授權介面
public final static String GetPageAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";
public static Map<String, String> getAccessToken(String appid, String appsecret) {
String requestUrl = GetPageAccessTokenUrl.replace("APPID", appid).replace("SECRET", appsecret);
HttpClient client = null;
Map<String, String> result = new HashMap<String, String>();
String accessToken = null;
try {
client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(requestUrl);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String response = client.execute(httpget, responseHandler);
JSONObject OpenidJSONO = JSONObject.fromObject(response);
accessToken = String.valueOf(OpenidJSONO.get("access_token"));
result.put("accessToken", accessToken);
} catch (Exception e) {
e.printStackTrace();
} finally {
client.getConnectionManager().shutdown();
}
return result;
}
}
第二步:獲取jsapi_ticket
/**
* @author Mr.Wen
* @description 獲取ticket
* @date 2018/3/29
*/
public class JsapiTicketUtil {
// 網頁授權介面
public final static String GetPageAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";

public static Map<String, String> JsapiTicket(String accessToken) {
String requestUrl = GetPageAccessTokenUrl.replace("ACCESS_TOKEN", accessToken);
HttpClient client = null;
Map<String, String> result = new HashMap<String, String>();
try {
client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(requestUrl);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String response = client.execute(httpget, responseHandler);
JSONObject OpenidJSONO = JSONObject.fromObject(response);
String errcode = String.valueOf(OpenidJSONO.get("errcode"));
String errmsg = String.valueOf(OpenidJSONO.get("errmsg"));
String ticket = String.valueOf(OpenidJSONO.get("ticket"));
String expires_in = String.valueOf(OpenidJSONO.get("expires_in"));
result.put("errcode", errcode);
result.put("errmsg", errmsg);
result.put("ticket", ticket);
result.put("expires_in", expires_in);
} catch (Exception e) {
e.printStackTrace();
} finally {
client.getConnectionManager().shutdown();
}
return result;
}
}
第三部:用時間戳、隨機數、jsapi_ticket和要訪問的url按照簽名演算法拼接字元串
String noncestr = WXUtil.generate();//隨機字元串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//時間戳
//4獲取url
//5、將參數排序並拼接字元串
String str = "jsapi_ticket="+ticket+"&noncestr="+noncestr+"×tamp="+timestamp+"&url="+url;
第四部:對第三步的字元串進行SHA1加密,得到簽名,並返回結果
String str = "jsapi_ticket="+ticket+"&noncestr="+noncestr+"×tamp="+timestamp+"&url="+url;
//6、將字元串進行sha1加密
String signature = SHA1.SHA1(str);
Map<String,String> map=new HashMap();
map.put("timestamp",timestamp);
map.put("accessToken",accessToken);
map.put("ticket",ticket);
map.put("noncestr",noncestr);
map.put("signature",signature);

⑧ 使用WebRTC搭建前端視頻聊天室——點對點通信篇

WebRTC給我們帶來了瀏覽器中的視頻、音頻聊天體驗。但個人認為,它最實用的特性莫過於DataChannel——在瀏覽器之間建立一個點對點的數據通道。在DataChannel之前,瀏覽器到瀏覽器的數據傳遞通常是這樣一個流程:瀏覽器1發送數據給伺服器,伺服器處理,伺服器再轉發給瀏覽器2。這三個過程都會帶來相應的消耗,佔用伺服器帶寬不說,還減緩了消息從發送到接收的時間。其實最理想的方式就是瀏覽器1直接與瀏覽2進行通信,伺服器不需要參與其中。WebRTC DataChannel就提供了這樣一種方式。

如果對WebRTC和DataChannel不太了解的同學,可以先閱讀如下文章:

- WebRTC的RTCDataChannel

- 使用WebRTC搭建前端視頻聊天室——信令篇

- 使用WebRTC搭建前端視頻聊天室——入門篇

當然伺服器完全不參與其中,顯然是不可能的,用戶需要通過伺服器上存儲的信息,才能確定需要和誰建立連接。這里通過一個故事來講述建立連接的過程:

不如釣魚去

一些背景:

現在,老劉聽說老姚釣魚技術高超,想和老姚討論釣魚技巧。只要老劉和老姚相互之間知道對方的門牌號以及憑證,就可以串門了:

老劉和老姚相互之間知道了對方的門牌號和小區出入憑證,他們相互之間有什麼需要交流的直接串門就行了,消息不再需要門衛老大爺來代為傳達了

換個角度

我們把角色做一個映射:

於是乎故事就變成了這樣:

這樣,就建立了一個點對點的信道,流程如下所示:

故事

老劉和老姚已經可以相互串門了,經過一段時間的交流感情越來越深。老姚的親友送了20斤葡萄給老姚,老姚決定送10斤給老劉。老姚畢竟年事已高,不可能一次帶10斤。於是乎,老姚將葡萄分成了10份,每次去老劉家串門就送一份過去。

這里可以做如下類比:

這其實就是通過datachannel傳輸文件的方式,首先將文件分片,然後逐個發送,最後再統一的進行組合成一個新的文件

分片

通過HTML5的File API可以將type為file的input選中的文件讀取出來,並轉換成data url字元串。這也就為我們提供了很方便的分片方式:

組合

通過datachannel發送的分片數據,我們需要將其進行組合,由於是data url字元串,在接收到所有包之後進行拼接就可以了。拼接完成後就得到了一個文件完整的data url字元串,那麼我們如何將這個字元串轉換成文件呢?

方案一:直接跳轉下載

既然是個dataurl,我們直接將其賦值給window.location.href自然可以下載,但是這樣下載是沒法設定下載後的文件名的,這想一想都蛋疼

方案二:通過a標簽下載

這個原理和跳轉下載類似,都是使用dataurl本身的特性,通過創建一個a標簽,將dataurl字元串賦值給href屬性,然後使用download確定下載後的文件名,就可以完成下載了。但是很快又有新問題了,稍微大一點的文件下載的時候頁面崩潰了。這是因為dataurl有大小限制

方案三:blob

其實可以通過給a標簽創建blob url的方式來進行下載,這個沒有大小限制。但是我們手上是dataurl,所以需要先進行轉換:

獲得blob後,我們就可以通過URL API來下載了:

這里有幾個點:

1. datachannel其實是可以直接傳送blob的,但是只有ff支持,所以傳data url

2. chrome下載是直接觸發的,不會進行詢問,firefox會先詢問後下載,在詢問過程中如果執行了revokeObjectURL,下載就會取消,囧

升級

如我們所知,WebRTC最有特點的地方其實是可以傳輸getUserMedia獲得的視頻、音頻流,來實現視頻聊天。但事實上我們的使用習慣來看,一般人不會一開始就打開視頻聊天,而且視頻聊天時很消耗內存的(32位機上一個連接至少20M左右好像,也有可能有出入)。所以常見的需求是,先建立一個包含datachannel的連接用於傳輸數據,然後在需要時升級成可以傳輸視頻、音頻。

看看我們之前傳輸的session description,它其實來自Session Description Protocol。可以看到wiki上的介紹:

這意味著什麼呢?我們之前建立datachannel是沒有加視頻、音頻流的,而這個流的描述是寫在SDP裡面的。現在我們需要傳輸視頻、音頻,就需要添加這些描述。所以就得重新獲得SDP,然後構建offer和answer再傳輸一次。傳輸的流程和之前一樣,沒什麼區別。但這一次,我們不需要傳輸任何的ice candidate,這里我曾經遇到了坑,經過國外大大的點撥才明白過來。

Peertc

我將datachannel和websocket組合,實現了一個構建點對點連接的庫Peertc,它提供非常簡潔的方式來建立連接和發送數據、文件和視頻/音頻流,詳情見github。走過路過的記得star一下哦,有什麼bug也非常希望能夠提出來。

最後

WebRTC的點對點方式能夠運用在很多場景:

- 如web qq這種Web IM工具,這就不說了

- 如象棋這種雙人對戰 游戲 ,每一步的數據伺服器時不關心的,所以完全可以點對點發送

- 一對一在線面試、在線教育,這其實是即時通信的一個業務方向

⑨ 前端JS AES加密 後端PHP AES加解密

<!DOCTYPEhtml>

<html>

<head>

    <title>aes demo</title>

</head>

<body>

    <script type="text/javascript" src="./CryptoJS/aes.js"></script>

    <script type="text/javascript" src="./CryptoJS/pad-zeropadding.js"></script>

    <script type="text/javascript">

    text = 'did=12345dg&version=1';

    var key = '';

    key = CryptoJS.enc.Utf8.parse(key);

    var iv = "";

    iv = CryptoJS.enc.Utf8.parse(iv);

    var encrypted = CryptoJS.AES.encrypt(text, key, {

        iv: iv,

        mode: CryptoJS.mode.CBC,

        padding: CryptoJS.pad.ZeroPadding

    }).toString()

    document.write(encrypted);

    </script>

</body>

</html>

後端

public function encrypt2($input = ''){

        $pk = "";

        $iv = substr("", 0, 16);

        // $t = 'T10515';

        $encrypted = ( mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $pk, $input, MCRYPT_MODE_CBC,$iv) );

        return base64_encode($encrypted);

    } 

    public function decrypt2($encrypted){

        $pk = "";

        $iv = substr("", 0, 16);

        // $t = 'T10515';

        // $encrypted = "b7y/JPJFNTfxNVR8H4NNtw==";

        return  mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pk, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv);

    }

可以推斷, js 部分實際只使用了 iv 的 16 位長度

ps:

js加密後默認會base64_encode

使用php解密需要base64_decode後才一致

所以使用js加密和php解密時候需要注意,php端要先base64_decode再解密,例:

js加密的串是$t=b7y/JPJFNTfxNVR8H4NNtw==

php需要

$password= trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $pk,base64_decode( $t), MCRYPT_MODE_CBC, $iv));

則$password才能正確解析出來

需要引入的兩個js文件

ase.js

[javascript] view plain

/*

CryptoJS v3.1.2

code.google.com/p/crypto-js

(c) 2009-2013 by Jeff Mott. All rights reserved.

code.google.com/p/crypto-js/wiki/License

*/

var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},

r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<

32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,

2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},

q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);

a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,

e)).finalize(b)}}});var n=d.algo={};return d}(Math);

(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<

l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"+/="}})();

(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},

_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),

f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,

m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,

E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/

4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);

(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,

l)}})();

CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},

finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=

c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,

e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,

this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,

1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},

decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,

b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();

(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,

16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchele=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchele=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>

8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchele,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchele,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=

d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();

pad-zeropadding.js

/*

CryptoJS v3.1.2

code.google.com/p/crypto-js

(c) 2009-2013 by Jeff Mott. All rights reserved.

code.google.com/p/crypto-js/wiki/License

*/

/**

* Zero padding strategy.

*/

CryptoJS.pad.ZeroPadding = {

    pad: function (data, blockSize) {

        // Shortcut

        var blockSizeBytes = blockSize * 4; 

        // Pad

        data.clamp();

        data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes);

    }, 

    unpad: function (data) {

        // Shortcut

        var dataWords = data.words; 

        // Unpad

        var i = data.sigBytes - 1;

        while (!((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) {

            i--;

        }

        data.sigBytes = i + 1;

    }

}; 

⑩ 前端商品項目管理系統有哪些

1、通用項目管理系統-Worktile(5星)

Worktile 是國內的一款老牌通用項目管理系統,具有非常高的功能成熟度,連續多年登上:36氪-中國企業服軟體金榜-項目管理榜單排名前三(2021 TOP1);它的客戶包含網路、招商銀行、小米等。

Worktile 是一款非常適合中小企業的項目管理系統,因為它具備項目管理、OKR(目標)管理、審批、簡報、IM、網盤等模塊,是一個工具的集合,能同時滿足企業多種工具化管理需求,從而大幅降低成本。

產品能力介紹:

看板式的項目管理,可視化每個項目/任務所處階段;

項目、項目集管理,監控項目進度,管理項目資源;

甘特圖等多種報表視圖,可視化項目進度、資源分配、目標完成情況;

不限量不限速的網盤,管理團隊內部文件;

OKR管理,協助團隊更好的落地OKR,實現管理變革;

日程管理,團隊安排會議和行程

聊天功能,團隊可以在工具內實時溝通,且記錄、文件永久保留;

工具集成,與第三方軟體協作使用;



購買方案:

10人以下免費

支持私有部署、公有雲、定製化開發等;



Worktile 在36氪企服點評的用戶評價:

「Worktile很注重partner之間的溝通,在群聊這些功能做的比較完善,不用切換軟體就可以布置任務、溝通進度,讓我們工作推行更節省時間。它的任務管理也是比較出彩的,整個team都能明確知道工作進程到哪一步,同事們之間的溝通也是比較密切,是一個優秀的辦公工具。總的來說軟體的功能比較完善,可以以一當十,對於運營工作來說真的很節省時間。」——Zoe



官網:Worktile-50萬+團隊都在用的 項目協作工具



2、軟體項目管理系統-PingCode(5星)

在我的測試中,PingCode 國內功能最全面、最好用的IT項目管理軟體之一,也是最推薦的一款IT項目管理工具之一。因為它能夠滿足需求管理、規劃、開發、編碼、構建、測試到發布上線研發全生命周期的管理,並且上手非常容易。

除此以外,PingCode 曾在2021年發布了國內首款研發自動化管理引擎,並且2021年入選軟體研發項目管理榜TOP1。

產品能力介紹:

PingCode 具備8大子產品,覆蓋從客戶反饋、規劃、開發、編碼、構建、測試到發布上線等研發管理全流程管理:

Ship(產品管理):提供工單收集、需求池管理、需求評審、產品路線圖等能力,打通客戶、業務團隊和產研團隊之間的協作,幫助團隊規劃產品路線;

Project(項目管理):支持敏捷開發、瀑布開發、Kanban等國內主流研發管理模式,以及規模化敏捷(SAFe)、項目集等的管理,規范團隊的協作流程;

Testhub(測試管理):提供用例維護、評審,測試計劃、自動化測試、測試報告、缺陷提交等能力;

Wiki(團隊知識庫):提供文檔協作、結構化團隊知識管理等能力,幫助生產和結構化沉澱團隊規范、制度、實踐經驗;

Goals(目標管理):提供戰略目標、團隊目標、個人目標管理,讓所有項目都聚焦於共同的目標,並在更高視野上及時了解企業目標進展;

Flow(研發自動化管理):提供自動化技術,將重復性和煩悶的手動操作變成自動化執行,讓團隊專注高價值生產;

Insight(效能度量):提供研發效能自動採集等能力,通過數據驅動的方式更加准確地評估和改善研發效能;

Access(目錄服務):集成企業級帳號目錄和支持單點登錄,全局統—安全管控;

應用市場:集成了研發中主流的工具,如Git、Jenkins、gitlab等等,實現了不同工具間的數據打通;能夠在飛書、企微等平台使用;



購買方案:

25人以下免費

支持定製化開發、私有部署、公有雲等;



PingCode 在36氪企服點評的用戶評價:

「以前用jira,自從去年Jira在國內停售本地版就開始找替代工具,來來回回嘗試了很多個產品,還是這個能比較好的替代Jira,無論是數據遷移,還是三級需求管理體系、產品路線圖、燃盡圖等可視化報表,或者是打造適合的工作流,都能比較好的滿足。」——Helloworld

官網:PingCode-智能化研發管理工具



3、通用項目管理系統-Asana(4.5星)

Asana 是國外G2網站上評分第一的項目管理軟體,很適合在境外的用戶使用,但國內使用通常會遇到訪問速度慢以及售後服務問題(比如知乎上有人說一個需求等了三年),但它仍然是一個好用的項目管理軟體;

功能/解決的問題:

支持看板管理,讓工作內容的所處階段都一目瞭然;

甘特圖進行有序的項目規劃,及時提醒避免項目延期;

集成電子郵箱等100多種辦公應用;

查看團隊成員的任務和優先順序

支持建立任務依賴關系;

支持設立個人工作管理區,將個人和團隊的項目做出區分;

軟體優勢:

具有非常人性化的功能設計,比如設立私有項目,為敏感工作創造一個安全的空間;

有非常詳細的項目/任務記錄,能查看完成任務的完整歷史記錄以及他們是如何完成的;

在提供軟體的同時,同樣也提供專業的管理咨詢(國內除外)

支持多種語言



4、遠程項目管理系統-Wrike(推薦指數5星)

Wrike 是一款專門為異地團隊協作打造的項目管理軟體,是2018 年FinancesOnline最佳項目管理軟體獎的獲得者。

功能/解決的問題:

支持任務管理、甘特圖、實時的進度提醒等常用的項目管理能力;

除此以外,還支持文檔協作,為團隊的遠程協作提供了非常做的共享能力

工作量管理、電子郵件系統集成、簡報等;

支持各種定製化的報表,用於分析定位管理中的問題;

所有共享活動都可以按時間順序查看,可取消關注,且所有團隊成員都可以查看彼此的活動進度;

軟體優勢:

Wrik除了非常全面的遠程項目協作功能,它還有出色的安全管理方案,以確保除授權人員外,沒有其他人可以訪問到在線資料庫中的信息和其他文件。

對比其他項目管理軟體,它能更輕松的、隨時隨地跟蹤和監控進度;

Wrike 的分類管理方法非常有意思,它能夠在你將項目放在不同的文件夾中的時候不會重復。

它能的項目管理方案讓提醒和需求的響應變得更加及時;



5、軟體項目管理系統-Jira(4.5星)

Jira 在軟體項目管理方面提供了非常成熟的功能,可以適應許多場景,無論是初創公司還是大型企業Jira都能較好的提供服務。Jira支持多種設備並提供靈活的部署方式,可快速完成上線,並允許技術人員或非技術人員進行個性化配置。

雖然2022年在國內停售本地版,一定意義上形成了對國內用戶的禁售,但這也絲毫不影響他是一個好的項目管理系統。

Jira 提供了以下主要能力:

敏捷、瀑布開發管理

強大的自定義工作流

無限添加的自定義欄位

BUG跟蹤

儀錶板

安全管理

團隊活動報告

第三方業務系統集成等

優劣勢:

功能成熟度高,支持高度自定義

成本極高,只適用於大型企業

上手難度大,需要長時間的培訓團隊才可能靈活使用

漢化不完全





四、最佳的5大開源項目管理系統



6、項目管理和缺陷跟蹤工具 Redmine(5星)

Redmine 是一個開源的、基於Web的項目管理和缺陷跟蹤工具。它用日歷和甘特圖輔助項目及進度可視化顯示。同時它又支持多項目管理。Redmine是一個自由開放 源碼軟體解決方案,它提供集成的項目管理功能,問題跟蹤,並為多個版本控制選項的支持。





7、開源項目管理平台 Taiga

Taiga 是一個免費開源,而且功能非常強大的項目管理平台,用於初創企業和敏捷開發團隊。提供一個簡單、漂亮的項目管理工具。

Taiga 採用 Python Django 框架開發,前端基於 AngularJS 實現。

優點:Taiga.io逐漸成長為功能齊全的應用程序,具有多種模式(Kanban,scrum),backlogs,用戶故事以及敏捷開發所需的一切。該應用程序是可定製的,並具有一些敏捷開發中不常見的加成功能,如視頻會議工具和內置維基。

缺點:Taiga.io仍處於測試階段,並一直在與相關問題進行斗爭,比如伺服器有時可能會比蝸牛還慢(盡管不是定期的)。沒有甘特圖功能,有些用戶表示界面很差勁。





8、基於 Web 的項目管理系統 project-open

project-open 是一個基於 Web 的項目管理系統,從整個組織的角度看類似於企業資源計劃enterprise resource planning(ERP)系統。它還可以管理項目檔案、預算、發票、銷售、人力資源和其他功能領域。有一些不同的變體,如用於管理項目公司的專業服務自動化professional services automation(PSA)、用於管理企業戰略項目的項目管理辦公室project management office(PMO)和用於管理部門項目的企業項目管理enterprise project management(EPM)。

project-open[甘特圖編輯器包括按等級劃分的任務、依賴關系和基於計劃工作和分配資源的調度。它不支持資源日歷和非人力資源。]project-open[ 系統非常復雜,其 GUI 可能需要刷新。

project-open是用 TCL 和 JavaScript 編寫的,可用於 Windows 和 Linux。 project-open核心採用 GPLv2 許可證,並具有適用於大公司的專有擴展。

適合於: 需要大量財務項目報告的大中型項目組織。

獨特賣點: project-open是一個綜合系統,可以運行整個項目公司或部門。







9、桌面項目管理系統 ProjectLibre

在開源世界中,ProjectLibre 可能是最接近 MS-Project 的產品。它是一個桌面應用程序,支持所有重要的項目計劃功能,包括資源日歷、基線和成本管理。它還允許你使用 MS-Project 的文件格式導入和導出計劃。

ProjectLibre 非常適合計劃和執行中小型項目。然而,它缺少 MS-Project 中的一些高級功能,並且它的 GUI 並不是最漂亮的。

ProjectLibre 用 Java 編寫,可用於 Windows、Linux 和macOS,並在開源的通用公共署名許可證Common Public Attribution License(CPAL)下授權。ProjectLibre 團隊目前正在開發一個名為 ProjectLibre Cloud 的 Web 產品,並採用專有許可證。

適合於: 負責中小型項目的個人項目管理者,或者作為沒有完整的 MS-Project 許可證的項目成員的查看器。

獨特賣點: 這是最接近 MS-Project 的開源軟體。





10、多項目管理系統 TaskJuggler

TaskJuggler 用於在大型組織中安排多個並行項目,重點是自動解決資源分配沖突(即資源均衡)。

它不是互動式的甘特圖編輯器,而是一個命令行工具,其工作方式類似於一個編譯器:它從文本文件中讀取任務列表,並生成一系列報告,這些報告根據分配的資源、依賴項、優先順序和許多其他參數為每個任務提供最佳的開始和結束時間。它支持多個項目、基線、資源日歷、班次和時區,並且被設計為可擴展到具有許多項目和資源的企業場景。

使用特定語法編寫 TaskJuggler 輸入文件可能超出了普通項目經理的能力。但是,你可以使用 ]project-open[ 作為 TaskJuggler 的圖形前端來生成輸入,包括缺勤、任務進度和記錄的工作時間。當以這種方式使用時,TaskJuggler 就成為了功能強大的假設情景規劃器。

TaskJuggler 用 Ruby 編寫,並且在 GPLv2 許可證下可用於 Windows、Linux 和 macOS。

適合於: 由真正的技術極客管理的中大型部門。

獨特賣點: 它在自動資源均衡方面表現出色。









在本文中,我們探討了開源項目管理系統的優劣勢,盤點了國內外一些開源的項目管理軟體和非開源的項目管理系統,希望以上內容對你有所幫助。