聽說你還在用開發者工具手動上傳小程序,快來試試 miniprogram-ci 提效摸魚

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以?點此加我微信ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列。另外:目前建有江西|湖南|湖北籍前端群,可加我微信進群。

本文是 @NewName 小伙伴參加源碼共讀活動第30期(@tarojs/plugin-mini-ci 小程序上傳代碼 ci)的投稿。

原文鏈接:https://juejin.cn/post/7089819849257385997

此人非同尋常,我發布了多少期源碼共讀、他就基本寫了多少期文章。

Part1學習準備工作

閱讀相關學習資料:

微信小程序CI?:https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html
taro?CI:?https://link.juejin.cn/?target=https%3A%2F%2Ftaro-docs.jd.com%2Ftaro%2Fdocs%2Fnext%2Fplugin-mini-ci%2F
coding自動構建微信小程序:https://help.coding.net/docs/ci/practice/quick/wechat-mini-program.html
小打卡小程序自動化構建:https://www.yuque.com/jinxuanzheng/gvhmm5/uy4qu9#mmmx7

clone源碼:源碼路徑如下:

https://github.com/NervJS/taro/tree/next/packages/taro-plugin-mini-ci

我是把taro整個clone下來的。

Part2源碼學習

1小程序CI的整體流程

首先看index.js:

module.exports?=?require('./dist/index.js').default
module.exports.default?=?module.exports

含義是引入dist文件夾下的index.js文件, 但是剛克隆下來的代碼中并沒有dist文件夾。很容易想到dist文件夾是打包后產生的,所以執行命令:

npm?i
npm?run?build

注意是在taro/packages/taro-plugin-mini-ci目錄下執行 install和build命令:43ca431666abf8d0f3da3fb914fce102.pngbuild之后可以看到有了dist文件夾:1cf0d3eaf792650ab1bcd18d85396b80.png對應目錄下也生成了index.js文件,生成的js文件和原來的ts文件也沒差太多,再加上最近再自學ts,就看index.ts吧(代碼有刪減):

import?{?IPluginContext?}?from?'@tarojs/service'
import?*?as?minimist?from?'minimist'
import?{?CIOptions?}?from?'./BaseCi'
import?WeappCI?from?'./WeappCI'
import?TTCI?from?'./TTCI'
import?AlipayCI?from?'./AlipayCI'
import?SwanCI?from?'./SwanCI'export?{?CIOptions?}?from?'./BaseCi'
export?default?(ctx:?IPluginContext,?pluginOpts:?CIOptions)?=>?{const?onBuildDone?=?ctx.onBuildComplete?||?ctx.onBuildFinishctx.addPluginOptsSchema((joi)?=>?{return?joi.object().keys({/**?微信小程序上傳配置?*/weapp:?joi.object({appid:?joi.string().required(),projectPath:?joi.string(),privateKeyPath:?joi.string().required(),type:?joi.string().valid('miniProgram',?'miniProgramPlugin',?'miniGame',?'miniGamePlugin'),ignores:?joi.array().items(joi.string().required())}),/**?字節跳動小程序上傳配置?*//**?阿里小程序上傳配置?*//**?百度小程序上傳配置?*/swan:?joi.object({token:?joi.string().required(),minSwanVersion:?joi.string()}),version:?joi.string(),desc:?joi.string()}).required()})onBuildDone(async?()?=>?{const?args?=?minimist(process.argv.slice(2),?{boolean:?['open',?'upload',?'preview']})const?{?printLog,?processTypeEnum?}?=?ctx.helperconst?platform?=?ctx.runOpts.options.platformlet?ciswitch?(platform)?{case?'weapp':ci?=?new?WeappCI(ctx,?pluginOpts)breakcase?'tt':ci?=?new?TTCI(ctx,?pluginOpts)breakcase?'alipay':case?'iot':ci?=?new?AlipayCI(ctx,?pluginOpts)breakcase?'swan':ci?=?new?SwanCI(ctx,?pluginOpts)breakdefault:break}if?(!ci)?{printLog(processTypeEnum.WARNING,?`"@tarojs/plugin-mini-ci"?插件暫時不支持?"${platform}"?平臺`)return}switch?(true)?{case?args.open:ci.open()breakcase?args.upload:ci.upload()breakcase?args.preview:ci.preview()breakdefault:break}})
}

代碼的整體流程比較簡單,判斷平臺,創建CI實例, 執行對應的CI。6b418ec16b37cd5e54f3d632b2d466b3.png

可以在啟動Node.js 程序時直接指定命令行參數,例如:

node?index.js?--beep=boop?-t?-z?12?-n5?foo?bar

Node.js 程序啟動后可以直接從process.argv中讀取到參數列表:

console.log(process.argv);
//?['/bin/node',?'/tmp/index.js',?'--beep=boop',?'-t',?'-z',?'12',?'-n5',?'foo',?'bar']

從上述代碼中可以看到,process.argv 變量是一個數組,數組前兩項分別是 node 程序位置和js腳本位置,數組中隨后的元素都是我們啟動Node.js后的參數,這些參數以空格分隔成數組。而minimist 是一個專門用于處理Node.js啟動參數的庫,可以將 process.argv 中的參數列表轉換成更加易于使用的格式:

const?argv?=?require('minimist')(process.argv.slice(2));
console.dir(argv);
//?{?_:?[?'foo',?'bar'?],?beep:?'boop',?t:?true,?z:?12,?n:?5?}

具體使用可以參考https://www.npmjs.com/package/minimist, 使用的時候接收參數和配置對象。

2CI抽象類:BaseCI

packages/taro-plugin-mini-ci/src/BaseCi.ts(代碼有刪減):

import?{?IPluginContext?}?from?'@tarojs/service'
import?*?as?path?from?'path'export?type?ProjectType?=?'miniProgram'?|?'miniGame'?|?'miniProgramPlugin'?|?'miniGamePlugin';/**?微信小程序配置?*//**?頭條小程序配置?*//**?支付寶系列小程序配置?*//**?百度小程序配置?*/export?interface?CIOptions?{/**?發布版本號,默認取?package.json?文件的?taroConfig.version?字段?*/version:?string;/**?版本發布描述,?默認取?package.json?文件的?taroConfig.desc?字段?*/desc:?string;/**?微信小程序CI配置, 官方文檔地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html */weapp?:?WeappConfig;/**?頭條小程序配置, 官方文檔地址:https://microapp.bytedance.com/docs/zh-CN/mini-app/develop/developer-instrument/development-assistance/ide-order-instrument */tt?:?TTConfig;/**?支付寶系列小程序配置,官方文檔地址:https://opendocs.alipay.com/mini/miniu/api */alipay?:?AlipayConfig;/**?百度小程序配置, 官方文檔地址:https://smartprogram.baidu.com/docs/develop/devtools/commandtool/?*/swan?:?SwanConfig;
}export?default?abstract?class?BaseCI?{/**?taro?插件上下文?*/protected?ctx:?IPluginContext/**?傳入的插件選項?*/protected?pluginOpts:?CIOptions/**?當前要發布的版本號?*/protected?version:?string/**?當前發布內容的描述?*/protected?desc:?stringconstructor?(ctx:?IPluginContext,?pluginOpts:?CIOptions)?{this.ctx?=?ctxthis.pluginOpts?=?pluginOptsconst?{?appPath?}?=?ctx.pathsconst?{?fs?}?=?ctx.helperconst?packageInfo?=?JSON.parse(fs.readFileSync(path.join(appPath,?'package.json'),?{encoding:?'utf8'}))this.version?=?pluginOpts.version?||?packageInfo.taroConfig?.version?||?'1.0.0'this.desc?=?pluginOpts.desc?||?packageInfo.taroConfig?.desc?||?`CI構建自動構建于${new?Date().toLocaleTimeString()}`this._init()}/**?初始化函數,會被構造函數調用?*/protected?abstract?_init():void;/**?打開小程序項目?*/abstract?open();/**?上傳小程序?*/abstract?upload();/**?預覽小程序?*/abstract?preview();
}

在抽象類中定義了一些屬性是protected的,意味著可以在本類以及子類中訪問;在constructor中對屬性進行了初始化,并調用初始化函數。然后是定義了一些CI操作的抽象方法。

3CI子類:AlipayCI

packages/taro-plugin-mini-ci/src/AlipayCI.ts

/*?eslint-disable?no-console?*/
import?*?as?miniu?from?'miniu'
import?*?as?path?from?'path'
import?BaseCI?from?'./BaseCi'
import?generateQrCode?from?'./QRCode'/**?文檔地址:https://opendocs.alipay.com/mini/miniu/api */
export?default?class?AlipayCI?extends?BaseCI?{protected?_init?():?void?{if?(this.pluginOpts.alipay?==?null)?{throw?new?Error('請為"@tarojs/plugin-mini-ci"插件配置?"alipay"?選項')}const?{?appPath?}?=?this.ctx.pathsconst?{?fs?}?=?this.ctx.helperconst?{?toolId,?privateKeyPath:?_privateKeyPath,?proxy?}?=?this.pluginOpts.alipayconst?privateKeyPath?=?path.isAbsolute(_privateKeyPath)???_privateKeyPath?:?path.join(appPath,?_privateKeyPath)if?(!fs.pathExistsSync(privateKeyPath))?{throw?new?Error(`"alipay.privateKeyPath"選項配置的路徑不存在,本次上傳終止:${privateKeyPath}`)}miniu.setConfig({toolId,privateKey:?fs.readFileSync(privateKeyPath,?'utf-8'),proxy})}open?()?{const?{?printLog,?processTypeEnum?}?=?this.ctx.helperprintLog(processTypeEnum.WARNING,?'阿里小程序不支持?"--open"?參數打開開發者工具')}async?upload?()?{const?{?chalk,?printLog,?processTypeEnum?}?=?this.ctx.helperconst?clientType?=?this.pluginOpts.alipay!.clientType?||?'alipay'printLog(processTypeEnum.START,?'上傳代碼到阿里小程序后臺',?clientType)//?上傳結果CI庫本身有提示,故此不做異常處理//?TODO?阿里的CI庫上傳時不能設置“禁止壓縮”,所以上傳時被CI二次壓縮代碼,可能會造成報錯,這塊暫時無法處理;?SDK上傳不支持設置描述信息const?result?=?await?miniu.miniUpload({project:?this.ctx.paths.outputPath,appId:?this.pluginOpts.alipay!.appId,packageVersion:?this.version,clientType,experience:?true,onProgressUpdate?(info)?{const?{?status,?data?}?=?infoconsole.log(status,?data)}})if?(result.packages)?{const?allPackageInfo?=?result.packages.find(pkg?=>?pkg.type?===?'FULL')const?mainPackageInfo?=?result.packages.find((item)?=>?item.type?===?'MAIN')const?extInfo?=?`本次上傳${allPackageInfo!.size}?${mainPackageInfo???',其中主包'?+?mainPackageInfo.size?:?''}`console.log(chalk.green(`上傳成功?${new?Date().toLocaleString()}?${extInfo}`))}}async?preview?()?{const?previewResult?=?await?miniu.miniPreview({project:?this.ctx.paths.outputPath,appId:?this.pluginOpts.alipay!.appId,clientType:?this.pluginOpts.alipay!.clientType?||?'alipay',qrcodeFormat:?'base64'})console.log('預覽二維碼地址:',?previewResult.packageQrcode)generateQrCode(previewResult.packageQrcode!)}
}

支付寶小程序子類的_init()方法主要做參數的驗證和設置;open,upload,preview實現了抽象類定義的方法,分別用于打開開發者工具,上傳代碼,預覽二維碼。核心功能的實現依賴于miniu。可以查看相應的資料。627ea6eb73df2b00180d6e704d01639b.png這篇文章介紹了使用MiniU完成CI/CD:https://forum.alipay.com/mini-app/post/35101018。生成二維碼調用了generateQrCode方法:

/***?生產二維碼輸出到控制臺*?@param?url?鏈接地址*/
export?default?function?generateQrCode?(url:?string)?{require('qrcode-terminal').generate(url,?{?small:?true?})
}

generateQrCode實際上是通過三方包qrcode-terminal來實現的。

4CI子類:SwanCI

在SwanCI類中open方法和preview方法的實現與AlipayCI一樣,upload實現有所不同:

async?upload?()?{const?{?outputPath?}?=?this.ctx.pathsconst?{?chalk,?printLog,?processTypeEnum?}?=?this.ctx.helperprintLog(processTypeEnum.START,?'上傳體驗版代碼到百度后臺')printLog(processTypeEnum.REMIND,?`本次上傳版本號為:"${this.version}",上傳描述為:“${this.desc}”`)shell.exec(`${this.swanBin}?upload?--project-path?${outputPath}?--token?${this.pluginOpts.swan!.token}?--release-version?${this.version}?--min-swan-version?${this.pluginOpts.swan!.minSwanVersion?||?'3.350.6'}?--desc?${this.desc}?--json`,?(_code,?_stdout,?stderr)?=>?{if?(!stderr)?{//?stdout?=?JSON.parse(stdout)console.log(chalk.green(`上傳成功?${new?Date().toLocaleString()}`))}})}

上傳的時候執行shell腳本,通過shelljs來實現的 。

5CI子類:WeappCI

WeappCI主要是使用了miniprogram-ci ,具體看一下open, upload, preview方法:open方法(代碼有刪減):

import?*?as?cp?from?'child_process'async?open?()?{const?{?fs,?printLog,?processTypeEnum,?getUserHomeDir?}?=?this.ctx.helperconst?{?appPath?}?=?this.ctx.paths//?檢查安裝路徑是否存在/**?命令行工具所在路徑?*///?檢查是否開啟了命令行cp.exec(`${cliPath}?open?--project?${appPath}`,?(err)?=>?{if?(err)?{printLog(processTypeEnum.ERROR,?err.message)}})}

open方法用于打開開發者工具,通過node.js child_process的exec執行命令。upload方法:

import?*?as?ci?from?'miniprogram-ci'async?upload?()?{const?{?chalk,?printLog,?processTypeEnum?}?=?this.ctx.helpertry?{printLog(processTypeEnum.START,?'上傳體驗版代碼到微信后臺')printLog(processTypeEnum.REMIND,?`本次上傳版本號為:"${this.version}",上傳描述為:“${this.desc}”`)const?uploadResult?=?await?ci.upload({project:?this.instance,version:?this.version,desc:?this.desc,onProgressUpdate:?undefined})if?(uploadResult.subPackageInfo)?{const?allPackageInfo?=?uploadResult.subPackageInfo.find((item)?=>?item.name?===?'__FULL__')const?mainPackageInfo?=?uploadResult.subPackageInfo.find((item)?=>?item.name?===?'__APP__')const?extInfo?=?`本次上傳${allPackageInfo!.size?/?1024}kb?${mainPackageInfo???',其中主包'?+?mainPackageInfo.size?+?'kb'?:?''}`console.log(chalk.green(`上傳成功?${new?Date().toLocaleString()}?${extInfo}`))}}?catch?(error)?{console.log(chalk.red(`上傳失敗?${new?Date().toLocaleString()}?\n${error.message}`))}}

上傳代碼的方法使用miniprogram-ci的upload方法,得到結果信息后根據分包信息來提示整體包大小和主包大小。preview方法(代碼有刪減):

async?preview?()?{const?{?chalk,?printLog,?processTypeEnum?}?=?this.ctx.helpertry?{printLog(processTypeEnum.START,?'上傳開發版代碼到微信后臺并預覽')const?uploadResult?=?await?ci.preview({project:?this.instance,version:?this.version,desc:?this.desc,onProgressUpdate:?undefined})if?(uploadResult.subPackageInfo)?{const?allPackageInfo?=?uploadResult.subPackageInfo.find((item)?=>?item.name?===?'__FULL__')const?mainPackageInfo?=?uploadResult.subPackageInfo.find((item)?=>?item.name?===?'__APP__')const?extInfo?=?`本次上傳${allPackageInfo!.size?/?1024}kb?${mainPackageInfo???',其中主包'?+?mainPackageInfo.size?+?'kb'?:?''}`console.log(chalk.green(`上傳成功?${new?Date().toLocaleString()}?${extInfo}`))}}?catch?(error)?{console.log(chalk.red(`上傳失敗?${new?Date().toLocaleString()}?\n${error.message}`))}
}

preview方法使用的是miniprogram-ci的preview方法, 得到結果信息后根據分包信息來提示整體包大小和主包大小。

6CI子類:TTCI

TTCI使用tt-ide-cli來完成預覽和上傳,使用child_process的exec來完成打開開發者工具的功能。open(代碼有刪除):

open?()?{if?(fs.existsSync(projectPath))?{console.log(chalk.green(`open?projectPath:?${projectPath}`))const?openPath?=?`${openCmd}?path=${projectPath}`cp.exec(openPath,?(error)?=>?{if?(!error)?{console.log('打開IDE成功',?openPath)}?else?{console.log(chalk.red('打開IDE失敗',?error))}})}}

這里open方法也是通過node.js child_process的exec執行命令。upload(代碼有刪除):

import?*?as?tt?from?'tt-ide-cli'
async?upload?()?{try?{await?tt.upload({entry:?outputPath,version:?this.version,changeLog:?this.desc})}?catch?(error)?{}}

上傳代碼使用tt-ide-cli的upload方法。preview(代碼有刪除):

import?*?as?tt?from?'tt-ide-cli'async?preview?()?{try?{await?tt.preview({entry:?outputPath,force:?true,small:?true})}?catch?(error)?{console.log(chalk.red(`上傳失敗?${new?Date().toLocaleString()}?\n${error.message}`))}}

生成預覽二維碼使用了tt-ide-cli的upload方法。

Part3總結

1.taro小程序ci的核心代碼邏輯是:判斷平臺,創建CI實例, 執行對應的CI。2.不同平臺對應不同的CI類,但都繼承了基礎的CI抽象類,實現了抽象類聲明的open,upload和preview方法。3.實現具體的open,upload和preview方法時根據對應小程序是否提供了命令行工具,有用到miniu,tt-ide-cli,miniprogram-ci,還有的使用shelljs,qrcode-terminal,以及child_process來執行命令。


cf714cd4d9dfebc36933cc7720c8b8ed.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助4000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

4347d3951e26844834b0a0afaa8676cf.png

掃碼加我微信 ruochuan02、拉你進源碼共讀

今日話題

目前建有江西|湖南|湖北?籍 前端群,想進群的可以加我微信 ruochuan12?進群。分享、收藏、點贊、在看我的文章就是對我最大的支持~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274697.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274697.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274697.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ucla ai_UCLA的可持續性:用戶體驗案例研究

ucla aiRole: UX Researcher / UX Designer / Critical-thinker角色: UX研究人員/ UX設計人員/批判性思維者 Scope: 4 weeks, March — March 2020范圍: 4周,2020年3月至2020年3月 What I Did: UX Research, Speculative Design, Product D…

推薦10個國外圖片素材網站

下面,為大家帶來的 10 個國外精選的墻紙網站。 NO.1 Social Wallpapering 給我帶來全新的體驗, Web2.0 一個熱門話題。可以讓我自由的評選自己喜歡的東西,投票、評論、沉淪等等,對于網站內喜歡的東西可以做出自己喜歡的方式。進入…

大三的小白同學是如何拿到字節offer的,經驗分享

這是來自大三邵小白同學的投稿。原文鏈接:https://juejin.cn/post/7092806181856657445很多時候我們容易羨慕別人成功了,卻往往沒有看到別人背后的努力。1前言大家好,我是邵小白,一個長沙某不知名雙非的大三學生。今年三月份來到杭…

UNIBO大學博物館網絡設計—品牌重塑和數字產品設計

Brief / Redesign the Visual Identity of the University of Bologna Museum Network (SMA) and apply the new designs to a Digital Product簡介/重新設計博洛尼亞大學博物館網絡(SMA)的視覺識別,并將新設計應用于數字產品 Period / Mar 2020 — June 2020期間/…

oracle中的sga和pga

oracle中的sga包含了幾個主要的部分 1.shared pool 共享池 2.database buffer cache 數據庫高速緩沖區 3.redo log buffers 重做日志緩沖區 4.large pool 大池 5.java pool java池 a.shared pool: oracle shared pool包括library cache(庫緩存)和dictionary cache(數據字典高速…

進來做幾道 JavaScript 基礎題找找自信?

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以 點此加我微信ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

人物肖像速寫_驕傲家庭:肖像項目

人物肖像速寫2020 has been a solemn, transformative year. Pride month takes place in the context of a groundswell up-rising against racism and police brutality and in the continued isolation of COVID-19.2020年是莊嚴,變革的一年。 驕傲月的發生是在反…

答讀者問:錢和成長,哪個更重要?

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以 點此加我微信ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

ui設計顏色的使用_UI設計中顏色使用的10條原則

ui設計顏色的使用重點 (Top highlight)1.顏色術語 (1. Color Terminology) Color terminology forms our foundation of color knowledge. Think of color terms like hue, tint, and shade as tools that we can employ to develop unique color palettes.顏色術語構成了我們顏…

Chrome插件:網易云音樂聽歌識曲

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以 點此加我微信ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

五大常用算法之四:回溯法

1、概念 回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。 回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標…

如何設置ad18捕捉圖標_圖標設計中的像素捕捉

如何設置ad18捕捉圖標More in the iconography series:? Foundations of Iconography? 7 Principles of Icon Design? 5 Ways to Create a Settings Icon? Icon Grids & Keylines Demystified? 3 Classic Icon FamiliesWe all want our designs to display sharp on a…

React Hooks 原理與最佳實踐

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以 點此加我微信ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

BW:BW增量更新方法(假增量)

1 說說假增量 我們都知道,對于BW來說,很多ECC的標準數據源自帶了增量更新功能,每天各種憑證產生的增量數據會自動堆積到增量隊列里,然后BW端做一個增量信息包按天把這些增量抽取到數據倉庫里,非常輕松自然,…

插圖 引用 同一行兩個插圖_為什么插圖是產品的重要組成部分

插圖 引用 同一行兩個插圖“Hi, my name is Ludmila and I’m a UX/UI designer”“嗨,我叫Ludmila,我是UX / UI設計師” “Hi, Ludmila”“嗨,路德米拉” “Welcome”“歡迎” Not anonymously at all, I’ve been doing UX/UI design fo…

如果是你你會如何重新設計和定義維基百科(wikipedia)?

日期:2012-8-11 來源:GBin1.com 最近一家設計公司發布了一個關于如何重新定義和設計維基百科的網站,在這里網站里詳細的刨析了如何重新設計維基百科的話,如何做品牌設計和網站設計,整個設計過程都使用非常詳細的文檔說…

祖父元素_幫助祖父母建立Skype帳戶的UX經驗教訓

祖父元素“Empathy is a key part of a UX designers arsenal”, they say. It’s drilled into our heads that we need to be thinking about our user, about their journey, about what works best for them. And it does feel empowering to boast of empathy, inside vis…

ECSHOP批量添加商品到購物車

Ecshop是一款開源的網上商店系統,在我心目中可以算得上網上商城界的Wordpress了。 本文介紹如何實現在ecshop中批量添加商品到購物車。 大家都知道,默認的ecshop只能單件點擊“添加到購物車”(Add to Cart)實現一件一件的添加商品…

2022年CSS的發展如何?

大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以 點此加我微信ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

分布式實物實現方式_這是您完成實物產品設計任務的方式

分布式實物實現方式You’ve come to the last stages of an interview. There’s only one thing left to do: the dreaded take home design assignment.您已經到達面試的最后階段。 只剩下一件事要做: 可怕的帶回家的設計任務。 This is the hard part of any in…