“消失”的這倆個(gè)月里大年,雖然我的技術(shù)博客沒有更新换薄,卻也發(fā)生了很多事情值得自己凝聚。
先是拜讀了趙皓陽的新書《生而貧窮》翔试,書中用大量的客觀數(shù)據(jù)描繪了一個(gè)驅(qū)離的世界——貧者越貧與階級(jí)固化轻要。其中讓我感悟到,當(dāng)我們大學(xué)生覺得自己被高成就人才“碾壓”而感嘆自己的命運(yùn)之時(shí)垦缅,還有很多根本走不到高考這一步的孩子們填充著金字塔的底層冲泥;國(guó)內(nèi)互聯(lián)網(wǎng)巨頭公司即使形成了壟斷資本鏈,不斷貪婪地吞噬著新興的中小型軟件公司壁涎,人民日?qǐng)?bào)一批判凡恍,騰訊市值也得蒸發(fā)個(gè)千百億。
再是經(jīng)歷了自己喜歡的自媒體公號(hào)被整肅的痛心過程怔球,其中包括對(duì)“毒舌電影”的封殺和對(duì)趙皓陽的公號(hào)的一個(gè)月禁言咳焚。難怪以特立獨(dú)行為特點(diǎn)的自由主義者李敖先生,在 05 年來大陸進(jìn)行神州文化之旅時(shí)曾表示愿意拋棄自己的自由主義庞溜,來換我國(guó)憲法中白紙黑字的“言論自由”革半,現(xiàn)在看來,這條路還挺久流码。
話說回重點(diǎn)又官,當(dāng)然要凝聚一下這倆個(gè)月我對(duì)前端項(xiàng)目的實(shí)踐心得,也是本文的主旨——曾經(jīng)大談方法論的我漫试,在實(shí)踐過程中如何快速填坑六敬,又如何感悟到以后要避免像這次一樣在編程上的大量“搬磚”?
“消失”的這倆個(gè)月里驾荣,我的前端項(xiàng)目如何從零開始外构。
項(xiàng)目背景及功能拆解
一切之前,先看一下提交作品階段由我原聲解說的真實(shí)系統(tǒng)演示與功能詳解的視頻播掷,如下审编。
[圖片上傳失敗...(image-39199-1509644428516)]](http://upload-images.jianshu.io/upload_images/2558748-b5c8c5142d99e406.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可見這場(chǎng)中國(guó)軟件杯競(jìng)賽我們選的競(jìng)賽題目是基于微信公眾號(hào)開發(fā)的借閱伴侶,其中的核心需求如下:
- 用戶可以進(jìn)入借閱書城搜書歧匈、借書垒酬,包括掃碼搜書
- 用戶可以收藏、預(yù)訂書籍并及時(shí)得到公眾號(hào)的主推提醒
- 用戶可以修改信息或查看自己的搜書、藏書勘究、預(yù)訂書籍的記錄
- 管理員需要授權(quán)用戶借閱此書和驗(yàn)收用戶歸還書籍并確認(rèn)無損
- 管理員需要錄入相關(guān)書籍信息矮湘,管理管理員用戶
原型制作
有了上示所列的功能,根據(jù)微信公眾號(hào)服務(wù)的是手機(jī)用戶的特點(diǎn)口糕,不難設(shè)計(jì)出一個(gè)通用的手機(jī)端風(fēng)格的原型缅阳。原型底下的導(dǎo)航欄中的四個(gè)功能,便是整個(gè)應(yīng)用的核心:圖書導(dǎo)航景描、書庫搜書十办、借閱書車和個(gè)人中心。這里使用“墨刀”原型設(shè)計(jì)工具伏伯,原型設(shè)計(jì)工具能仿真交互上的一些操作橘洞,最終還能將結(jié)果導(dǎo)出成 HTML 放置到服務(wù)器上,方便給他人發(fā)送鏈接進(jìn)行功能交流说搅。
架構(gòu)項(xiàng)目
能在一個(gè)競(jìng)賽中展現(xiàn)自己的特點(diǎn)想必一定是好事炸枣,剛開始構(gòu)想項(xiàng)目所需要用到的技術(shù)棧的時(shí)候,一股腦把我知道的(都沒實(shí)戰(zhàn)過的)所有技術(shù)點(diǎn)都諾列了出來弄唧,每個(gè)技術(shù)點(diǎn)各有分工适肠,一時(shí)美哉,如下候引。
- Bower 做 JavaScript 的包依賴管理
- JQuery 封裝 DOM 操作并進(jìn)行跨域請(qǐng)求
- NPM 做 Node.js 的包依賴管理(沒用上)
- ESLint 做代碼風(fēng)格規(guī)范檢測(cè)(未實(shí)現(xiàn))
- Grunt 啟動(dòng) Karma 統(tǒng)一項(xiàng)目管理(未實(shí)現(xiàn))
- Istanbul 檢查單元測(cè)試代碼覆蓋率(有問題)
- Jasmine 做單元測(cè)試(有問題)
- JSDoc 規(guī)范代碼注釋風(fēng)格(未實(shí)現(xiàn))
- Karma 自動(dòng)化完成單元測(cè)試(有問題)
- Webpack 最終打包整個(gè)項(xiàng)目文件(未實(shí)現(xiàn))
- Yeoman 最后封裝成一個(gè)項(xiàng)目原型模板(未實(shí)現(xiàn))
除了前倆個(gè)技術(shù)點(diǎn)使用起來真的很簡(jiǎn)單外侯养,別的技術(shù)點(diǎn)在嘗試的過程中都遇到阻礙,用 Karma 自動(dòng)化完成 Jasmine 單元測(cè)試并依靠 Istanbul 將測(cè)試覆蓋率輸出成 HTML 這個(gè)本來是實(shí)現(xiàn)成功了的澄干,但引入 JQuery 后逛揩,Jasmine 默認(rèn)不識(shí)別 JQuery 的 $ 符號(hào)及其各種函數(shù),這幾個(gè)技術(shù)點(diǎn)便在最后暫時(shí)被拋棄麸俘。
其實(shí)辩稽,Karma、Jasmine从媚、Istanbul 被拋棄的主要原因是自己還不習(xí)慣逞泄,或者說不會(huì),先寫測(cè)試再寫程序拜效,也就是測(cè)試驅(qū)動(dòng)開發(fā)喷众。雖然測(cè)試驅(qū)動(dòng)開發(fā)在去年暑假的特訓(xùn)營(yíng)里學(xué)過,但久久的未深入和這次項(xiàng)目功能的復(fù)雜性自己一時(shí)無法預(yù)測(cè)完畢紧憾,才導(dǎo)致自己剛開始就先寫了注冊(cè)時(shí)的輸入框驗(yàn)證的測(cè)試代碼到千,后期的所有功能代碼都是想到就直接跳過測(cè)試來寫實(shí)際代碼,后期引入 JQuery 時(shí)遇到 Jasmine 默認(rèn)不支持 JQuery 才發(fā)覺測(cè)試代碼的坑已經(jīng)很難及時(shí)彌補(bǔ)回來了稻励,期末和競(jìng)賽就快要截止這兩件事更重要父阻。
最后的項(xiàng)目目錄是這樣的愈涩,鑒于本次項(xiàng)目開發(fā)過程構(gòu)建在 Git 上望抽,開源許可證書加矛、說明文檔、Git 忽略文件都必不可少煤篙;Bower 管理器需要 bower.json 配置文件并會(huì)據(jù)此生成 bower_components 依賴庫斟览、Node 包管理器需要 package.json 配置文件并回?fù)?jù)此生成 node_modules 模塊。prototype 放原型設(shè)計(jì)工具導(dǎo)出的有交互功能的 HTML 頁面辑奈,項(xiàng)目最后合并后端代碼時(shí)導(dǎo)入 java_api 和 php_wechat 庫苛茂,就是最終的整個(gè)目錄結(jié)構(gòu)了。
├── LICENSE # 開源許可證書
├── README.md # 項(xiàng)目說明文檔
├── app # 移動(dòng)端前端項(xiàng)目正式源碼
│ ├── admin # 移動(dòng)端管理 APP 源代碼
│ └── user # 移動(dòng)端用戶借閱官網(wǎng)源代碼
├── bower.json # Bower 前端庫依賴關(guān)系
├── bower_components # Bower 前端依賴庫(.gi)
│ └── 相關(guān)配置詳見 [bower.json](./bower.json)
├── images # 公用圖片庫
├── java_api # 服務(wù)端搜索引擎接口源碼
├── karma.conf.js # Karma 自動(dòng)化完成單元測(cè)試配置
├── node_modules # Node 安裝模塊(.gi)
│ └── 相關(guān)配置詳見 [package.json](./package.json)
├── package.json # Node 配置
├── pc # 電腦端前端項(xiàng)目正式源代碼
│ └── admin # 桌面端管理系統(tǒng)源代碼
├── prototype # 原型圖 HTML 版
├── unit-test # 前端單元測(cè)試
├── php_wechat # 微信端源代碼
└── .gitignore # Git 版本管理忽略信息說明文件
根據(jù)項(xiàng)目要求鸠窗,我們需要開發(fā)管理員手機(jī)端妓羊、管理員電腦端和用戶手機(jī)端——統(tǒng)一起來就是手機(jī)端和電腦端,手機(jī)端包括用戶模塊和管理員模塊稍计,不難架構(gòu)出 app 躁绸、app/admin、app/user 和 pc/admin 的文件目錄臣嚣,其中這三個(gè)目錄里的子目錄都是這樣的:
├── *.html # 低耦合的 HTML 頁面
├── css # CSS 源代碼
├── images # 背景圖净刮、LOGO 等
└── js # JS 源代碼
因?yàn)闆]用上測(cè)試和 Webpack 等技術(shù),也就沒有了其相應(yīng)目錄硅则。
UI 開發(fā)
剛剛提到了制作出的原型能導(dǎo)出 HTML淹父,那我們豈不美哉?把原型設(shè)計(jì)工具當(dāng)成像 DreamWeaver 一樣的可視化前端開發(fā)工具真的可以嗎怎虫?我們來看看導(dǎo)出的源碼暑认。
源碼里能看到項(xiàng)目被 webpack 打包,況且很多 CSS 也可能是用 SASS 等預(yù)處理器編譯后的結(jié)果大审,并不是真正易懂的源碼蘸际,前端開發(fā)人員依然需要運(yùn)用 UI 技術(shù)從原生程序搭建自己的項(xiàng)目。
HTML 實(shí)現(xiàn)
在 app/user饥努、app/admin捡鱼、pc/admin 中的結(jié)構(gòu)剛剛已經(jīng)介紹,HTML 就分別地放在這些目錄下酷愧。目錄結(jié)構(gòu)中提到的低耦合驾诈,要求我們將 CSS 寫到 CSS 文件,將 JS 寫到 JS 文件中溶浴,最后再分別合并 CSS 文件和 JS 文件到自己的文件夾中即可乍迄。方便起見,剛剛說到的三個(gè)項(xiàng)目目錄結(jié)構(gòu)再次放到這里士败。
├── *.html # 低耦合的 HTML 頁面
├── css # CSS 源代碼
├── images # 背景圖闯两、LOGO 等
└── js # JS 源代碼
在我這次的 HTML 實(shí)現(xiàn)過程中褥伴,主要就在寫 DIV 標(biāo)簽及其用到的 Class 屬性名、偶爾修改一下外鏈漾狼。在剛用戶進(jìn)入的圖書導(dǎo)航的首頁上重慢,我們可以在不寫 CSS 的情況下構(gòu)建出下列 DIV 層次結(jié)構(gòu)。其中我寫的這個(gè)可能并不是最優(yōu)方案逊躁,甚至稱不上好似踱,但它達(dá)到了能用的效果,并讓我及時(shí)的提交競(jìng)賽作品稽煤,后期改進(jìn)即可核芽。
- 圖書導(dǎo)航頁原型圖:
- 圖書導(dǎo)航頁 DIV 層次結(jié)構(gòu)
其中注釋里說的“這里將被 ajax”加載、“這是書名等”可以在后期才開發(fā) JS 代碼需要填充頁面時(shí)再加上酵熙,前期寫一個(gè)死的文字模板反而方便在開發(fā) CSS
代碼時(shí)及時(shí)布局效果轧简。
CSS 實(shí)現(xiàn)
實(shí)現(xiàn) CSS 代碼時(shí),這里使用了一個(gè)看起來不那么方便的選擇器方式 —— 從和當(dāng)前 DIV (也可以看做“組件”)直接相關(guān)的根 DIV 開始向下寫匾二,CSS 的優(yōu)先級(jí)并不需要這樣寫哮独,但這樣寫好處之一是能快速看出層級(jí)關(guān)系,修改相應(yīng)代碼假勿。這是我從“海投網(wǎng)”中借鑒的借嗽,以后學(xué) SASS 或重構(gòu) UI 時(shí)可以考慮嘗試另一種風(fēng)格,漸漸找到較為合適自己的那一個(gè)转培。
/* 輪播圖 */
.mSlideShowWrap {
margin: 0;
padding: .2rem 0 0 0;
height: 8.6rem;
width: 100%;
display: block;
}
.mSlideShowWrap .mNewBooksSideBar {
height: 8.6rem;
width: 1.4rem;
border: #bbb solid medium;
display: block;
float: left;
background-color: #fff;
}
.mSlideShowWrap .mNewBooksSideBar .mSideBarTitle {
margin: 0;
padding: 0 0 .2rem .1rem;
height: 2.15rem;
width: auto;
display: block;
color: #000;
}
由于之前淺嘗輒止 CSS恶导,在其實(shí)現(xiàn)過程反而不會(huì)使用 position、float 等功能浸须,布局方面多用 CSS3 的 flex 實(shí)現(xiàn)惨寿,快速學(xué)習(xí) flex 之后的大部分寫 CSS 的時(shí)間,都在搬 flex 的磚删窒,這就是我搬磚的由來裂垦,卻因之后的 JavaScript 編程實(shí)戰(zhàn)而“高潮”。
邏輯與接口實(shí)現(xiàn)(JavaScript 編程)
大前端時(shí)代到來肌索,簡(jiǎn)單的前端界面設(shè)計(jì)人員早已飽和蕉拢,前端技術(shù)也迎來了新的高度,很多時(shí)候我們是將前端開發(fā)者和 JavaScript 程序員掛鉤起來的诚亚,然而事實(shí)上并不是這樣晕换。前端工程師起初多叫重構(gòu)工程師,從《Web 全棧工程的自我修養(yǎng)》作者余果的求職經(jīng)歷可以看到站宗,最開始前端就是偏向設(shè)計(jì)和交互的闸准,就是用來一絲不差的實(shí)現(xiàn)高保真原型圖,現(xiàn)在用戶體驗(yàn)的要求上來了梢灭,異步請(qǐng)求的需求量上來了夷家,JavaScript 才漸漸成了前端工程師的必備技能蒸其,甚至漸漸的,“掌握至少一門后端語言”也加入到了前端工程師的招聘需求中库快。
看來又多說了幾句摸袁,這次競(jìng)賽前端項(xiàng)目的最后就是用 JavaScript 進(jìn)行邏輯與接口的實(shí)現(xiàn)。我們來分別談一談缺谴。
JavaScript 邏輯實(shí)現(xiàn)
邏輯實(shí)現(xiàn)包括輸入框信息的驗(yàn)證但惶、頁面的跳轉(zhuǎn)和用戶登錄狀態(tài)的保存等耳鸯。在引入 JQuery 后湿蛔,這一切開發(fā)變得簡(jiǎn)單起來。
下面是一個(gè)用 JQuery 快速實(shí)現(xiàn)的輸入框驗(yàn)證代碼示例县爬。
var password = $("input:eq(0)").val();
var newPassword = $("input:eq(1)").val();
var rePassword = $("input:eq(2)").val();
var identity = $("input:eq(3)").val();
var flag = 1; // 1 代表判斷通過
if (!checkIDCard(identity)) flag = 0, tips = "不符合正確的身份證號(hào)格式";
if (!compareTwoPassWord(newPassword, rePassword)) flag = 0, tips = "密碼與重復(fù)密碼不一致";
if (!checkPassword(rePassword)) flag = 0, tips = "不符合正確的重復(fù)密碼格式(6~13位)";
if (!checkPassword(newPassword)) flag = 0, tips = "不符合正確的新密碼格式(6~13位)";
if (!checkPassword(password)) flag = 0, tips = "不符合正確的舊密碼格式(6~13位)";
下面是一個(gè)根據(jù)邏輯需求進(jìn)行頁面跳轉(zhuǎn)的代碼示例阳啥。
if (data["IsSuccess"]) {
$(".pContentMessage").text("錄入成功!正在重新加載");
setTimeout(function () {
window.location.href = "admin_center.html?tab=0";
}, 1000);
}
JavaScript 接口實(shí)現(xiàn)
前后端分離的項(xiàng)目中财喳,后端只用注重接口的實(shí)現(xiàn)即可察迟,一個(gè)一個(gè)很短的接口鏈接及其參數(shù)說明、返回結(jié)果說明拋給前端耳高,前端就要進(jìn)行各種相應(yīng)的邏輯編程扎瓶、UI 編程,正想不通泌枪,為什么在我周圍概荷,學(xué)前端的還是女生多。當(dāng)然啦碌燕,前端業(yè)界的領(lǐng)頭人物性別比例就不多說了误证。我曾在一個(gè)前端微信群中聊過這類有關(guān)性別平等的話題,偏見還是很多的修壕,就在我們身邊愈捅,這里就不多多說來。啊慈鸠,前端和后端也平等蓝谨。
一言不合,后端拋給你個(gè)接口青团,長(zhǎng)得還很奇怪的樣子:
補(bǔ)全圖書信息
- 請(qǐng)求地址
- 請(qǐng)求類型
HTTP:POST
- 參數(shù)
參數(shù)名稱 | 參數(shù)說明 | 必填 |
---|---|---|
isbn | 書的isbn號(hào) | Y |
- 結(jié)果示例
{
"next": "",
"count": 1,
"books": [
{
"bId": null,
"bName": "大型網(wǎng)站系統(tǒng)與Java中間件開發(fā)實(shí)踐",
"sId": null,
"cId": null,
"spell": null,
"initial": null,
"imgurl": "https://img1.doubanio.com/mpic/s27269837.jpg",
"isbn": "9787121227615",
"author": "曾憲杰",
"count": null
}
]
}
- 返回參數(shù)說明
next:下一頁得next值譬巫,""表示沒有下一頁
count:books中含有幾本書
books:book的集合
book{
bId:書籍唯一標(biāo)識(shí)
bName:書籍名稱
sId:書庫的標(biāo)識(shí)ID
cId:書籍類型的標(biāo)識(shí)ID
spell:全拼
initial:首字母
imgurl:書籍圖片路徑
isbn:書籍的isbn號(hào)
author:作者
count:書庫中該書的總量
}
當(dāng)然,前端進(jìn)行數(shù)據(jù)訪問的跨域權(quán)限需要后端支持壶冒,具體怎么支持這就不是前端的事了缕题。當(dāng)后端有上述接口示例交給前端時(shí),如果不是需要帶有 Cookie 等參數(shù)的接口胖腾,前端可以直接用代碼實(shí)戰(zhàn)訪問烟零,根據(jù)瀏覽器開發(fā)者工具里的具體報(bào)錯(cuò)信息來修改代碼瘪松;更推薦在寫跨域代碼前先用 postman 這類的可視化 HTTP 請(qǐng)求工具/ API 測(cè)試工具來測(cè)試。
編寫跨域請(qǐng)求代碼時(shí)锨阿,需要一些異步回調(diào)相關(guān)的知識(shí)宵睦,當(dāng)請(qǐng)求結(jié)果返回時(shí)觸發(fā)回調(diào)函數(shù),進(jìn)行相應(yīng)的操作墅诡。這里用道德回調(diào)函數(shù)壳嚎,主要就是頁面跳轉(zhuǎn)和數(shù)據(jù)渲染兩個(gè)功能,例如一個(gè)完整的跨域請(qǐng)求函數(shù)末早,并將返回結(jié)果渲染到頁面的代碼可以是下面這個(gè)樣子烟馅。
function finishBook () {
// 隱藏詳情頁
$(".pContentDetailWrap:eq(0)").hide();
$(".pContentSubmitWrap:eq(0)").hide();
var isbn = $("input:eq(0)").val();
var post_data = {
"isbn": isbn
};
if (!isbn) {
$(".pContentMessage").text("ISBN 號(hào)不能為空");
return;
}
var post_url = "https://wwwxinle.cn/Book/public/index.php/index/Manager/infoBook";
$.post(post_url, post_data, function (data, status) {
data = JSON.parse(data);
if (data["count"] == 0) {
$(".pContentMessage").text("沒有找到相關(guān)信息");
return;
}
var book = data["books"][0];
$(".pContentDetailLeftWrap img").attr("src", book["imgurl"])
$(".pContentDetailItemWrap:eq(0) input").val(book["bName"]);
$(".pContentDetailItemWrap:eq(3) input").val(book["author"]);
$(".pContentDetailItemWrap:eq(4) input").val(1);
$(".pContentDetailHiddenWrap").text(JSON.stringify(book));
$(".pContentDetailWrap:eq(0)").show();
$(".pContentSubmitWrap:eq(0)").show();
});
}
回調(diào)成功,一個(gè)完整的跨域流程和前端對(duì)接口的實(shí)現(xiàn)流程就到了收尾之處然磷≈3茫回調(diào)函數(shù)還有很多其它的注意點(diǎn),比如回調(diào)函數(shù)里的變量值不能被回調(diào)函數(shù)外訪問的時(shí)候需要注意什么等姿搜,遇到這些坑時(shí)可以選擇盡可能將外部變量及其功能放入內(nèi)部實(shí)現(xiàn)寡润,或用其他更前沿的技術(shù)來實(shí)現(xiàn)。
整體架構(gòu)回顧
之前一直在說前端項(xiàng)目的構(gòu)建過程舅柜,在我們團(tuán)隊(duì)三人的整體分工中梭纹,也是有其整體框架:Web 前端和沒有數(shù)據(jù)庫的 PHP 后端進(jìn)行請(qǐng)求,PHP 后端和有數(shù)據(jù)庫的 JAVA 數(shù)據(jù)接口進(jìn)行請(qǐng)求致份,JAVA 數(shù)據(jù)接口直接訪問數(shù)據(jù)庫——沃变抽,其實(shí)隊(duì)友用的是基于 Apache Lucene(TM) 的開源搜索引擎,只不過我當(dāng)時(shí)看到他們進(jìn)行 SQL 操作了知举,不知者無罪~
獨(dú)特吧瞬沦?Node.js 除了做后端,也可以做“前臺(tái)”雇锡,就是這時(shí) Node 不操作數(shù)據(jù)庫逛钻,操作數(shù)據(jù)庫的還是典型的后端語言如 PHP、JAVA锰提、Python 等曙痘;那么在這個(gè)項(xiàng)目中,PHP 微信端有點(diǎn)“前臺(tái)”的感覺立肘,主要承載著每個(gè)人專屬微信號(hào)信息的獲取和公眾號(hào)的主推功能边坤,并向 JAVA 后端進(jìn)行數(shù)據(jù)訪問。Web 前端只和 PHP 微信端進(jìn)行聯(lián)絡(luò)谅年。
如果可以和 MVC 架構(gòu)聯(lián)系起來的話茧痒,Web 前端是大 V,PHP 微信端是大 C融蹂,JAVA 服務(wù)端是大 M旺订;其中每個(gè)大 V弄企、大 C、大 M 都有自己小 V区拳、小 C拘领、小 M。神奇的邏輯樱调。
舍不得收尾约素、說拜拜
轉(zhuǎn)眼間,自己還在大學(xué)期間學(xué) JavaScript 基礎(chǔ)笆凌、學(xué)習(xí) CSS 布局的時(shí)候圣猎,ES 7、ES8 都開始被各大社群討論菩颖;React样漆、Vue 等主流框架也開始加深誘惑著我們初學(xué)者;各大培訓(xùn)班瘋狂輸出的前端學(xué)員就光數(shù)量上也讓大學(xué)生軟件開發(fā)學(xué)習(xí)者有所擔(dān)憂晦闰。
一切還好。正如文章開始的那些感悟中隱藏在背后的那句羅曼羅蘭式英雄的風(fēng)度一樣——“世界上只有一種真正的英雄主義鳍怨,就是認(rèn)清了生活的真相后還依然熱愛它”呻右。
哈哈,希望我的引用不算錯(cuò)位鞋喇。也希望我的這個(gè)項(xiàng)目總結(jié)能散發(fā)出本身應(yīng)有的光芒声滥。
- Hello,我是韓亦樂侦香,現(xiàn)任本科軟工男一枚落塑。軟件工程專業(yè)的一路學(xué)習(xí)中,我有很多感悟罐韩,也享受持續(xù)分享的過程憾赁。如果想了解更多或能及時(shí)收到我的最新文章,歡迎訂閱我的個(gè)人微信號(hào):韓亦樂散吵。我的簡(jiǎn)書個(gè)人主頁中龙考,有我的訂閱號(hào)二維碼和 Github 主頁地址;我的知乎主頁 中也會(huì)堅(jiān)持產(chǎn)出矾睦,歡迎關(guān)注晦款。
- 本文內(nèi)部編號(hào)經(jīng)由我的 Github 相關(guān)倉(cāng)庫統(tǒng)一管理;本文可能發(fā)布在多個(gè)平臺(tái)但僅在上述倉(cāng)庫中長(zhǎng)期維護(hù)枚冗;本文同時(shí)采用【知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議】進(jìn)行許可缓溅。