-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.json
1 lines (1 loc) · 146 KB
/
index.json
1
[{"categories":["Life"],"content":" 团队中秋节的曲目,因为小伙伴们频繁出差以及加班的缘故,没有太多一起排练的时间,好在最后大家状态都还不错,及时完成了这首歌的Cover。 最初录制时间设想在蓝调时间,无奈当前阴转雨,可谓计划赶不上变化,不过最后从视频呈现来看,小雨似乎也很有情调。 希望你们会喜欢,祝大家中秋快乐,阖家幸福。 ","date":"2023-09-29","objectID":"/2023/09/pi-xing-dai-yue-cover/:0:0","tags":["mv","音乐"],"title":"《披星戴月的想你》Cover by Red Nose","uri":"/2023/09/pi-xing-dai-yue-cover/"},{"categories":["Music"],"content":"まだこの世界せかいは 僕ぼくを飼かいならしてたいみたいだ 望のぞみ通どおりいいだろう 美うつくしくもがくよ 互たがいの砂時計すなどけい 眺ながめながらキスをしようよ 「さよなら」から 一番いちばん 遠とおい場所ばしょで待まち合あわせよう 辞書じしょにある言葉ことばで 出来上できあがった世界せかいを憎にくんだ 万華鏡まんげきょうの中なかで 八月はちがつのある朝あさ 君きみは僕ぼくの前まえで ハニかんでは澄すましてみせた この世界せかいの教科書きょうかしょのような笑顔えがおで ついに時ときはきた 昨日きのうまでは序章じょしょうの序章じょしょうで 飛とばし読よみでいいから ここからが僕ぼくだよ 経験けいけんと知識ちしきと カビの生はえかかった勇気ゆうきを持もって いまだかつてないスピードで 君きみのもとへダイブを まどろみの中なかで 生温なまぬるいコーラに ここでないどこかを 夢見ゆめみたよ 教室きょうしつの窓まどの外そとに 電車でんしゃに揺ゆられ 運はこばれる朝あさに 愛あいし方かたさえも 君きみの匂においがした 歩あるき方かたさえも その笑わらい声ごえがした いつか消きえてなくなる 君きみのすべてを この眼めに焼やき付つけておくことは もう権利けんりなんかじゃない 義務ぎむだと思おもうんだ 運命うんめいだとか未来みらいとかって 言葉ことばがどれだけ 手てを 伸のばそうと届とどかない 場所ばしょで僕ぼくら恋こいをする 時計とけいの針はりも二人ふたりを 横目よこめに見みながら進すすむ そんな世界せかいを二人ふたりで 一生いっしょういや、何章なんしょうでも 生いき抜ぬいていこう 歌词仅用于学习用途,版权归歌曲所有人所有。 ","date":"2023-08-26","objectID":"/2023/08/lyric-radwimps-sparkle/:0:0","tags":["日语","歌词"],"title":"Radwimps - スパークル (movie ver.)","uri":"/2023/08/lyric-radwimps-sparkle/"},{"categories":null,"content":"这里是? 这里是博主的阅读记录。 ","date":"2023-08-16","objectID":"/books/:1:0","tags":null,"title":"阅读","uri":"/books/"},{"categories":null,"content":"2023 分类 书名 作者 完成日期 时间 评分 理论 漫画计算机原理 🇯🇵 川添爱 2023-07-10 1小时 11分 4 / 5 工具 INPUT 最高学习法 🇯🇵 樺沢紫苑 - - -/5 哲学 哲学·科学·常识 🇨🇳 陈嘉映 - - -/5 ","date":"2023-08-16","objectID":"/books/:1:1","tags":null,"title":"阅读","uri":"/books/"},{"categories":null,"content":"2022 分类 书名 作者 完成日期 时间 评分 传记 你干吗在乎别人怎么想? 🇺🇸 Richard Feynman 2022-05-09 5小时 39分 4 / 5 工具 起床后的黄金1小时 🇯🇵 池田千惠 2022-05-01 2小时 50分 3 / 5 小说 1984 🇬🇧 George Orwell 2022-04-09 11小时 49分 4 / 5 人文 丑陋的中国人 🇨🇳 柏杨 2022-01-07 7小时 23分 4 / 5 ","date":"2023-08-16","objectID":"/books/:1:2","tags":null,"title":"阅读","uri":"/books/"},{"categories":null,"content":"2020 分类 书名 作者 完成日期 时间 评分 小说 十日谈 🇮🇹 Giovanni Boccaccio 2020-08-22 16小时 22分 4 / 5 小说 人间失格 🇯🇵 太宰治 2020-07-25 3小时 4分 3.5 / 5 传记 拍电影我在想的事 🇯🇵 是枝裕和 2020-07-20 5小时 11分 4 / 5 ","date":"2023-08-16","objectID":"/books/:1:3","tags":null,"title":"阅读","uri":"/books/"},{"categories":["Life"],"content":" 本来这首歌是想要8/9月份作为户外露营的节目的,后来没成。 好在10月底天气还不算冷,比较遗憾的是当天一早雾气比较重,所以江边的镜头在大中午拍摄光比太大,导致大家都黑黑的,😄。 期待 2023年可以「等一个自然而然的夏天」「一起去海边」「留住这个瞬间」。 ","date":"2022-11-09","objectID":"/2022/11/xiang-qu-hai-bian-cover/:0:0","tags":["mv","音乐"],"title":"《想去海边》Cover by Red Nose","uri":"/2022/11/xiang-qu-hai-bian-cover/"},{"categories":null,"content":"Beginner of Drum Set 学习架子鼓的契机是21年春节在鼓房录一个视频的时候,因为耳鸣的原因我在店里借了一个耳机戴着,没想到头大扯太大力把耳机弄坏了。后来店里老板没有送回保修也没让赔偿,过意不去就报了一年的架子鼓课程。 ","date":"2022-06-26","objectID":"/drummer/:1:0","tags":null,"title":"Drummer","uri":"/drummer/"},{"categories":null,"content":"Practice 以下是平时练习基本功的一些练习,分享在此,另一方面也是便于自己练习的时候查询。 ","date":"2022-06-26","objectID":"/drummer/:2:0","tags":null,"title":"Drummer","uri":"/drummer/"},{"categories":null,"content":"鼓棒的四种击打方式 Full Stroke Down Stroke Tap Stroke Up Stroke - - - - ","date":"2022-06-26","objectID":"/drummer/:2:1","tags":null,"title":"Drummer","uri":"/drummer/"},{"categories":null,"content":"单击/双跳练习 ","date":"2022-06-26","objectID":"/drummer/:2:2","tags":null,"title":"Drummer","uri":"/drummer/"},{"categories":["Life"],"content":" 「是的,我看见到处是阳光」,这首歌在盘尼西林改编之后有了不一样的味道,喜欢这样的摇摆节奏。 也祝大朋友们,儿童节快乐。 ","date":"2022-06-01","objectID":"/2022/06/new-boy-cover/:0:0","tags":["mv","音乐"],"title":"《New Boy》Cover by Red Nose","uri":"/2022/06/new-boy-cover/"},{"categories":null,"content":"这里是? 这里是记录博主游玩游戏后的感想、评价及评分,十分主观,且会有剧透,请斟酌观看。 PlayStation Switch 美国末日 重制版 塞尔达传说:旷野之息 美国末日 第二章 歧路旅人 战神3 重制版 神秘海域:德雷克船长的宝藏 ","date":"2022-03-02","objectID":"/games/:1:0","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"游戏 ","date":"2022-03-02","objectID":"/games/:2:0","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"THE LAST OF US REMASTERED / 美国末日 重制版 THE LAST OF US REMASTERED 「主观评分」: 9/10 「游玩平台」: PS4 「游玩感受」: 是购买PS4后第一批买入的游戏,因对于恐怖游戏有一定的恐惧,把音量调的很小,但依然能感受到音效以及音乐渲染的气氛。游戏的没有像生化危机等恐怖游戏那样时不时破窗、出其不意的吓人,总体节奏比较可控,不会被吓到扔掉🎮。 剧情很棒,角色刻画的都很立体,乔尔的转变很自然,结局的时刻很高光,虽然很自私,但是能够理解这样的选择。 ","date":"2022-03-02","objectID":"/games/:2:1","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"THE LAST OF US PART II / 美国末日 第二章 THE LAST OF US PART II 「主观评分」: 7/10 「游玩平台」: PS4 「游玩感受」: 游戏较前作提升很多,画面、操控等等都不错,剧情方面就有点尴尬。 角色动机有时候很迷,转变不自然,反派死于话多。西雅图第一天的时候,反派同伙都被狄娜杀死了,按照正常逻辑反派不枪杀了狄娜还在磨磨唧唧不知道干什么。最让我气的是,汤米的转变没有一点铺陈,强行让艾莉去复仇。 相比艾莉乏善可陈的剧情线,艾比的剧情就相对来说丰富了。艾比从有到无,一步一步的失去,最后差点死在圣·芭芭拉。 其实我总觉得在剧院艾莉艾比决战时结束刚刚好,这样或许我还会期待后续的剧情如何展开。 ","date":"2022-03-02","objectID":"/games/:2:2","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"GOD OF WAR III REMASTERED / 战神3 重制版 GOD OF WAR III REMASTERED 「主观评分」: 9/10 「游玩平台」: PS4 「游玩感受」: 好玩!打击感、血腥暴力元素很可以。因为一开始选择了团难模式,有些部分跪了很多次。 BOSS 战很有意思,各个武器我拳套和流亡刀用的多一点,其他的使用频率很低。剧情很有意思,众神在临死前总想着办法欺骗奎托斯来苟活,就连最初以为是「好」的女神雅典娜也只不过是为了得到希望之力。 奎托斯受够了欺骗,自刎结束了生命,将希望之力送给了众人。 是个很好的结局,是个很好的游戏!喜欢动作 RPG 必玩之作。 ","date":"2022-03-02","objectID":"/games/:2:3","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"UNCHARTED: DRAKE’S FORTUNE / 神秘海域:德雷克船长的宝藏 UNCHARTED: DRAKE'S FORTUNE 「主观评分」: 7/10 「游玩平台」: PS4 「游玩感受」: 是 Sony 在 「Play at home」赠送的游戏,可能因为是比较有年代的游戏的缘故,07年的画面,应该来说还行吧。主要可能是因为玩结束了美末的缘故,对于游戏内的射击完全不适应,没有很真实的射击感。AI 的射击感觉就是开了外挂一样,有很多不自然的动作。还有就是水上摩托的驾驶感也不是很好。不过这些批判是站在22年来看的,实际上如果放在当年可能还是不错的。 值得称赞的是战斗音乐、场景音乐以及剧情还是不错的,最后发电厂的丧尸也有凭借着音乐吓了我一跳。 不过最后的 BOSS 战真的是服了,一定要不确认 BOSS 是不是真的挂了再去看女主吗?至少把枪拿走吧。好了,什么都不拿也就算了,最后还要推直升机下海里去,BOSS 举着枪等着你推。真是一个好莱坞式的结尾。棒! ","date":"2022-03-02","objectID":"/games/:2:4","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"UNCHARTED: AMONG THIEVES / 神秘海域:盗亦有道 UNCHARTED: AMONG THIEVES 「主观评分」: 8/10 「游玩平台」: PS4 「游玩感受」: 故事开局采用倒叙手法好评! 射击感虽然比第一代好一些,但还是有点奇怪,打野人的时候更明显,野人没有中弹反馈感。 ","date":"2022-03-02","objectID":"/games/:2:5","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"ゼルダの伝説 ブレス オブ ザ ワイルド / 塞尔达传说 旷野之息 THE LEGEND OF ZELDA: BREATH OF THE WILD 「主观评分」: 10/10 「游玩平台」: Switch 「游玩感受」: 这款游戏是购买 Switch 的理由,沉浸、有趣、好玩。 我还没玩结束,结束后再来完善感受。 ","date":"2022-03-02","objectID":"/games/:2:6","tags":null,"title":"游戏","uri":"/games/"},{"categories":null,"content":"OCTOPATH TRAVELER / 歧路旅人 「主观评分」: 7.5/10 「游玩平台」: Switch 「游玩感受」: 首先说下整个让人喜欢的部分: HD-2D 画面,怀旧不旧,在清一色的 3D 画风游戏中,这样的画面很讨喜。 音乐很好听! 要说不足的话: 战斗画面比较单一,不喜欢踩地雷的战斗模式 支线任务没有清晰的说明 要我来说,整体的剧情太多,这可能会是我玩不到结束的一个主要原因,目前剧情普遍推进到第三、四章,让人厌烦的是需要不停地刷团队每个人的等级。如果后面我玩到结局了,到时候我就再来写一点。总体来说游戏风格、音乐令人欢喜,战斗模式以及剧情是我比较烦闷的地方。 ","date":"2022-03-02","objectID":"/games/:2:7","tags":null,"title":"游戏","uri":"/games/"},{"categories":["Life"],"content":" Red Nose 的由来是因为这支 MV,因为当时在林子里拍摄,风很大,篝火火力全开也无法使我们暖和,在 NG 了几遍之后,大家也都冻成了红鼻子😂。 ","date":"2022-01-26","objectID":"/2022/01/yellow-cover/:0:0","tags":["mv","音乐"],"title":"《Yellow》Cover by Red Nose","uri":"/2022/01/yellow-cover/"},{"categories":["Report"],"content":"一年真的很快就过去了,其实时间一直在往前,而回归的月份让人误以为又是一个重新开始。 2021年总体来说差强人意,阅读没有持续,日语一开始还是比较积极地在学习的,后来因为程序开发占用掉了学习时间,四季度基本上搁置至今,也许今年应该找一个老师,就像架子鼓一样。 一整年的感觉就是时间不够用,下半年明显感觉到缺少休息带来的身体方面的酸痛,肩颈背变得僵硬。2022年还是需要劳逸结合,时间方面也要合理规划。 ","date":"2022-01-05","objectID":"/2022/01/annual-report-2021/:0:0","tags":["年度总结"],"title":"2021年年度总结","uri":"/2022/01/annual-report-2021/"},{"categories":["Report"],"content":"回顾 今年年尝试了总体策划一场活动,在过程中遇到了任务分配不合理,人员没有充分利用,时间规划不清晰的问题,好在最后活动相较顺利的举办,也算是一次经验累积吧。 得益于上半年的计算机基础课的学习,在公司信息化平台其他模块开发的时候,运用了一些学到的知识:抽象、递归等,深知对所学知识还需要充分消化,在2022年应该还需要结合实际来运用这些知识。 ","date":"2022-01-05","objectID":"/2022/01/annual-report-2021/:1:0","tags":["年度总结"],"title":"2021年年度总结","uri":"/2022/01/annual-report-2021/"},{"categories":["Report"],"content":"全年完成的计划: 33节架子鼓学习 健身 计算机科学基础课 日语学习 7课 (勉强算吧) ","date":"2022-01-05","objectID":"/2022/01/annual-report-2021/:1:1","tags":["年度总结"],"title":"2021年年度总结","uri":"/2022/01/annual-report-2021/"},{"categories":["Report"],"content":"未完成的计划: 阅读 吉他 ","date":"2022-01-05","objectID":"/2022/01/annual-report-2021/:1:2","tags":["年度总结"],"title":"2021年年度总结","uri":"/2022/01/annual-report-2021/"},{"categories":["Report"],"content":"项目完成情况: 100% 检针模块 40% 的海外订柜模块 ","date":"2022-01-05","objectID":"/2022/01/annual-report-2021/:1:3","tags":["年度总结"],"title":"2021年年度总结","uri":"/2022/01/annual-report-2021/"},{"categories":["Report"],"content":"期许 2022年,希望自己能够坚持阅读,坚持做好一两件重要(重大)的事、分清主次,能够做到独立思考。 继续加油。 ","date":"2022-01-05","objectID":"/2022/01/annual-report-2021/:2:0","tags":["年度总结"],"title":"2021年年度总结","uri":"/2022/01/annual-report-2021/"},{"categories":["Life"],"content":"上周日晚上去上网球课,刚上车收到手机弹出的 Siri 建议,点开随即进入地图应用并且给我规划好去网球场的路线,很不巧,那天下雨,所以没有去室外场地而是室内场地。 不知道是 iOS 15 加强了这方面的功能,还是原本 iOS 14 也有。反正,现在这个版本的 Siri 建议聪明了很多。 系统会根据使用者的习惯,会在你早上上车时候告诉你去公司需要多长时间,并给你选出 2 至 3 条合适的路线;会在你复制了链接后建议你用 Safari 打开链接;会告诉你在某个时间点你经常会打开什么 App,你现在是否要打开? Siri 就从一开始呆萌的只会搜索网络结果及跟你回几句嘴开始变成了一个智能小管家,这么几年的深度学习的确起了效果。 在某些方面上,我也开始依赖起这个小管家。 但有时想一想,这样的数据很隐私,何时在何地你会做什么事情。若这样的数据被泄漏、盗取,就可以精准定位用户画像,甚至可以跟踪到具体位置。 科技带来便利的同时,也同样暴露了隐私。 好在现在科技公司都在隐私方面下功夫,苹果推出了专门的 Privacy 页面,用以了解账户所有的数据信息,也在新版本的 iOS 系统里增加了隐私报告。 希望这些隐私数据能够脱敏,在给用户提供个性化建议的同时,也不会暴露用户本身。 科技是好,但也还有生活,也许有时候离开科技,才是自由。 ","date":"2021-11-23","objectID":"/2021/11/ios15-machine-learning/:0:0","tags":null,"title":"iOS15 的深度学习与隐私","uri":"/2021/11/ios15-machine-learning/"},{"categories":["Notes"],"content":" 例句中符号说明 ~ 替代词汇及句子 ー 替代数字 [ ] 括号中的语句可以省略 ( ) 括号中为其他表达方式 笔记更新至第7课 助词「は」读作「わ」 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:0:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"肯定句 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:1:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"名词1 + 助词 は + 名词2 + です。 私 は マイク・ミラー です。 名词1 + 助词 も + 名词2 + です / ですか。 「も」用于将相同的事物作为前提加以陈述时。 サントスさん は 会社員 です。 ワンさん も 会社員 です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:1:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"名词1 + は + 场所 + です。 用来表示场所、物体或人所在的地方。 お手洗い は あそこ です。 電話 は 2階 です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:1:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"名词(场所)1 + へ + 行きます / 来ます / 帰ります。 使用表示移动的词时,移动方向用助词「へ」(读作「え」)表示。 京都 へ 行きます。 日本 へ きました。 うち へ 帰ります。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:1:3","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"时间 + です。 今9時15分 です。 询问时间在「時」「ふん」之前加「なん」。 「分」读法: 「ふん」:前面数字是 2、5、7、9 时。 「ぷん」:前面数字是 1「いっ」、3、4、6「るっ」、8「はっ」、10「じゅっ(じっ)」 时。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:1:4","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"否定句 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:2:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"名词1 + 助词 は + 名词2 + じゃ(では)ありません。 ではありません 是正式场合的用法。 「じゃありません」和「ではありません」是「です」的否定形式。 私 は 学生 じゃありません。 私 は 医者 ではありません。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:2:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"疑问词 + も + 行きません。 对疑问词所问范畴内的一切全部加以否定时,在疑问词后加「も」,且动词使用其否定形。 どこ[へ] も いきません。 / 哪儿也不去。 何 も 食べません。 / 什么也不吃。 誰もき ま せんでした。 / 谁也没来。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:2:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"疑问句 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:3:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"一般疑问句 名词1 + 助词 は + 名词2 + ですか。 マイク・ミラーさん は 会社員 ですか。 「肯定回答」はい、[私は] 会社員です。 「否定回答」いいえ、[私は] 会社員 じゃありません。 そうです / 違います 在名词句中,在回答询问是否的疑问句时,使用以下回答。 それ は 辞書 ですか。 「肯定回答」はい、そうです。 / 「简单回答」 そう。 「否定回答」いいえ、違います。 / 「或者直接告诉正确答案」いいえ、本です。 そうですか 在听到新信息时,用这句话来表示知道了(有点不太确定的那种感觉)。句尾语调为降调。 この傘はあなたのですか。 いいえ、違います。佐藤さんのです。 そうですか。 〜か 「か」是说话人在得到自己所不知道的新信息之后,表示认可、理解时的表达方式。这与「そうですか」的「か」用法相同。 日曜日京都へ行きました。 京都ですか。いいですね。 そうですね 对对方说的事情表示赞同或有同感。 「そうですか」是说话人在得到新信息之后表示认可、理解。 明日 は 日曜日 ですね。 あ、そうですね。 名词 + は + 疑问词 + ですか。 お手洗い は どこ ですが。 エレベーター は どちら ですか。 何なに を しますか。 询问要做什么。 月曜日 何 をしますか。 京都へ行きます。 动词 + ませんか。 表示邀请听话人一起来做某事。 一緒に 京都へ行きませんか。 | 一起去京都吗?(不一起去京东吗?) 动词 + ましょう。 表示积极地提议、邀请。也可以表示积极的响应对方的提议、邀请。 ちょっと休み ましょう。 一緒に昼ごはんを食べませんか。 ええ、食べましょう。 注:「动词ませんか」和「动词ましょう」同为邀请对方的表达方式,前者更加尊重对方。 #### 词/句 + は + 〜ごで + なんですか。 询问某个词或者句子用~语怎么说。 「ありがとう」は 英語 何ですか。 「Thank You」です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:3:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"选择疑问句 〜か、〜か。 两个或两个以上的并列疑问句进行选择回答的疑问句。此类疑问句回答不用加上「はい」或「いええ」,直接回复选择。 それは「9」です か、「7」です か。 「9」です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:3:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"疑问词 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:4:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"どこ / どちら 「どこ」是询问场所的疑问词。 「どちら」是询问方向的疑问词,也用于询问场所,语气较「どこ」郑重。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:4:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"いつ 询问时间时,除了「何時なんじ」等询问词之外,还可以使用「いつ」,「いつ」之后不接助词「に」。 いつ 日本 へ 来ましたか。 3月25日 に 来ました。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:4:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"何 「なに」和「なん」意思相同,但以下情况使用「なん」; 后续单词的词头为「た」「だ」「な」时。 それは なん ですか。 なん の本ですか。 注:「なんで」除了可以询问手段、方法之外,还可以用于询问理由。想明确表示在询问手段、方法,可以用「なにで」。 带有量词时 テレーズちゃんは なん 歳ですか。 以上两种以外情况使用「なに」。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:4:3","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"其他 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:5:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":"名词1 + から + 名词2 + まで 「から」表示起点(时间、场所),「まで」表示重点(时间、场所),他们经常一起使用,也可以单独使用。 銀行 は 9時から 3時まで です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-grammar/:5:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 文法","uri":"/2021/09/mina-no-nihonngo-grammar/"},{"categories":["Notes"],"content":" 例句中符号说明 ~ 替代词汇及句子 ー 替代数字 [ ] 括号中的语句可以省略 ( ) 括号中为其他表达方式 笔记更新至第7课 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:0:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词的省略 在会话中,当从前后关系就可以明白语意时,助词可以省略。 このスプーン[は]、すてきですね。 コーヒー[を]、もう一杯いかがですか。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:1:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 は 助词「は」读作「わ」 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:2:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 の ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:3:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词1 の 名词2 名词1 表示 名词2 的属性。 ミラーさん は IMC の 社員 です。 名词1 来说明 名词2 与什么事物有关。 これ は コンピョーター の 本 です。 名词1 表示 名词2 的所属/产地。 これ は 私 の 本 です。 これ は 日本 の コンピョーター です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:3:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"代替名词 あれ は 誰 の 鞄 ですか。 佐藤さんのです。 在回答时,「の」替代了问句中出现的名词「鞄」,「の」放在「佐藤」后面相当于省略了「鞄」。「の」可以用于替代物品,不可用来替代人。 この 鞄 あなたの ですか。 いいえ、私 の じゃありません。 ミラーさんは IMC の 社員 ですか。 ✔️ はい、IMC の 社員 です。 ❌ はい、IMC の です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:3:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 に ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:4:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(时间) + に + 动词 在表示时间的名词后加「に」,表示动作进行的时间 7時2分 に 日本へ来ました。 以下表示时间的名词不能加「に」: 今日きょう 明日あした 明後日あさって 昨日きのう 一昨日おととい 今朝けさ 今晩こんばん 今いま 毎朝まいあさ 毎晩まいばん 毎日まいにち 先週せんしゅう 今週こんしゅう 来週らいしゅう いつ 先月せんげつ 今月こんげつ 来月らいげつ 今年ことし 来年らいねん 去年きょねん 等。 昨日 勉強しました。 这些表示时间的名词可加可不加: 〜曜日〜ようび 朝あさ 昼ひる 晩ばん 夜よる ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:4:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(人) + に + 动词 助词「に」表示接触点。 友達 に 会います。 语义上偏向去见朋友:我 =\u003e 朋友 友達 と 会います。 语义上偏向两个人去约定的地方见面:我 =\u003e 场所 \u003c= 朋友 ❌ 友達 を 会います。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:4:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词1 + に + 名词2 + 动词。 动词分两种: 一种是表示提供事物、信息的意思,需要有接受这些事物、信息的对象,这一对象用助词「に」来表示。(名词1 为受方时) 如 「あげます」 「かします」 「おしえます」 等。 另外一种是表示得到事物、信息的意思,需要有提供这些事物、信息的对象,这一对象用助词「に」来表示,也可以用「から」来表示。(名词1 为授方时) 如 「もらいます」 かります ならいます 等。 [私は]木村さん に 花を あげました。 我给木村小姐送了花。 [私は]木村さん に(から) 花を もらいました。 我收到了木村小姐送的花。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:4:3","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 ね ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:5:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"〜ね 表示说话人希望得到听话人的同意或说话人对某件事物加以确认、叮嘱的语气。 毎日10時まで勉強します。 大変です ね。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:5:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(场所) + に + 动词(表示移动的) 在表达移动到达的场所时,用助词「に」。与助词「へ」的差别在于,「へ」是表达移动方向,「に」是表达移动到这个场所。 私は学校 に 行きます。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:5:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 へ 助词「へ」读作「え」 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:6:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(场所) + へ + 动词(表示移动的) 使用表示移动的词时,移动方向用助词助词「へ」表示。 京都 へ 行きます。 うち へ 帰ります。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:6:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 と ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:7:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词1 + と + 名词2 名词并列,在之间用「と」连接,表示名词1和名词2。 銀行の休みは土曜日 と 日曜日 です。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:7:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(人/动物) + と + 动词 表示与自己一起行动的人或动物。 家族 と 日本へ来ました。 单独行动时,要用「一人で」且不用助词「と」。 一人で 東京へ行きます。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:7:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 で ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:8:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(交通工具) + で + 动词。 助词「で」表示手段、方法,接在表示交通工具的名词之后,表示与动词一起使用。 電車 で 行きます。 徒步行走用「歩あるいて」且不用接助词「で」。 駅から歩いて帰りました。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:8:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(场所) + で + 动词。 接在场所后的助词「で」表示发生的场所。 駅 で 新聞を買います。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:8:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词(工具/手段) + で + 动词。 助词「で」用来表示方法、手段、工具。 箸はしで食べます。 | 用筷子吃饭。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:8:3","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 を ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:9:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词 + を + 动词(他动词) 他动词的宾语用助词「を」表示。 ジュース を 飲みます。 注:「を」只用来表示助词。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:9:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"名词 + を + 动词 表示动作作用对象。 动词是「します」时,可以接在很多名词之后,使其作为宾语。意思是表示做该名词所表示的内容。 スッカー を します。 踢足球 パーティー を します。 举办晚会。 宿題しゅくだい を します。 做作业。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:9:2","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"助词 よ 接在词尾,用于将对方不知道的事情或说话人自己的判断等告诉对方。 この電車は甲こう子し園えんへ行きますか。 いいえ、行きません。次の「普ふ通つう」です よ。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:10:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"副词 ときぢき 修饰后面的动词或新的动词,与前句无关。意思是「有时候」。 うちで本を読みます。ときどき図書館へ行きます。 ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:11:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"副词 もう ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:12:0","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Notes"],"content":"もう + 动词ました。 「もう」是「已经」的意思,与「动词ました」一起使用,表示「动词ました」已经结束。 在回答时,如果行为已经结束了,进行肯定回答「はい、もう 动词 ました。」;如果行为尚未结束,进行否定回答「いいえ、动词て いません。」或者「いいえ、まだです。」。 もう昼ご飯を食べましたか。 [肯定回答] はい、[もう]食べました。 [否定回答] いいえ、まだです。(いいえ、食べていません。) [否定回答] ❌ いいえ、まだ食べません。(いいえ、食べませんでした。) ","date":"2021-09-05","objectID":"/2021/09/mina-no-nihonngo-particle/:12:1","tags":["日语"],"title":"《大家的日本语》学习笔记 - 助词 \u0026 副词","uri":"/2021/09/mina-no-nihonngo-particle/"},{"categories":["Life"],"content":"今天突然在想一个问题「完美和不完美」。 在很多时候我都在追求一定的完美,在选择学习资料上、数据整理方案、程序的算法逻辑等等,总会考虑很多,是否有不完美的地方,这固然是一件好事情,但也有时候无论如何也无法达到真正意义上的完美,总有不完美的地方。 最近在上王垠老师的课,他的观点很多方面都让我有了新的认知。以前学音乐觉得音乐是完美的语言,现在看其实也有很多不完美的地方,十二平均律也不是最完美的韵律。 说到上课,我惊讶于王垠老师可以将知识点用很容易理解的方式讲出来,抽丝剥茧,入门者很容易理解,但内容又不是浅层次的,课后练习很容易看出来是经过认真设计的,能够深入去理解知识点的。 今天刷到微博,大意就是在交易市场上大家都愿意亏损当学费,而不愿意花几万元去学习技术。花几万元去学习技术,我觉得门槛虽然高一点,但是能够系统的学习到知识(当然不是说费用高的就是好的),我认为这样的学费其实是很便宜的。 ","date":"2021-04-02","objectID":"/2021/04/studying-training-learning/:0:0","tags":null,"title":"一些琐事","uri":"/2021/04/studying-training-learning/"},{"categories":["Life"],"content":" 原本计划 2020 年要在公司层面寻找人员组成公司的乐队的,后来因为疫情搁置了,年底的时候分公司有小伙伴告诉我她学了 Bass,正好大冰龙带着他吉他 Demo 想要来投稿公众号,一拍即合,干脆整个乐队吧。 大家一起排练、改编和录音,于是就有了周杰伦《稻香》的 Cover。 ","date":"2021-03-16","objectID":"/2021/03/dao-xiang-cover/:0:0","tags":["mv","音乐"],"title":"《稻香》乐队Cover","uri":"/2021/03/dao-xiang-cover/"},{"categories":null,"content":"为什么有这个页面 设置这个页面为了跟踪我的学习计划是否有效地推进,离目标多远,有多少计划是搁置或是放弃的。 Best or nothing! ","date":"2021-03-02","objectID":"/10000/:1:0","tags":null,"title":"10000小时计划","uri":"/10000/"},{"categories":null,"content":"进行中的计划 计划 累计时间 更新日期 进度 🥁 架子鼓 156小时 2023.10.16 📖 阅读 62小时 23分钟 2023.10.16 ","date":"2021-03-02","objectID":"/10000/:2:0","tags":null,"title":"10000小时计划","uri":"/10000/"},{"categories":null,"content":"搁置的计划(未更新时间超过6个月) ","date":"2021-03-02","objectID":"/10000/:3:0","tags":null,"title":"10000小时计划","uri":"/10000/"},{"categories":null,"content":"放弃的计划(未更新时间超过12个月) 计划 累计时间 更新日期 进度 🎸 吉他 19小时 2022.06.14 ","date":"2021-03-02","objectID":"/10000/:4:0","tags":null,"title":"10000小时计划","uri":"/10000/"},{"categories":["Plan"],"content":"工作计划 今年的工作重心在分公司的信息化建设,一方面是业务系统的系统化的推进,另外一方面是自研的信息系统的开发。前者要抓紧推进的,是工作的重心。后者不应该占据自身太多的时间,在时间较为空余时进行开发,也可借助开源平台进行二次开发以节约时间成本。 文化建设方面,公众号主要由 Jackson 负责打理(基本还是我在弄😓),我负责每个月计划以及方向的制定,其他方面仍然需要保持高度的敏感性,提前准备。 工会的文体活动去年已经定好计划,按照预计时间提前准备。 今年需要摒弃细微末节,将时间用在重要的事情上去。同时还需要发掘相关方面的人才,使队伍壮大起来。 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:1:0","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"学习计划 今年在学习方面应该要比去年更加进步一点,这不仅仅只在深度方面。所以今年我打算着重学习日语、架子鼓、吉他。其余例如开发、音乐制作、视频拍摄则依据实际需要来选择学习内容。阅读今年依然是必不可少的一环。 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:0","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"阅读 (未完成) 今年计划阅读 10本书,同一类型书籍最多不超过3本。计划表以及进度会在第一本书阅读开始时更新。 分类 数量 完成 小说 3本 历史 2本 传记 2本 指导 2本 哲学 1本 阅读进度: 书名 分类 开始时间 完成时间 耗时 状态 学会提问 指导 2021.02.18 ? - ▶️ 进行 丑陋的中国人 历史(不能算历史) 2021.03.16 2022.01.07 7小时23分 ✅ 完成 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:1","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"日语 (未完成) 日语计划今年至少要完成 N3 的考试,最好是能够考到 N2。有必要的话,会找老师上课。 自学计划是打算将《大家的日本语》两册书学完,根据学习的情况再看是否需要《标准日本语》作为补充。 考试报名时间弄错了,没报上。目前只完成到初级的第七课。 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:2","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"计算机科学基础课 (完成) 今年报了王垠老师的《计算机科学基础课》,要将这课程内容好好吸收,希望能够理解课程的所有内容。 学完了,笔记以及练习还需要整理和消化。 虽然练习都做了出来,链表、树、解释器、类型检查还有 Parser 还需要加强理解,在实际案例中能够运用到这些内容。 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:3","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"架子鼓 (完成) 年后先去检查耳朵,确保学习期间能够尽可能的保护耳朵「买了静音耳塞」。之后去报班。 5月9日报了一年的架子鼓班(50节课),我发现我练架子鼓蛮专注的,可能是因为在练歌?下次长时间练基本功的时候再来发表感想。 课程进度:32/50 (因为疫情,有几个月琴行停课) 已学内容: 单跳 / 双跳 / 倚音 / 开合镲 《改变自己》《星空》《不再犹豫》《君が好きだと叫びたい》《Cold Pants》 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:4","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"吉他 (未完成) 吉他完成指弹练习曲前12首,时间充足的情况下尽量能够多完成。 曲目 分类 开始时间 完成时间 耗时 状态 练习曲4 练习曲 2021.02.14 2021.03.20 9 hour ✅ 完成 练习曲5 练习曲 2021.03.21 - - ▶️ 进行 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:5","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"乐队排练/表演 周杰伦《稻香》/ MV / 吉他 / 2021.02.05 / 📹 视频 伍佰《Last Dance》 / Live / 键盘 / 2021.02.14 / 📹 视频 五月天《星空》 / Live / 吉他 / 2021.04.09 / 无视频 五月天《星空》 / Live / 架子鼓 / 2021.08.14 / 📹 视频 现场收音,效果不是很好。另我的节奏也有点不太稳。 Coldplay 《Yellow》 / MV / 架子鼓 / 📹 视频 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:6","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"其他 开发、音乐制作、视频拍摄等会根据实际情况在此更新。 开发: 拼柜模块 检针模块 海外订柜模块(开发中) ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:2:7","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"身心计划 这方面计划由健身私教、书法练习、情绪管理及自省组成。 健身是身体方面的强化;书法是心灵方面的洗涤;情绪的管理以及自省来改善不完美的自己。 ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:3:0","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Plan"],"content":"健身 Phase One (total 44, ¥ 6,000) 02.22 ~ 02.28 / 3 courses 03.01 ~ 03.07 / 4 courses 03.08 ~ 03.14 / 3 courses 03.15 ~ 03.21 / 4 courses 03.22 ~ 03.28 / 1 courses 04.12 ~ 04.18 / 4 courses 04.19 ~ 04.25 / 3 courses 04.26 ~ 05.02 / 3 courses 05.03 ~ 05.09 / 2 courses 05.10 ~ 05.16 / 3 courses 05.17 ~ 05.23 / 4 courses 05.24 ~ 05.30 / 2 course 老师出差 05.31 ~ 06.06 / 2 courses 06.06 ~ 06.13 / 4 courses 06.14 ~ 06.20 / 2 courses 一期结束 2021,不念过往,不问未来,珍惜现在,加油W. ","date":"2021-02-14","objectID":"/2021/02/annual-plan-2021/:3:1","tags":["年度计划"],"title":"2021年年度计划","uri":"/2021/02/annual-plan-2021/"},{"categories":["Report"],"content":"2020年虽然说是疫情年,但这一年依旧是忙碌的一年。 从年初网店运营以及产品的拍照,到六一活动的筹备,以及下半年的集装箱拼柜系统的开发,基本都是无缝衔接。 ","date":"2021-01-15","objectID":"/2021/01/annual-report-2020/:0:0","tags":["年度总结"],"title":"2020年年度总结","uri":"/2021/01/annual-report-2020/"},{"categories":["Report"],"content":"自省 「Do One Thing Perfect」上半年践行的不是很好,拍照、修图、店铺装修以及运营每个部分都分散了我的精力,并不能专注于一件事,另外一方面在这个团队的协作方面存在了一些问题: 大家都没有做网店的经验 由于我们主业是做B端客户的,大家对于做 C 端认为只是一个临时阶段 对于一些同事来说,做与不做或者效率高低对于 ta 没有直接影响。 所以,当主业正常之后,大家都各自回归原来的岗位了,并没有产生出一个互联网销售团队。 下半年是信息化工作为主,在开发之初没有选择熟悉的架构,该用现代化的开发方式,选用了 JS 语言来开发。在前期花了不少功夫来快速入门 React, Antd Pro, Koa 以及 TypeORM。 选择现代化框架虽然是正确的,但是因为需要快速入门而研读各类手册及教程给了我不小的压力。所以在入门之后,就在边学习「全栈公开课2020」边进行程序开发。 第一版的系统在一个月内上线,虽然自己在开发系统时考虑了很多便利性的功能,但是因为业务仍需要重复工作将数据录入至系统,所以业务员使用的意愿不是很强烈。这反映出了前期的调研不够严谨和充分。这也导致第二版系统几乎要重做。 严谨而充分的调研,会减少错误的劳动。 2020年的计划完成情况较上一年好: 阅读完成了 4本书,完成率 40%。 吉他完成了 1首练习曲,完成率 4.54%。 练字仅上半年坚持,持续了23小时。 健身从五月份开始,基本上完成了任务,一共上了 82节私教课。 全栈公开课完成了 3个章节 阅读和练字有一方面原因是因为午休时间减少了,但主要原因依然是执行力不够。 全栈公开课本应该在12月底全部完成的,因为第二版的开发影响了进度,在2021年要全部学完的。 ","date":"2021-01-15","objectID":"/2021/01/annual-report-2020/:1:0","tags":["年度总结"],"title":"2020年年度总结","uri":"/2021/01/annual-report-2020/"},{"categories":["Report"],"content":"PLUS 加入了「公司工会文体组」 修复了「公司官网」的木马 喝醉了 2次 ","date":"2021-01-15","objectID":"/2021/01/annual-report-2020/:2:0","tags":["年度总结"],"title":"2020年年度总结","uri":"/2021/01/annual-report-2020/"},{"categories":["Report"],"content":"结语 这一年依旧是因为事情比较杂和多,对于一年的主题「Do One Thing Perfect」践行的不够理想,仅在下半年做的还可以,没有畏惧新事物带来的压力,持续学习和开发。在阅读、健身、学习方面完成的较好,练字及器乐方面完成的不够理想。总体来说今年算是及格吧。 在 2021年,摒弃一些细微末节,重心放在学习以及沟通方面的提升吧。 一生很短,遗憾很多,人生在不断失去,人生也在不断获得。未来的自己一定不要辜负现在你受到的伤痛,爱所爱的人,也要爱自己。 ","date":"2021-01-15","objectID":"/2021/01/annual-report-2020/:3:0","tags":["年度总结"],"title":"2020年年度总结","uri":"/2021/01/annual-report-2020/"},{"categories":["Notes"],"content":"本文是博主学习赫尔辛基大学的 全栈公开课2020 过程中的学习笔记,文章分类结构与课程会有些许不同,本文部分内容引用自原文。","date":"2020-12-09","objectID":"/2020/12/fullstackopen-nodejs-express/","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 03 - 用 NodeJS 和 Express 写服务端程序","uri":"/2020/12/fullstackopen-nodejs-express/"},{"categories":["Notes"],"content":"Node.js 与 Express 前端浏览器还不支持 JavaScript 的最新特性,所以在浏览器运行的代码是 babel 转译过的,而在后端运行 JavaScript 的情况是使用 Node ,而 Node 支持大部分最新的 JavaScript 特性,所以后端代码不需要转译。 npm 来源于 Node 生态,是管理 JavaScript 包的工具。 一般情况在终端使用 node index.js 即可启动项目,但最好的做法是在项目的 package.json 中定义脚本: { // ... \"script\": { \"start\": \"node index.js\", // ... }, // ... } 之后只要在项目根目录使用 npm start 即可启用项目。 简易服务器 该部分仅作了解即可,在实际项目中这样的方式太麻烦。主流的方式是使用例如 Express 这类的库。 新建一个项目,在根目录使用 npm init 来初始化项目,创建 index.js : const http = require('http') const app = http.createServer((request, response) =\u003e { response.writeHead(200, { 'Content-Type': 'text/plain' }) response.end('Hello World') }) const PORT = 3001 app.listen(PORT) console.log(`服务器运行在 ${PORT} 端口`) 通过 npm start 即可启动服务器,通过浏览器即可访问 http://localhost:3001。 如服务器提供的数据是 json,需要将 Content-Type 改为 application/json。输出的数组需要进行 JSON.stringify(array) 处理。 Node.js 使用了 CommonJS,还不支持 ES6 模块,所以不能使用 import http from 'http'。 Web and express 在项目根目录安装 npm install express。因为使用了 npm 来安装,所以会自动在项目 package.json 添加 express 依赖: { // ... \"dependencies\": { \"express\": \"^4.17.1\" } } ^4.17.1 限制了该项目支持的 express 的最低版本。 让原先 index.js 使用 express 库。 const express = require('express') const app = express() let notes = [ // 略 ] // 定义路由 // 处理对应用 '/' 的 HTTP GET 请求 app.get('/', (req, res) =\u003e { // response 响应请求,返回 \u003ch1\u003eHello World!\u003c/h1\u003e。express 会自动设置 Content-Type 为 text/html,状态码 200 res.send('\u003ch1\u003eHello World!\u003c/h1\u003e') }) // 处理对应用 '/api/notes' 的 HTTP GET 请求 app.get('/api/notes', (req, res) =\u003e { // response 响应请求,返回 json 数据。express 会自动设置 Content-Type 为 application/json,状态码 200 res.json(notes) }) // 服务器运行端口 const PORT = 3001 app.listen(PORT, () =\u003e { console.log(`服务器运行在 ${PORT} 端口`) }) nodemon 通过使用 nodemon,可以使应用在开发过程中由于代码的修改而自动重启服务,从而避免每次修改完代码后都需要重新 npm start 项目。 通过 npm install nodemon --save-dev 在项目中添加开发依赖,会在 package.json 的开发依赖中定义。 { //... \"dependencies\": { \"express\": \"^4.17.1\", }, \"devDependencies\": { \"nodemon\": \"^2.0.2\" } } 开发依赖是在开发时需要用到的而在生产环境中用不到的依赖。 使用方法还是在 package.json 的增加脚本,而后通过 npm run dev 来启动,这于 start 和 test 不同,需要在命令中加入 run。 { // .. \"scripts\": { \"start\": \"node index.js\", \"dev\": \"nodemon index.js\", \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\" }, // .. } REST 在 RESTful thinking 中称为 resource。 每个 resource 都有一个相关联的 URL,这个 URL 是资源的唯一地址。 一个约定是结合 resource 类型名称和 resource 的唯一标识符来创建 resource 唯一的地址。 假设根目录为 /api,那么笔记的集合则是 /api/notes ,单个笔记则是 /api/notes/10。 对资源又可以进行不同的操作,以下表格可以粗略地定义为 REST 所指的 统一接口 uniform interface: URL Verb functionality notes GET 获取整个 resources 集合 notes POST 根据 request 的数据创建新 resource notes/10 GET 获取指定的 resource notes/10 DELETE 删除指定的 resource notes/10 PUT 根据 request 的数据修改指定的整个 resource notes/10 PATCH 根据 request 的数据修改指定的 resource 的部分数据 REST API 可以当作为是一种约定,而非一种标准,世界上大多数 REST API 都不符合 Fielding 在其论文中概述的原始标准。所以在编写 API 时要有一致性,以便系统进行合作。 Fetching a single resource 获取一个单一资源 我们约定的单个笔记的唯一地址是 notes/10,其中 10 是笔记的唯一 id 号。通过冒号语法为路由定义参数: // 处理对应 api/notes/id 的路由,其中 id 可以为任意字符串 app.get('/api/notes/:id', (req, res) =\u003e { // 从 request 中获得 id 参数,并将 id 更改为 number const id = Number(req.params.id) const note = notes.find(note =\u003e note.id === id) if (note) { res.json(note) } else { // 笔记不存在则返回 404 状态码 res.status(404).end() } }) Deleting Resources 删除资源 app.delete('/api/notes/:id', (req, res) =\u003e { const id = Number(req.params.id) notes = notes.filter(note =\u003e note.id !== id) // 返回 204 状态码 res.status(204).end() }) Receiving data 接收数据 向 /api/notes 发送 HTTP POST 请求,并以 JSON 格式在 request body 中发送新笔记的信息,需要使用到 express json-parser,它与命令 app.use(express.json()) 一起使用。 const express = require('express') const app = express() app.use(express.json()) const generateId = () =\u003e { const maxId = notes.length \u003e 0 ? Math.max(...notes.map(note =\u003e note.id)) // 使用展开语法将 notes 中所有的 id 都展开出来 : 0 return maxId + 1 } // ... app.post('/api/notes', (req, res) =\u003e { const body = req.body if (!body.content) { // 使用 return 返回 400 状态码以及错误提示并阻止代码继续执行 return res.status(400).json( { error: '内容缺失' }) } const note = { content: body.content, important: body.important || false, data: new Date(), id: generateId(), } notes = notes.concat(note) res.json(note) }) 像","date":"2020-12-09","objectID":"/2020/12/fullstackopen-nodejs-express/:0:1","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 03 - 用 NodeJS 和 Express 写服务端程序","uri":"/2020/12/fullstackopen-nodejs-express/"},{"categories":["Notes"],"content":"将应用部署到网上 Same origin policy and CORS 同源政策和 CORS Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts) on a web page to be requested from another domain outside the domain from which the first resource was served. A web page may freely embed cross-origin images, stylesheets, scripts, iframes, and videos. Certain “cross-domain” requests, notably Ajax requests, are forbidden by default by the same-origin security policy. Cross-origin resource sharing. —— 维基百科 同源策略 和 CORS 是 Web 应用的通用原则。 在 Node 项目中可以使用 cors 中间件来允许来自其他的请求。 通过 npm install cors 来安装。 const cors = require('cors') app.use(cors()) Application to the Internet 将应用部署到网上 使用 Heroku 来部署应用。 在项目根目录新建 Procfile 文件,在文件内填写 web: npm start 来告诉 Heroku 如何启动应用。 将应用的 index.js 中端口改为环境变量: const PORT = process.env.PORT || 3001 // ... 在应用内创建 git 仓库,并使用 git 方式或者 ssh 方式将应用部署至 Heroku 上,方法同其他 git 方式,VS code 集成了 git 功能,可以直接使用,需要注意的是,git push 时候,需要的是 Heroku 的 Access API 而不是用户密码。 Frontend production build 前端生产构建 目前为止,应用处于开发模式中运行,简言之就是「人类可读」的环境,在部署应用时,我们需要将应用创建一个生产构建或为生产而优化的版本,也就是「机器可读」的环境。 create-react-app 创建的应用可以使用 npm build 命令来构建。 通过在应用根目录运行这个命令,将会创建一个名为build 的目录(其中包含应用中唯一的 HTML 文件index. HTML) ,其中包含目录 static。 应用的 JavaScript 代码的 Minified 版本将生成到 static 目录。 即使应用代码位于多个文件中,所有的 JavaScript 都将被缩小到一个文件中。 实际上,来自所有应用依赖项的所有代码也将缩小到这个单一文件中。 Serving static files from the backend 从后端服务部署静态文件 将前端构建的 build 文件夹复制到后端应用的根目录,通过 express 的内置的 static 中间件来现实前端构建的内容。 app.use(express.static('build')) 当 express 收到 HTTP GET 请求时,它会首先检查 build 目录是否包含与请求地址对应的文件,并返回相应的内容。 这样的方式采用了前后端在一起的方式,所以可以将前端的 baseUrl 改成相对路径 /api/notes 即可。 在确保生产环境在本地正常之后,将生产构建 git push 至 Heroku 完成部署。 Streamlining deploying of the frontend 流程化前端部署 通过更改后端 package.json 的 scripts 来实现流程化构建,以下直接引用了教材内容,一般来说根据项目实际情况来填写这些 scripts { \"scripts\": { //... \"build:ui\": \"rm -rf build \u0026\u0026 cd ../../osa2/materiaali/notes-new \u0026\u0026 npm run build --prod \u0026\u0026 cp -r build ../../../osa3/notes-backend/\", \"deploy\": \"git push heroku main\", \"deploy:full\": \"npm run build:ui \u0026\u0026 git add . \u0026\u0026 git commit -m uibuild \u0026\u0026 npm run deploy\", \"logs:prod\": \"heroku logs --tail\" } } Proxy 代理 在前端开发时,因为之前将 baseUrl 更改成后端的相对路径,所以在开发模式运行前端内容时,并不能获取到准确的为止,所以此时需要通过代理,将相对路径的请求转发至后端服务器。 在 package.json 增加 proxy 代理设置来转发。 { // ... \"scripts\": { // ... }, \"proxy\": \"http://localhost:3001\" } 方法的一个劣势,是前端部署的复杂程度。 部署新版本需要生成新的前端生产构建并将其复制到后端存储库。 这使得创建一个自动化的部署管道变得更加困难。 部署管道是指通过不同的测试和质量检查将代码从开发人员的计算机转移到生产环境的自动化控制的方法。 ","date":"2020-12-09","objectID":"/2020/12/fullstackopen-nodejs-express/:0:2","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 03 - 用 NodeJS 和 Express 写服务端程序","uri":"/2020/12/fullstackopen-nodejs-express/"},{"categories":["Notes"],"content":"将数据存入 MongoDB Debugging Node applications 调试 Node 应用 将数据 console.log 到控制台是一种可靠的方法。 使用 VS Code 的代码调试器,在软件的 Run 菜单下选择 Add Configuration… 来配置 debug 的设置,选择代码使用的环境 Node.js 会自动生成配置文件,然后选择 Start Debugging 开始调试。 使用 Google Dev Tools 调试应用,在控制台使用 node --inspect index.js 进行调试,也可以在 Console 控制台点击 Node logo 开启。系统需要全局安装 Node,如果只是在项目中安装 Node 是使用命令,也不显示 Node logo 的 质疑一切,出现 bug 时,逐一排除所有的可能性,将 bug 修复后再继续编写代码。 MongoDB MongoDB 不同于 MySQL 等其他关系数据库,它时文档数据库,它通常被归类为 NoSQL 使用 MongoDB Atlas 为应用提供数据存储服务,也可以在本地创建 MongoDB。 使用 Mongoose 库来代替 MongoDB 官方的驱动程序操作数据库会非常方便。Mongoose 可以被描述为 ODM(Object Document Mapper),它可以非常简单的将 JavaScript 对象保存为 Mongo 文档。 在项目中使用 npm install mongoose 安装 Mongoose。 新增 mongo.js 用于与数据库的连接: const mongoose = require('mongoose') if ( process.argv.length \u003c 3 ) { console.log('请提供连接数据库的密码:node mongo.js \u003cpassowrd\u003e') process.exit(1) } const password = process.argv[2] const url = `mongodb+srv://fullstack:${password}@cluster0-ostce.mongodb.net/test?retryWrites=true` mongoose.connect( url, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false, useCreateIndex: true } ) 可以通过修改 url 中的 test 来更改数据库名称,如果数据库中没有这个数据库,它会在连接成功后自动添加。 Schema 以下定义了笔记的 Schema 模式和匹配的 Model 模型。 // mongo.js // ... const noteSchema = new mongoose.Schema( { content: String, date: Date, important: Boolean, } ) const Note = mongoose.model('Note', noteSchema) Schema 告诉 Mongoose 如何将 note 对象存储在数据库中。 在 Note 模型定义中,第一个 “Note” 参数是模型的单数名。集合的名称将是小写的复数 notes,因为 Mongoose 约定是当模式以单数(例如 Note)引用集合时自动将其命名为复数(例如 notes)。 像 Mongo 这样的文档数据库是 schemaaless,这意味着数据库本身并不关心存储在数据库中的数据的结构。 可以在同一集合中存储具有完全不同字段的文档。 Mongoose 背后的思想是,存储在数据库中的数据在 application 级别上被赋予一个 schema,该模式定义了存储在任何给定集合中的文档的形状。 Creating and saving objects 创建和保存对象 在 Node Model 模型的帮助下,创建新的 Note 非常简单: // mongo.js // ... const note = new Note( { content: '新的 note', date: new Date(), important: false, } ) 模型是所谓的构造函数 constructor function,它根据提供的参数创建新的 JavaScript 对象。 由于对象是使用模型的构造函数创建的,因此它们具有模型的所有属性,其中包括将对象保存到数据库的方法。 通过 save() 方法来保存新的 note: // mongo.js // ... note.save().then(result =\u003e { console.log('保存成功') // 关闭数据库连接,否则程序无法完成它的执行。 mongoose.connection.close() }) Fetching objects from the database 从服务器获取对象 使用 find() 方法来获取: // mongo.js // ... Note.find({}).then(result =\u003e { result.forEach(note =\u003e { console.log(note) }) mongoose.connection.close() }) find({}) 方法中 {} 是空对象,表示没有检索条件,数据库会返回所有结果。 find({ important: true }) 使用这样的条件将会返回所有重要的笔记。 Backend connected to a database 后端连接到数据库 使用与上方相同的方法,将数据库连接的代码添加到 index.js 中去,注意,若数据库密码不从 process 中得到,而直接保存在 url 中,切勿将带有密码的文件提交至 Github,并将路由调整如下: route.get('/api/notes/',(req, res) =\u003e { Note.find({}).then(notes =\u003e { res.json(notes) }) }) 如果不想要返回 _id 和 __v 字段,通过 Schema 的 toJSON 方法来修改,如下: 注意一点,mongo 的 _id 字段看起来像个 String 类型,但它其实是个对象 noteSchema.set('toJSON', { transform: (document, returnedObject) =\u003e { returnedObject.id = returnedObject._id.toString() // _id 字段是对象,需要 toString 方法来转换成 String delete returnedObject._id; delete returnedObject.__v; } }) Database configuration into its own module 数据库逻辑配置到单独的模块 便于维护及管理,将数据库逻辑配置到单独的模块是较好的选择。 在项目根目录下创建 models 文件夹,并在该文件夹下新建 note.js 文件: const mongoose = require('mongoose') const url = process.env.MONGODB_URI console.log('正在连接', url) mongoose.connect ( url, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false, useCreateIndex: true } ) .then(result =\u003e { console.log('成功连接 MongoDB') }) .catch((error)=\u003e { console.log('连接 MongoDB 失败:', error.message) }) const noteSchema = new mongoose.Schema({ content: String, date: Date, important: Boolean, }) noteSchema.set('toJSON', { transform: (document, returnedObject) =\u003e { returnedObject.id = returnedObject._id.toString() delete returnedObject._id delete returnedObject.__v } }) module.exports = mongoose.model('Note', noteSchema) 此处定义 Note modules 与定义 ES6 模块方式略有不同。 模块的公共接口是通过将值设置为 module.exports 变量来定义的。 我们将该值设置为 Note 模型。模块内部定义的其他东西,比如变量 mongoose 和 url 对于模块的用户来说是不可访问的或者不可见的。 在 index.js 中导入 note 模块即可: const Note = require('./models/note') 将数据库的 url 直接编入代码中不是一个安全的选择,将它设置为环境变量 MONGODB_URI 传递给应用会更合适。 定义环境变量的方式有很多种: 在启动时定义。 在 packag","date":"2020-12-09","objectID":"/2020/12/fullstackopen-nodejs-express/:0:3","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 03 - 用 NodeJS 和 Express 写服务端程序","uri":"/2020/12/fullstackopen-nodejs-express/"},{"categories":["Notes"],"content":"ESLint 与代码检查 先前在路由中检查笔记的有效性,如果没有数据,将返回 400 错误信息以及错误信息「提交的内容缺失」: app.post('/api/notes', (req, res) =\u003e { const body = req.body if (body.content === undefined) { return res.status(400).json({ error: '提交的内容缺失' }) } // ... }) 在数据存储到数据库之前验证数据的一个更好的方法是使用 mongoose 提供的 validation 功能。 const noteSchema = new mongoose.Schema( { content: { type: String, // 字符串 minLength: 5, // 最小长度 5 字符 required: true // 必填 }, date: { type: Date, // 日期 required: true // 必填 }, important: Boolean // 布尔值 } ) minlength 和 required 验证器是内置的 ,由 Mongoose 提供。如果没有一个内置的验证器满足我们的需求的话,Mongoose 允许我们创建新的验证器自定义验证器。 在 errorHandler 中间件增加 validation 的判断: const errorHandler = (err, req, res, next) =\u003e { console.log(err) if (err.name === 'CastError' \u0026\u0026 err.kind === 'ObjectId') { return res.status(400).send({ error: 'error id' }) } else if (err.name === 'ValidationError') { return res.status(400).json({ error: err.message }) } next(err) } Promise chaining 承诺链 教材所讲的是承诺链的概念,所用的案例并不是很典型,引用作者的话: 在这个例子中,承诺链没有提供多少好处。 但要是有许多必须按顺序进行的异步操作,情况就会发生变化……在本课程的下一章节中,我们将学习 JavaScript 中的async/await 语法,这将使编写后续的异步操作变得容易得多。 note.save() .then() .then() .then() .catch() .then 返回了一个 Promise,通过多个 .then 方法组成了 Promise Chaining。 如同 then 的字面意思,代码是依次执行的。 Deploying the database backend to production 将数据库后端部署到生产环境 略 Lint Lint 是什么? Generically, lint or a linter is any tool that detects and flags errors in programming languages, including stylistic errors. The term lint-like behavior is sometimes applied to the process of flagging suspicious language usage. Lint-like tools generally perform static analysis of source code. 通常,lint 或 linter 是检测和标记编程语言中的错误,包括文本错误的一种工具。 lint-like 这个术语有时用于标记可疑的语言使用情况。 类似 lint 的工具通常对源代码执行静态分析。 在像 Java 这样的编译静态类型语言中,像 NetBeans 这样的 IDE 可以指出代码中的错误,甚至那些不仅仅是编译错误的错误。 执行静态分析的额外工具,如检查样式 ,可以用来扩展 IDE 的功能,也指出与样式有关的问题,如缩进。 在 JavaScript 的世界里,目前主要的静态分析工具又名 「linting」是 ESlint。 安装 ESlint 作为开发依赖: npm install eslint --save-dev 初始化默认设置: node_modules/.bin/eslint --init 该配置将保存在 .eslintrc.js 文件中。 可根据习惯修改规则,比如使用 2 个 space。 检查验证方式: node_modules/.bin/eslint index.js 为 linting 创建一个单独的脚本 { // ... \"scripts\": { \"start\": \"node index.js\", \"dev\": \"nodemon index.js\", // ... \"lint\": \"eslint .\" }, // ... } 在根目录新建 .eslintignore 并增加想要忽略检查的文件。 安装 eslint-plugin 来替代使用命令检查代码中的错误,ESlint 插件会将不符合规则的代码使用红色波浪线标记出来。 ESlint 有大量的规则, 通过在 .eslintrc.js 文件中编辑增加规则即可。 许多公司定义了通过 ESlint 配置文件在整个组织中执行的编码标准。 建议不要一遍又一遍地使用重造轮子,从别人的项目中采用现成的配置到自己的项目中可能是一个好主意。 最近,很多项目都采用了 Airbnb 的 Javascript 风格指南,使用了 Airbnb 的 ESlint 。 ","date":"2020-12-09","objectID":"/2020/12/fullstackopen-nodejs-express/:0:4","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 03 - 用 NodeJS 和 Express 写服务端程序","uri":"/2020/12/fullstackopen-nodejs-express/"},{"categories":["Notes"],"content":"本文是博主学习赫尔辛基大学的 全栈公开课2020 过程中的学习笔记,文章分类结构与课程会有些许不同,本文部分内容引用自原文。","date":"2020-11-10","objectID":"/2020/11/fullstackopen-server/","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 02 - 与服务器通信","uri":"/2020/11/fullstackopen-server/"},{"categories":["Notes"],"content":"从渲染集合到模块学习 使用 VS Code 可以安装 React 的代码片段 Snippets,安装在这里。 善用 console.log 来进行调试,使用 console.log('props value is', props),用 , 分隔而不是用 + 连接 object。 在应用崩溃使用 console.log 来调试时,应该从最先渲染的组件开始插入 console.log 来排查出错问题的位置,然后结合 打印数组、对象等方式找出具体的问题并解决,直到程序正常运行为止。 JavaScript Arrays JS数组 学习视频,待整理 Rendering collections with Map method 用 Map 方法渲染集合 import React from 'react' import ReactDOM from 'react-dom' const notes = [ { id: 1, content: '我喜欢 react', date: '2020-10-29T15:17:10.098Z', important: true }, { id: 2, content: '启动电脑开VS,欢迎来到编程世界。', date: '2020-10-29T15:18:26.092Z', important: false }, { id: 3, content: 'GET 和 POST 是 HTTP 协议中最重要的方法', important: true } ] const App = (props) =\u003e { const { notes } = props return ( \u003cdiv\u003e \u003ch1\u003e笔记\u003c/h1\u003e \u003cul\u003e \u003cli\u003e{notes[0].content}\u003c/li\u003e \u003cli\u003e{notes[1].content}\u003c/li\u003e \u003cli\u003e{notes[2].content}\u003c/li\u003e \u003c/ul\u003e \u003c/div\u003e ) } ReactDOM.render( \u003cApp notes={notes} /\u003e, document.getElementById('root') ) 以上 notes 数组仅有三个对象,可以通过引用一个硬编码的索引号来访问数组中对象。 使用 map 函数从数组对象生成 React 元素。 notes.map(note =\u003e \u003cli\u003e{note.content}\u003c/li\u003e) 通过这样的方法可以生成 li 元素的数组。 [ \u003cli\u003e我喜欢 react\u003c/li\u003e, \u003cli\u003e启动电脑开VS,欢迎来到编程世界。\u003c/li\u003e, \u003cli\u003eGET 和 POST 是 HTTP 协议中最重要的方法\u003c/li\u003e, ] 现在重构之前的代码,如下: const App = (props) =\u003e { const { notes } = props return ( \u003cdiv\u003e \u003ch1\u003e笔记\u003c/h1\u003e \u003cul\u003e {notes.map( note =\u003e \u003cli\u003e{note.content}\u003c/li\u003e )} \u003c/ul\u003e \u003c/div\u003e ) } map 的工作方式 const result = notes.map(note =\u003e note.id) console.log(result) // 打印出 [1,2,3] 使用 map 方法会创建一个新数组,其元素是从原始数组通过 mapping 映射创建的,映射的逻辑是使用作为 map 方法传递进去的函数。 这个函数是 // 紧凑形式 note =\u003e note.id // 以上函数的完整形式 (note) =\u003e { return note.id } 该函数获取一个 note 对象作为参数,然后番位其 id 字段的值。 Key attribute Key属性 正如 React 列表 \u0026 Key 的说明,列表项,即 map 方法生成的每个元素,都必须有一个唯一的键值,名为 key 的属性。 const App = (props) =\u003e { const { notes } = props return ( \u003cdiv\u003e \u003ch1\u003e笔记\u003c/h1\u003e \u003cul\u003e {notes.map(note =\u003e \u003cli key={note.id}\u003e {note.content} \u003c/li\u003e )} \u003c/ul\u003e \u003c/div\u003e ) } 虽然说可以使用数组的索引作为键,避免控制台报错,但这仍然可能会导致意想不到的问题。,这有问题案例 // 不要这样做 \u003cul\u003e {notes.map((note, index) =\u003e \u003cli key={index}\u003e {note.content} \u003c/li\u003e )} Refactoring modules 重构模块 将 App 重构,使得 App 更简洁易用。 // 新增 Note 组件 const Note = ({ note }) =\u003e { return ( \u003cli\u003e{note.content}\u003c/li\u003e ) } const App = ({ notes }) =\u003e { return ( \u003cdiv\u003e \u003ch1\u003e笔记\u003c/h1\u003e \u003cul\u003e {notes.map(note =\u003e \u003cNote key={note.id} note={note} /\u003e )} \u003cul\u003e \u003c/div\u003e ) } 此处要注意,这样必须在 Note 组件定义 key 属性,而不是在 li 标签定义。 通常来说,在较小型的应用中,组件一般放在 src/components 目录下,一般约定按照组件名称来命名文件。 例如创建一个 Node 组件,我们将 Node.js 文件存在 components 目录下,其文件内容为 import React from 'react' const Note = ({ note }) =\u003e { return ( \u003cli\u003e{note.content}\u003c/li\u003e ) } export default Note 最后一行 export 是在声明模块,即变量 Note。 那么在使用这个组件的文件中,使用 import 方法来使用这个模块。 import React from 'react' import ReactDom from 'react-dom' import Note from './components/Note' const App = ({ notes }) =\u003e { // ... } 导入自己的组件时,它们的位置必须给出导入文件的相对路径。 './components/Note' 开头的 . 是指当前工作目录,因此引入文件的位置是当前目录下的 components 文件夹中的 Node.js 文件,其中 .js 可以省略。 ","date":"2020-11-10","objectID":"/2020/11/fullstackopen-server/:0:1","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 02 - 与服务器通信","uri":"/2020/11/fullstackopen-server/"},{"categories":["Notes"],"content":"表单 使用 useState 方法将新增的笔记添加到 App 组件状态中。 const App = ({ notes }) =\u003e { const [notes, setNotes] = useState(notes) const [newNote, setNewNote] = useState('a new note...') const addNote = (event) =\u003e { event.preventDefault() // 阻止事件的默认操作 const noteObject = { id: notes.length + 1, content: newNote, date: new Date().toISOString(), important: Math.random() \u003c 0.5, } setNotes(notes.concat(noteObject)) // 使用 concat 方法来新建 setNewNote('') } const handleNoteChange = (event) =\u003e setNewNote(event.target.value) return ( \u003cdiv\u003e \u003ch1\u003e笔记\u003c/h1\u003e \u003cul\u003e {notes.map(note =\u003e \u003cNote key={note.id} note={note} /\u003e )} \u003cul\u003e \u003cform onSubmit={addNote}\u003e \u003cinput value={newNote} onChange={handleNoteChange} /\u003e \u003cbutton type=\"submit\"\u003esave\u003c/button\u003e \u003c/form\u003e \u003c/div\u003e ) } 其中注意点 \u003cinput /\u003e 组件中,如果只有 value={newNote} 属性受控,将会导致 input 组件渲染成一个只读元素,这将正确的修改 input 的value,必须搭配 onChange={handleNoteChange} 才能正确控制 input 元素的状态。相反的,如果只有 onChange={handleNoteChange} 而没有 value={newNote},那样 setNewNote('') 将不会重置 input 元素的值。 Filtering Displayed Elements 过滤显示的元素 知识点 三目运算符 - condition ? val1 : val2 当 condition 为 true 时,返回 val1,否则返回 val2 数组的 filter 方法 - arr.filter() import React, { useState } from 'react' import Note from './components/Note' const App = (props) =\u003e { const [notes, setNotes] = useState(props.notes) const [newNote, setNewNote] = useState('') const [showAll, setShowAll] = useState(true) // ... const notesToShow = showAll ? notes : notes.filter(note =\u003e note.important) // 因为 note.important 本身是布尔值,所以省略了 '=== true' 的判断 return ( \u003cdiv\u003e \u003ch1\u003eNotes\u003c/h1\u003e \u003cdiv\u003e \u003cbutton onClick={() =\u003e setShowAll(!showAll)}\u003e show {showAll ? '显示重要' : '显示全部' } \u003c/button\u003e \u003c/div\u003e \u003cul\u003e {notesToShow.map(note =\u003e \u003cNote key={note.id} note={note} /\u003e )} \u003c/ul\u003e // ... \u003c/div\u003e ) } 通过三目运算符判断 showAll 的状态来过滤需要显示的数据以及按钮的值。 ","date":"2020-11-10","objectID":"/2020/11/fullstackopen-server/:0:2","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 02 - 与服务器通信","uri":"/2020/11/fullstackopen-server/"},{"categories":["Notes"],"content":"从服务器获取数据 一般的项目包含前端「客户端」和后端「服务端」。截至目前,程序仅涉及到前端的开发。 接下来使用 JSON 服务器 作为后端。 使用 npm install -g json-server 执行全局安装 json-server,也可以在应用根目录使用 npx json-server --port 3001 --watch db.json 运行 json-server 服务器。 在项目根目录创建 db.json : { \"notes\": [ { \"id\": 1, \"content\": \"我喜欢 react\", \"date\": \"2020-10-29T15:17:10.098Z\", \"important\": true }, { \"id\": 2, \"content\": \"启动电脑开VS,欢迎来到编程世界。\", \"date\": \"2020-10-29T15:18:26.092Z\", \"important\": false }, { \"id\": 3, \"content\": \"GET 和 POST 是 HTTP 协议中最重要的方法\", \"date\": \"2020-10-29T15:17:10.098Z\", \"important\": true } ] } 为什么使用 3001 端口?是因为前端 React 程序占用了 3000 端口,所以将 json-server 设定为 3001 端口。 可以通过 http://localhost:3001/notes 来访问 db.json 的 notes 数据了。 选用 json-server 作为后端服务器的原因是在开发阶段可以很快速的实现功能。实际项目一般会将数据存在数据库中,如 MySQL MongoDB 等。 The browser as a runtime environment XHR「XMLHttpRequest」是1999年引入的技术,使用 XHR 对象发出 HTTP 请求。 现代浏览器基本上都支持了 promises 的 fetch 方法,而不是 XHR 使用的事件驱动型,所以现在一般也不用 XHR 方法。 但还是有必要了解一下 XHR 方法如何请求数据的。 const xhttp = new XMLHttpRequest() xhttp.onreadystatechange = function() { if (this.readyState == 4 \u0026\u0026 this.status == 200) { const data = JSON.parse(this.responseText) } } xhttp.open('GET', '/data.json', true) xhttp.send() 以上将事件处理程序注册到 xhttp 对象,当 xhttp 的状态发生改变时执行。XHR 请求是异步执行,并非自上而下的同步执行。 JavaScript 引擎,或者运行环境,遵循异步模型。原则上所有的 IO 操作「除了一些特例」都以非阻塞方式执行。这意味着代码执行在调用 IO 函数之后立即继续,而不需要等待它返回。 异步操作完成的某个时刻,JavaScript 引擎才会调用注册到该操作的事件处理程序。 JavaScript 是单线程的,所以它并不能并行执行代码,若没有使用非阻塞方式,浏览器将会在执行代码时卡住,直到代码执行结束才恢复响应。 为了保证浏览器的 responsive,代码逻辑要让任何一个单一计算不花费太多时间。 现代浏览器可以使用 Web Worker 来运行并行化代码。但注意的是单个浏览器窗口仍然是由一个单线程处理。 npm 目前几乎所有 JavaScript 项目都是使用 node 包管理器定义的,也就是 npm。使用 npm 会在项目根目录创建一个 package.json 文件: { \"name\": \"notes\", \"version\": \"0.1.0\", \"private\": true, \"dependencies\": { \"@testing-library/jest-dom\": \"^4.2.4\", \"@testing-library/react\": \"^9.4.0\", \"@testing-library/user-event\": \"^7.2.1\", \"react\": \"^16.12.0\", \"react-dom\": \"^16.12.0\", \"react-scripts\": \"3.3.0\" }, \"scripts\": { \"start\": \"react-scripts start\", \"build\": \"react-scripts build\", \"test\": \"react-scripts test\", \"eject\": \"react-scripts eject\" }, \"eslintConfig\": { \"extends\": \"react-app\" }, \"browserslist\": { \"production\": [ \"\u003e0.2%\", \"not dead\", \"not op_mini all\" ], \"development\": [ \"last 1 chrome version\", \"last 1 firefox version\", \"last 1 safari version\" ] } } dependencies 定义了该项目所需要的依赖或外部库。 安装依赖也非常方便,在项目根目录使用终端 npm install axios 命令即可。 当执行完成后,会在 package.json 的 dependencies 中添加 axios。当然我们也可以直接在 package.json 增加这一条,然后在根目录通过执行 npm install 来安装所有依赖。 } \"dependencies\": { // ... \"axios\": \"^0.19.2\", \"react\": \"^16.12.0\", \"react-dom\": \"^16.12.0\", \"react-scripts\": \"3.3.0\" }, // ... } 如何安装开发依赖?开发依赖是在开发中提供帮助,实际项目并不需要它。 npm install json-server --save-dev 以上安装了 JSON 服务器,在 package.json 中增加 server script 来帮助我们快速启动 JSON 服务器。 { // ... \"scripts\": { \"start\": \"react-scripts start\", \"build\": \"react-scripts build\", \"test\": \"react-scripts test\", \"eject\": \"react-scripts eject\", \"server\": \"json-server -p3001 --watch db.json\" }, } 这样可以通过 npm run server 来启动 JSON 服务器了。 Axios and promises axios 库是代替浏览器和服务器之间的通信,功能类似于 fetch。在上一节使用 npm 安装了 axios 库,在项目中像引入 react 库一样 import 即可。 import axios from 'axios' const promise = axios.get('http://localhost:3001/notes') console.log(promise) const promise2 = axios.get('http://localhost:3001/foobar') console.log(promise2) 由于 JSON 服务器中仅有 notes 数据,所以访问 http://localhost:3000 控制台会有报错,如下: Axios 的 get 方法会返回一个 promise。 Mozilla’s 网站上的文档对 promises 的解释: A Promise is an object representing the eventual completion or failure of an asynchronous operation. Promise承诺是一个对象,用来表示异步操作的最终完成或失败。 promise 是一个表示异步操作的对象,有三种不同状态 The promise is pending The promise is fulfilled The promise is rejected pending 表示还在提交中,最终值处于不可用状态。 fulfilled 表示数据已兑现,操作成功,最终值可用。这种状态有时也被称为 resolve。 rejected 表示拒绝,操作失败,说明出现了错误阻止最终值。 回到上面的示例,在一个请求的 PromiseStatus 是 resolved 也就是 fulfilled 状态,表示是成功的。而第二个是 rejected,控制台提示错误原因,是因为我们HTTP GET 请求的地址是不存在的「404错误」。 如果我们想要访问 promise 表示的操作结果,必须要向 promise 注册一个事件处理程序。这里是使用 then 方法实现。 const promise = axios.get('http://localhost:3001/notes') promise.then(response =\u003e { const notes = response.data }) JavaScript 运行时环境调用由 th","date":"2020-11-10","objectID":"/2020/11/fullstackopen-server/:0:3","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 02 - 与服务器通信","uri":"/2020/11/fullstackopen-server/"},{"categories":["Notes"],"content":"在服务端将数据 Alert 出来 REST 表现层状态转换 REST(Representational state transfer),不是一种标准,而是一种设计风格。REST通常基于HTTP、URI、XML以及HTML这些现有的广泛流行的协议和标准。 在 REST 术语中,我们将单个数据对象(如应用中的便笺)称为 resources。 每个资源都有一个唯一的地址——它的 URL。 根据 json-server 使用的一般约定,我们将能够在资源 URL, 即 notes/3 上定位某个便笺,其中3是资源的 id。 另一方面, notes url 指向包含所有便笺的资源集合。 通过 HTTP GET 请求从服务器获取资源。 例如,对 URL notes/3 的 HTTP GET 请求将返回 id 为3的便笺。 对 notes URL 的 HTTP GET 请求将返回所有便笺的列表。 根据 json 服务器遵守的 REST 约定,通过向 notes URL 发出 HTTP POST 请求来创建、存储新的便笺。 新便笺资源的数据在请求的 body 中发送。 Json-server 要求以 JSON 格式发送所有数据。 实际上,这意味着数据必须是格式正确的字符串,并且请求必须包含值为 application/json 的 Content-Type 请求头。 Sending Data to the Server 发送数据到服务器 使用 POST 方法将对象发送至服务器,创建一个新对象,不需要发送 id 属性,因为 id 交给服务器生成更加合理。 addNote = (event) =\u003e { event.preventDefault() const newObject = { content: newNote, date: new Date(), important: Math.random() \u003c 0.5, } axios .post('http://localhost:3001/notes', newObject) .then(response =\u003e { setNotes(notes.concat(response.data)) setNewNote('') }) } 在 POST 请求中发送的数据是一个 JavaScript 对象,axios 自动懂得为 Content-Type 头设置适当的 application/json 值。 通过 Chrome 开发工具的 Network 选项卡检查 HTTP 请求来查看是否符合预期。 Postman 工具用来调试服务器应用非常易用,Chrome 扩展官方已弃用(DEPRECATED),使用 App 功能更加强大。 Changing the important of Notes 向 Note 组件添加用于调整 Notes 的 important 值的按钮: const Note = ({ note, toggleImportance }) =\u003e { const label = note.important ? '设置为不重要' : '设置为重要' return ( \u003cli\u003e {note.content} \u003cbutton onClick={toggleImportance}\u003e{label}\u003c/button\u003e \u003c/li\u003e ) } 在 App 组件增加事件处理程序 toggleImportance: const App = () =\u003e { const [notes, setNote] = useState([]) const [newNote, setNewNote] = useState('') const [showAll, setShowAll] = useState(true) // ... const toggleImportance = (id) =\u003e { const url = `http://localhost:3001/notes/${id}` const note = notes.find(note =\u003e note.id === id) const changeNote = { ...note, important: !note.important } axios .put(url, changeNote) .then(response =\u003e { setNotes(notes.map(note =\u003e note.id !== id ? note : response.data)) }) } // ... return ( \u003cdiv\u003e \u003ch1\u003e笔记\u003c/h1\u003e \u003cdiv\u003e \u003cbutton onClick={() =\u003e setShowAll(!showAll)}\u003e show {showAll ? '显示重要' : '显示全部' } \u003c/div\u003e \u003cul\u003e {noteToShow.map((note) =\u003e \u003cNote key={note.id} note={note} toggleImportance={() =\u003e toggleImportance(note.id)} /\u003e )} \u003c/ul\u003e // ... \u003c/div\u003e ) } 通过 PUT 方法把对应 id 的 note 修改,修改成重要或是不重要。并通过回调函数将组件内的 Notes 状态更新。 Extracting communication with the backend into a separate module 将与后端通信提取到单独的模块中去,常用的存放目录是 src/services。 在 services 目录下创建 note.js: import axios from 'axios' const baseUrl = 'http://localhost:3001/notes' const getAll = () =\u003e axios.get(baseUrl) const create = (newObject) =\u003e axios.post(baseUrl, newObject) const update = (id, newObject) =\u003e axios.put(`${baseUrl}/${id}`, newObject) export default { getAll: getAll, create: create, update: update } 修改 App.js // ... import noteService from './services/notes' const App = () =\u003e { // ... useEffect(() =\u003e { noteService .getAll() .then(response =\u003e { setNotes(response.data) }) }, []) const toggleImportance = (id) =\u003e { const note = notes.find(note =\u003e note.id === id) const changeNote = { ...note, important: !note.important } noteService .update(id, changeNote) .then(response =\u003e { setNotes(notes.map(note =\u003e note.id !== id ? note : response.data)) }) } const addNote = (event) =\u003e { event.preventDefault() const noteObject = { content: newNote, date: new Date().toISOString(), important: Math.random() \u003e 0.5 } noteService .create(noteObject) .then(response =\u003e { setNotes(notes.concat(response.data)) setNewNote('') }) } // ... } export default App 如果整个 App 只使用 response 对象的 response.data 属性,那么可以使用如下方法会更好一些。 services/note.js 做如下修改; const getAll() =\u003e { const request = axios.get(baseUrl) return request.then(response =\u003e response.data) } // 其余方法以此类推 相应的 App 组件里对应的 service 也要做修改: noteService .getAll() .then(initialNotes =\u003e { setNotes(initialNotes) }) getAll 函数返回了一个 Promise, 当 HTTP 请求成功时,Promise 将返回从后端响应中发送回来的数据。 承诺Promise是现代 JavaScript 开发的核心,需要投入一定时间理解它们。 You do not know JS - Chapter 3 Promises Promise chaining cleaner syntax for defining object literals 用于定义对象字面量的更清晰的语法 上章节中,service/note.js 最后 export 了三个对象: export d","date":"2020-11-10","objectID":"/2020/11/fullstackopen-server/:0:4","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 02 - 与服务器通信","uri":"/2020/11/fullstackopen-server/"},{"categories":["Notes"],"content":"给 React 应用加点样式 导入外部 css 文件 内联样式 导入外部 css 文件的方式,在 index.js 使用 import import './index.css' 之后在 index.css 添加相关样式即可。常规 html 文件在元素中使用 class 属性来对应样式表的类选择器,而 react 中需要使用 className 来对应。 const Note = ({ note, toggleImportance }) =\u003e { const label = note.important ? '设置为不重要' : '设置为重要'; return ( \u003cli className='note'\u003e {note.content} \u003cbutton onClick={toggleImportance}\u003e{label}\u003c/button\u003e \u003c/li\u003e ) } 内联样式的使用方法如下: 需要注意的是,内联样式中无法使用 伪类 pseudo-classes。 const Footer = () =\u003e { const footerStyle = { color: 'green', fontStyle: 'italic', fontSize: 16 } return ( \u003cdiv style={footerStyle}\u003e \u003cbr /\u003e \u003cem\u003efooter content\u003c/em\u003e \u003c/div\u003e ) } 内联样式和其他一些将样式添加到 React 组件的方法完全违背了旧的惯例。 传统上,将 CSS 与内容(HTML)和功能(JavaScript)解耦被认为是最佳实践。 根据这个古老的思想流派,我们的目标是将 CSS、 HTML 和 JavaScript 编写到它们各自的文件中。 React的哲学,事实上,是这个极端的对立面。 由于将 CSS、 HTML 和 JavaScript 分离成单独的文件在大型应用中似乎不利于伸缩,所以 React 将应用按照其逻辑功能实体进行划分。 构成应用功能实体的结构单元是 React 组件。 React 组件定义了组织内容的 HTML,确定功能的 JavaScript 函数,以及组件的样式; 所有这些都放在一个地方。 这是为了创建尽可能独立和可重用的单个组件。 ","date":"2020-11-10","objectID":"/2020/11/fullstackopen-server/:0:5","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 02 - 与服务器通信","uri":"/2020/11/fullstackopen-server/"},{"categories":["Notes"],"content":"本文是博主学习赫尔辛基大学的 全栈公开课2020 过程中的学习笔记,文章分类结构与课程会有些许不同,本文部分内容引用自原文。","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":["Notes"],"content":" 关于笔记内容 本文是博主学习赫尔辛基大学的 全栈公开课2020 过程中的学习笔记,文章分类结构与课程会有些许不同,本文部分内容引用自原文。 ","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/:0:0","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":["Notes"],"content":"JavaScript ","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/:1:0","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":["Notes"],"content":"认识 Javascript JavaScript 标准的正式名称是ECMAScript。 目前最新的版本是2019年6月发布的,名为ECMAScript 2019 ,即ES10。 Variables 变量 JavaScript中有 const let var 这几种定义变量的方法,其中 const 实际上是定义了一个常量,也就是其值不能再修改。 let 定义了一个普通的变量。 var 在很长一段时间里,是 JavaScript的唯一定义变量的方法,其余两种是在 ES6 版本添加的。在一些特定情况,var 的工作方式与大多数语言中的变量定义相比是十分不同的。所以不建议使用 var。 值得注意的是 let 声明一个块作用域的局部变量,在该块区域以外是无法被调用的。 const a = 100 let b = 200 b += 10 // console.log(b) -\u003e 210 b = '你好' // console.log(b) -\u003e 你好 a = 1000 // 报错 Array 数组 数组可以使用 const 定义,因为数组是一个对象,而且数组的变量总是指向这同一个对象,当添加新元素的时,数组的内容也将发生变化。 const array = [1, 3, -3] // 定义 array 变量 array.push(9) // 向 array 数组添加元素 数字9 console.log(array.length) // 数组 length 为 4 console.log(array[1]) // 打印 array 的第 2 个元素 为 3 // 遍历数组使用 forEach array.forEach(value =\u003e { console.log(value) // 将数组所有内容依次打印出来 1, 3, -3, 9 }) 上述案例中使用的是 push 方法将新元素添加到数组中。在使用 React 时,经常使用函数式编程的技巧。函数编程范型的一个特点,就是使用不可变的数据结构。在React代码中,最好使用concat方法,因为它不向数组中添加元素,而是创建一个新数组,新数组中包含了旧数组和新的元素。 const array = [1, 3, -3] const array2 = array.concat(5) // 此时 array 没有改变 // array2 为 [1, 3, -3, 5] array.concat(5) 这种方法调用不会向 array 数组添加新的元素,而是直接返回一个包含 array 以及 concat 的元素的一个新数组。 map 方法遍历 以下案例使用了 map 方法创建了一个新数组,将 array 的每一个元素作为函数的入参来创建新的元素。 const array3 = array.map(value =\u003e value * 10) // array3 为 [10, 30, -30] map 方法还可以将数组转换成完全不同的内容,下例将 array 的整数值转换成了包含 HTML 字符串的数组。 const array4 = array.map(value =\u003e '\u003cli\u003e' + value + '\u003c/li\u003e') // array4 为 ['\u003cli\u003e1\u003c/li\u003e', '\u003cli\u003e3\u003c/li\u003e', '\u003cli\u003e-3\u003c/li\u003e'] 数组中的单个元素可以使用解构赋值赋给变量。 const array = ['apple', 'banana', 'cherry', 'durian', 'fig'] const [fruit1, fruit2, ... restFruit] = array // fruit1 为 apple // fruit2 为 banana // restFruit 为 [cherry, durian, fig] Objects 对象 定义对象的不同方式 对象字面量 (Object Literals),使用大括号 {} 使用句点 . 使用中括号 [] 对象属性的值可以是任何类型:整数 字符串 数组 对象等。 // 对象字面量 const object = { name: 'imagic', age: 100, company: { name: 'BBC', location: 'UK', }, devices: ['iPhone','MacBook Pro', 'raspberry'] } // 句点方式 和 中括号 // 引用 console.log(object.name) // 打印出 imagic console.log(object['name']) // 打印出 imagic // 添加 object.address = '221B Baker Street' object['nick name'] = 'carrot' // 因为 nick name 中间有空格,只能使用中括号 [] 来完成。 Functions 函数 // 定义函数 const sum = (num1, num2) =\u003e { return num1 + num2 } // 调用函数 const result = sum(10,3) // result 为 13 如果只有一个参数,我们可以在定义中去掉括号 const square = num =\u003e { return p * p } 如果函数只包含一个表达式,则不需要大括号。 const square = num =\u003e num * num 这个方式在操作数组时特别方便。如数组的 map 方法。 箭头函数是随 ES6 一起添加到 JavaScript. 在之前定义函数的唯一方法是使用 function。 // 定义函数 function square(num1, num2) { return num * num2 } // 函数表达式方法 const average = function(num1, num2) { return (num1 + num2) / 2 } Object method and “this” 对象方法以及“ this”关键字 箭头函数和使用 function 关键字的函数,在涉及到 this 关键字(指向对象本身)的行为上,有很大的不同。 function 方法 const object = { name: 'imagic', age: 100, greet: function () { console.log('Hi, I am ' + this.name) } } object.greet() // 打印出 'Hi, I am imagic' // 也可以在对象创建之后再赋值给对象 object.growOlder = function () { this.age += 1 } console.log(object.age) // 打印出 100 object.growOlder() console.log(object.age) // 打印出 101 对象中定义的 greet 方法可以通过赋值给变量的方法引用,但是要注意以下情况: object.greet() // 打印出 'Hi, I am imagic' const referenceToGreet = object.greet() referenceToGreet() // 打印出 'Hi, I am undefined' 这是因为通过引用调用 referenceToGreet() 方法时,该方法不认识 this 是什么。与其他语言相反,在 JavaScript 中,this 的值是根据 方法如何调用来定义的。 当通过引用调用该方法时,this 的值就变成了所谓的全局对象,这并不是我们所想要的结果。所以在开发时要尽量避免使用 this 来避免潜在的问题。 消除由 this 引起的问题的方法有几种办法: 使用 setTimeout 方法 使用 bind 方法 setTimeout(object.greet, 1000) 当使用 setTimeout 来调用 object.greet 方法时,实际上是 JavaScript 引擎在调用该方法,此时的 this 是指向的是全局对象。 setTimeout(object.greet.bind(object), 1000) 使用了 bind 方法创建了一个新函数,它将 this 绑定指向到了 object,这与方法的调用位置和方式无关。 使用箭头函数可以解决与 this 相关的一系列问题。 但是,它不能当做对象的方法来使用,因为那样的话 this 就不起作用了。 Classes 类 JavaScript 中并没有像面向对象程序语言中的类机制。 然而,JavaScript 中的一些新特性使得它能够「模拟」面向对象中的类。 与 ES6 一起引入到 JavaScript 中的类语法,它在很大程度上简化了 JavaScript 中的类(或者说像是类)的定义。 // 定义名为 Person 的 class class Person { constructor(name, age) { this.name = name this.age = age } greet() { console.log('Hi, I am ' + this.name) } } // 创建两个 Person 对象 const imagic = new Person('imagic', 100) imagic.greet() // 'Hi, I am imagic' const w = new","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/:1:1","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":["Notes"],"content":"React ","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/:2:0","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":["Notes"],"content":"认识 React React 是一个用于构建用户界面的 JavaScript 库。1 安装 React 以下默认系统已经安装了 node,如果无法按照以下命令操作,请查看 node 版本是否需要更新。 在 终端 terminal 使用 create-react-app 工具创建 React 应用。 npx create-react-app project cd project 以上创建了 project 应用,并进入了它的目录,使用以下命令运行这个应用。 npm start 默认情况下访问应用的地址为 localhost:3000。 Component 组件 React 组件命名必须首字母大写。 React 组件内容只能有一个根元素。(虽然可以使用创建组件数组的方式来规避这个问题,但会使代码看起来不好看,所以不使用) 根元素可以使用空元素 \u003c\u003e\u003c/\u003e,这样在 Dom 树中不会有额外的 \u003cdiv\u003e 元素了。 不要在组件内定义组件,最大的问题是 React 在每次渲染时,会将内部的组件当作一个新的组件。这会导致 React 无法去优化组件。 import React from 'react' import ReactDOM from 'react-dom' // 定义 App 组件 const App = () =\u003e { const now = new Date() const a = 10 const b = 20 return ( \u003cdiv\u003e \u003cp\u003eHello world, it is {now.toString()}\u003c/p\u003e \u003cp\u003e {a} plus {b} is {a + b} \u003c/p\u003e \u003c/div\u003e ) } // 将组件 App 渲染到 id 为 'root' 的 div 中,该元素在 public/index.html 中定义。 ReactDOM.render(\u003cApp /\u003e, document.getElementById('root')) JSX React 组件的布局大部分使用 JSX 编写的,JSX 和 HTML 非常相似,React 组件返回的 JSX 会被编译成 JavaScript。 JSX 是一种「类 XML」语言,所以每个标签都需要关闭。如 \u003cbr\u003e 必须写成 \u003cbr /\u003e。 Multiple Component 多组件 React 的核心理念就是通过将许多定制化的、可重用的组件组合成应用。有一个约定,就是应用的组件树顶部都要有一个 root 组件叫做 App。 const Hello = () =\u003e { return ( \u003cdiv\u003e \u003cp\u003e你好,世界!\u003c/p\u003e \u003c/div\u003e ) } const App = () =\u003e { return ( \u003cdiv\u003e \u003ch1\u003e欢迎\u003c/h1\u003e \u003cHello /\u003e // Hello 组件可以重复使用 \u003cHello /\u003e \u003cHello /\u003e \u003c/div\u003e ) } ReactDOM.render(\u003cApp /\u003e, document.getElementById('root')) Props: passing data to components Props: 向组件传递数据 先看一段代码 const Hello = (props) =\u003e { return ( \u003cdiv\u003e \u003cp\u003e你好,{props.age} 岁的 {props.name}\u003c/p\u003e \u003c/div\u003e ) } 我们给 Hello 组件设置了一个参数 props,它接收了一个对象,对象具有组件中所定义的所有属性对应的字段。 const App = () =\u003e { const name = 'W' const age = 100 return ( \u003cdiv\u003e \u003ch1\u003e欢迎\u003c/h1\u003e \u003cHello name='imagic' age={100} /\u003e \u003cHello name={name} age={age+100} /\u003e \u003c/div\u003e ) } props 的值可以是字符串,也可以是 JavaScript 表达式的结果。如果是表达式,则需要用花括号{}括起来。 ","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/:2:1","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":["Notes"],"content":"组件状态,事件处理 Component helper functions 组件辅助函数 组件辅助函数实际上是在另一个函数中定义的,这个函数是用来定义组件的行为的。 bornYear 函数可以访问 Hello 组件中所有的 props,不需要单独将 props.age 单独传参给 bornYear。 const Hello = (props) =\u003e { const bornYear = () =\u003e { const yearNow = new Date().getFullYear() return yearNow - props.age } return ( \u003cdiv\u003e \u003cp\u003e Hellp {props.name}, you are {props.age} years old. \u003c/p\u003e \u003cp\u003e So you were probably born in {bornYear()} \u003c/p\u003e \u003c/div\u003e ) } Desctructuring 解构 结构是 ES6 规范中添加的一个特性,它允许我们在赋值时从对象和数组中解构出值。 使用解构的方法可以将属性直接赋值给变量,从而简化组件。 以下是常规的方法 const props = { name: 'imagic', age: 100 } const Hello = (props) =\u003e { const name = props.name const age = props.age const bornYear = () =\u003e new Date().getFullYear() - age return ( \u003cdiv\u003e \u003cp\u003e Hellp {name}, you are {age} years old. \u003c/p\u003e \u003cp\u003e So you were probably born in {bornYear()} \u003c/p\u003e \u003c/div\u003e ) } 解构可以更加方便的将对象的属性的值提取到单独的变量中: const props = { name: 'imagic', age: 100 } const Hello = (props) =\u003e { const { name, age } = props const bornYear = () =\u003e new Date().getFullYear() -age // 以下与上述案例相同,省略 } 也可以使用如下方法直接将属性值赋给变量: const Hello = ({ name, age }) =\u003e Page re-rendering 页面重渲染 页面初次渲染之后,外观是不会变化的,所以如果需要页面变化,则需要将页面重新渲染。 此处使用的是 ReactDOM.render 方法,不是重新渲染组件的推荐方法,以下只作为了解即可。 const App = (props) =\u003e { const { counter } = props return( \u003cdiv\u003e{counter}\u003c/div\u003e ) } let counter = 1 ReactDOM.render( \u003cApp counter={counter} /\u003e, document.getElementById('root') ) 以上代码如果添加 counter += 1 命令,App 部件是不会重新渲染,我们需要再次调用 ReactDOM.render 的方法让组件重新渲染: const App = (props) =\u003e { const { counter } = props return ( \u003cdiv\u003e{counter}\u003c/div\u003e ) } let counter = 1 const refresh = () =\u003e { ReactDOM.render( \u003cApp counter={counter} /\u003e, document.getElementById('root') ) } refresh() // 第一次渲染,页面显示 1 counter += 1 refresh() // 第二次渲染,页面显示 2 counter += 1 refresh() // 第三次渲染,页面显示3 由上面可以看到,页面渲染了3次,页面从1变到了3,因为渲染速度较快,很难注意到1和2。如果想要看到看到1变到3的过程,我们可以使用 setInterval 或者 setTimeout 的方法增加延迟。 不推荐使用这样的方法重新渲染,下面有更好的方法可以实现。 Stateful conmponent 有状态组件 以上的组件都不包含任何组件的状态「无状态组件」,可以通过 React 的 state hook 向组件添加状态。 import React, { useState } from 'react' // 引入 useState 函数 import ReactDOM from 'react-dom' const App = () =\u003e { /** * 使用 useState 函数并解构赋值将元素分配给 counter 和 setCounter 两个变量 * counter 变量被赋予初始值 state 为 0 * setCounter 被分配给一个函数,该函数用于修改 state,也就是用来修改 counter 的值 */ const [ counter, setCounter ] = useState(0) /** * 设置1秒后调用 setCounter 函数 * 将 counter + 1 赋值给 counter */ setTimeout( () =\u003e setCounter(counter + 1), 1000 ) return ( \u003cdiv\u003e{counter}\u003c/div\u003e ) } ReactDOM.render( \u003cApp /\u003e, document.getElementById('root') ) 当 1 秒后调用 setCounter 时,React 会重新渲染这个组件,此时 counter 由原先的值变为 counter + 1,也就是由 0 变为 1 ,然后 setTimeout 继续倒数 1 秒,接着第二次调用 setCounter,然后 counter 又会变为 2,如此往复。 Event handling 事件处理 事件处理程序,是指(被注册为)在特定事件发生时进行调用。例如用户点击按钮产生的 点击 Click 事件。 const App = () =\u003e { const [ counter, setCounter ] = useState(0) const handleClick = () =\u003e { setCounter(counter + 1) } return ( \u003c\u003e \u003cdiv\u003eLike {counter}\u003c/div\u003e \u003cbutton onClick={ handleClick }\u003e 赞 \u003c/button\u003e \u003c/\u003e ) } 按钮的 onClick 调用了 handleClick 函数,每次点击 赞 按钮都会调用 handleClick 函数,也就是 Click 事件都会 setCounter 将 counter 的值 +1。 也可以直接在 onClick 属性的值直接定义事件处理函数: \u003cbutton onClick={() =\u003e setCounter(counter +1)}\u003e 赞 \u003c/button\u003e Event handler is a function 事件处理是一个函数 事件处理是一个函数,也就意味着我们不能将事件处理程序作出以下的定义: 定义为一个字符串,如 \u003cbutton onClick=\"字符串...\"\u003e按钮\u003c/button\u003e 计算结果,如 \u003cbutton onClick=\"counter + 1\"\u003e👍\u003c/button\u003e 赋值,如 \u003cbutton onClick=\"counter = 0\"\u003e重置\u003c/button\u003e 下述情况也不可以: \u003cbutton onClick={console.log('按钮被点击')}按钮\u003c/button\u003e 当这个组件渲染出来时,按钮被点击 会在 console 控制台被打印出来,但点击按钮后不会发生任何事情,console.log 函数调用只在渲染组件时被执行。 这里的问题是,我们的事件处理被定义为 function call,这意味着事件处理程序实际上被分配了函数返回的值,而 console.log 的返回值是undefined。 要注意的是,此处不能简略的写成如下: \u003cbutton onClick={setCounter(counter +1)}\u003e 赞 \u003c/button\u003e 当我们点击后,应用会奔溃并报错 Error: Too many re-renders. .....。 这是因为事件处理器被定义成了一个函数调用,在很多情况下这是可行的,但是在特殊情况下就不行了。 这样的情况是因为,页面第一次渲染的时候,它执行的函数调用 setCounter(0+1),并将组件状态的值改成了1。这就导致组件重新渲染,重新渲染又会执行 setCounter 函数,导致组件状态发生变化,然后重新渲染,这样就进入了一个无限循环,导致 React 报错。 要使 setCounter(counter +1) 在事件处理程序中正常被调用,可以使用钩子函数,将组件改成 \u003cbutton onClick={() =\u003e setCounter(counter +1)}\u003e赞\u003c/button\u003e。但在按钮中单独定义时间处理函数不是一个好方法。 所以,最好的方式还是将事件处理程序分离成单独的函数,就跟最初那样定义一个 handleC","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/:2:2","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":["Notes"],"content":"深入 React 应用调试 Complext state 复杂状态 大多数情况,复杂的状态最简单和最好的方法是多次使用 useState 函数来创建单独的状态。 关于使用单个和多个变量的情况,可以查阅官方FAQ:我应该使用单个还是多个 state 变量? 下面是使用复杂状态的案例 const App = () =\u003e { const [clicks, setClicks] = useState( { left: 0, right: 0, }) const handleLeftClick = () =\u003e { const newClicks = { left: clicks.left + 1, right: clicks.right, } setClicks(newClicks) } const handleRightClick = () =\u003e { const newClicks = { left: clicks.left, right: clicks.right + 1, } setClicks(newClicks) } return ( \u003c\u003e {clicks.left} \u003cbutton onClick={handleLeftClick}\u003eLeft\u003c/button\u003e \u003cbutton onClick={handleRightClick}\u003eRight\u003c/button\u003e {clicks.right} \u003c/\u003e ) } 可以看到,点击 Left 按钮时,right 的值是不变的,同样的,点击 Right 按钮时, left 的值是不变的。此处使用展开语法来定义新的状态对象,使代码更简洁。 const handleLeftClick = () =\u003e { const newClicks = { ...clicks, left: clicks.left + 1, } setClicks(newClicks) } const handleRightClick = () =\u003e { const newClicks = { ...clicks, right: clicks.right + 1, } setClicks(newClicks) } 将对象分配给事件处理中的变量是没有必要的,上述代码可以简写成如下 const handleLeftClick = () =\u003e setClicks({ ...clicks, left: clicks.left + 1 }) const handleRightClick = () =\u003e setClicks({ ...clicks, right: clicks.right + 1 }) 以下代码违反了 React 中状态不可以直接修改的原则,这会导致很多副作用,应杜绝这样的方式。 const handleLeftClick = () =\u003e { clicks.left++ setClicks(clicks) } Handling arrays 处理数组 下例增加了点击历史记录的功能,需要添加一个新的状态。使用 useState([]) 初始化该数组。 使用 concat 方法向数组中添加元素,该方法不改变现有数组,而是返回数组的新副本,并将元素添加到数组中。 虽然 push 方法也可以向数组添加元素,但因 React 组件的状态不能直接更改,所以不推荐这样使用。 下例使用了 join 方法,该数组将所有项目连接到一个字符串中,由作为函数参数传递的字符串「例中为一个空格」分隔。 const App = () =\u003e { const [left, setLeft] = useState(0) const [right, setRight] = useState(0) const [allClicks, setAll] = useState([]) const handleLeftClick = () =\u003e { setAll(allClicks.concat('点击了Left')) setLeft(left + 1) } const handleRightClick = () =\u003e { setAll(allClicks.concat('点击了Right')) setRight(right + 1) } return ( \u003cdiv\u003e {left} \u003cbutton onClick={handleLeftClick}\u003eleft\u003c/button\u003e \u003cbutton onClick={handleRightClick}\u003eright\u003c/button\u003e {right} \u003cp\u003e{allClicks.join(' ')}\u003c/p\u003e \u003c/div\u003e ) } Conditional rendering 条件渲染 下例将操作历史记录交由 History 组件来处理,使用 if 判断渲染历史记录。 const History = (props) =\u003e { if (props.allClicks.length === 0) { return ( \u003cdiv\u003e 暂无操作历史 \u003c/div\u003e ) } return ( \u003cdiv\u003e 操作历史:{props.allClicks.join(' ')} \u003c/div\u003e ) } const App = () =\u003e { // ... 同上例 return ( \u003cdiv\u003e {left} \u003cbutton onClick={handleLeftClick}\u003eleft\u003c/button\u003e \u003cbutton onClick={handleRightClick}\u003eright\u003c/button\u003e {right} \u003cHistory allClicks={allClicks} /\u003e \u003c/div\u003e ) } 可以看出,allClicks 为空数组的时候,History 组件将会渲染 暂无操作历史 的内容,其他情况下,将会渲染操作历史。 Debugging React applications 调试 React 应用 web 开发第一原则 始终打开浏览器开发控制台 尤其是 Console 选项卡应该始终处于打开状态,除非有特定的原因需要查看另一个选项卡。 保持代码和网页同时打开 编译失败时,应立即找到并修复问题 不能正常工作时,可以使用 console.log 来查看。console.log('props value is', props) 与 props 不要使用 + 号,因为这样会打印出 props value is [object object]。 也可在代码中写入 debugger,chrome 开发者控制台会在执行到该代码时暂停。 debugger 还可以使用在 Source 选项卡右侧找到空间一行一行地执行代码。 通过在 Sources 选项卡中添加断点,您还可以在不使用 debugger 命令的情况下访问调试器。 在 Chrome 安装 React developer tools 扩展,可以用来检查不同的React 元素,以及它的属性、状态。 Rules of Hooks Hook的规则 不能从循环、条件表达式或任何不适定义组件的函数的地方调用 useState 「同样的还有 useEffect 函数」。这样做是为了确保Hook总是以相同的顺序调用,如果不是这样,应用的行为就会不规则。 const App = () =\u003e { // 这里使用时没有问题的 const [age, setAge] = useState(0) if ( age \u003e 10 ) { // 这里使用时没有效果的 const [range, setRange] = useState('少年') } for ( let i = 0; i \u003c age; i++ ) { // 这里依然无效 const [nothing, setNothing] = useState(false) } const notGood = () =\u003e { // 这里也不行 const [x, setX] = useState(null) } return ( // ... ) } Function that returns a function 返回函数的函数 定义事件处理程序的另外一种方法是使用返回函数的函数。因为函数返回的是函数,所以事件处理程序是可以使用这个函数。 使用返回函数的函数,将可以使用参数自定义的通用函数添加到不同组件的事件处理程序中。 const hello = (who) =\u003e { const handler = () =\u003e console.log('hello', who) return handler } 当 React 渲染时, \u003cbutton onClick={hello('world')}\u003ebutton\u003c/button\u003e 本质上会被转换成 \u003cbutton onClick={()=\u003e console.log('hello', 'world')}\u003ebutton\u003c/button\u003e。 这样我们就可以在不同组件中调用了。 \u003cbutton onClick={hello('imagic')}\u003eimagic\u003c/button\u003e \u003cbutton onClick={hello('w')}\u003ew\u003c/button\u003e 我们将 hello 函数重构一下 // 省去 handler const hello = (who) =\u003e { return () =\u003e { console.log('hello', who) } } // 再来 const hello = (who) =\u003e () =\u003e { console.log('hello', wh","date":"2020-10-15","objectID":"/2020/10/fullstackopen-javascript-and-react/:2:3","tags":["React","JavaScript"],"title":"全栈公开课2020学习笔记 01 - JavaScript 和 React","uri":"/2020/10/fullstackopen-javascript-and-react/"},{"categories":null,"content":"欢迎你 欢迎来到 「ΛW」的随心所欲的博客,我是 imλgic,博主很懒,更新很慢。 如果你喜欢这里,那就留下点什么痕迹吧,反正我是不会去看的。 ","date":"2020-10-14","objectID":"/about/:1:0","tags":null,"title":"关于我","uri":"/about/"},{"categories":null,"content":"这里有什么呢? 这里有无聊的碎碎念,也许还有好看的照片,也许没有。心情好的时候可能会扒一两首曲子,心情不好的时候,可能会去跑个步、码个代码或者索性就玩消失。 ","date":"2020-10-14","objectID":"/about/:2:0","tags":null,"title":"关于我","uri":"/about/"},{"categories":null,"content":"教练,我想打个盹! Zzz… ","date":"2020-10-14","objectID":"/about/:3:0","tags":null,"title":"关于我","uri":"/about/"},{"categories":null,"content":"支持我 可以通过以下方式支持我,谢谢! 购买 Vultr 的主机 通过 Buy Me Coffee 赞助 or Support My Wishlist 通过 Crypto 支持 BitCoin segwit: bc1qzm7whmlfa4jf9axru6ht5gnvv4hph7lx6pjlrj legacy: 1JGD18QK5cr31qu3awKrg8726Rpxc134MP ETH: 0xB6Cf59A450eA15e5f331E343D9C072A1DFa7AF93 ","date":"2020-10-14","objectID":"/about/:4:0","tags":null,"title":"关于我","uri":"/about/"},{"categories":["Life"],"content":"说来也奇怪,我不太喜欢玩恐怖游戏的,却在第一次购买PS4游戏的时候入手了「巫师3」和「The Last Of US」。 不喜欢恐怖游戏是因为有一年暑假,在拉上窗帘没有开灯的房间内玩生化危机3的时候,被僵尸破窗的声音给吓到了之后,之后就很少会碰恐怖惊悚类的游戏。 今年在游玩顽皮狗打造的「The Last Of US」游戏里慢慢地接受了这种恐怖地游戏,好在游戏没有刻意地去惊吓玩家,让我能够完整的体验完游戏。 我貌似更偏爱线性叙事的游戏,像「巫师3」、「塞尔达」这类开放世界的游戏,我都还没玩结束。倒不是我不喜欢开放世界,我是喜爱开放世界的,所以我愿意花很多时间去探索它,以至于我每次想玩的时候都觉得时间不够我去探索,索性就放一边了😂。 游戏很有趣。 ","date":"2020-08-04","objectID":"/2020/08/the-last-of-us-game/:0:0","tags":["游戏","美国末日","PlayStation"],"title":"美国末日","uri":"/2020/08/the-last-of-us-game/"},{"categories":["Plan"],"content":"2019年的主题是 “Learn More.”,我觉得践行的不是很好,时间精力有限,学习不同的东西固然可以,无法专注、深入并不能达到很好的效果。这个主题适合作为五年、十年这样长周期的计划(也可能是实力不够,需要时间来凑,😂)。 简单地想了一下,2020年主题定为 “Do 1 thing PERFECT.”。一来改一改我这么久以来不断尝新,捡芝麻丢西瓜的习惯,二来也想看一看,专注于一件事情并做到完美,对于自己有多少提升。 2020年,最重要的要将5年计划制定出来。 2020年乃至长时间内,要阅读,要提升自己,要管理好自己的情绪。 oh 对,年底要对一年总结。 无论有多难,也没有生活艰难。在世一场,就是来面临苦难的。任青春成诗,那已是过去的30年,余生,请好好热爱。 年度关键词:主动 专注 敏感 细致。 活动记录以视频记录为主,照片记录为辅,文字记录为次。 主要工作内容: 公司企划 文化渗透内容的创意、设计及执行 装扮及活动 团支部的一些事情 一些其他事情 分公司信息化 数据汇总汇报 日常系统维护 信息化建设 分公司文化 小红袜 乐跑 团建活动 节日文化活动 分公司行政工作 车辆审批 机票订票 安排单据签批 PPT制作 其他领导安排的工作 ","date":"2020-01-02","objectID":"/2020/01/annual-plan-2020/:0:0","tags":["年度计划"],"title":"2020年年度计划","uri":"/2020/01/annual-plan-2020/"},{"categories":["Plan"],"content":"工作计划 年前对于以上工作一一剖析,具体分析问题,调整好应对2020年的这场硬仗。 目前的工作主要是行政岗位的工作,需要一定的统筹安排能力,19年前所有的工作方式以及内容主要集中在使用个人能力及技能方面,在统筹方面有短板,加之明年同事将不再负责年会活动,故2020年要重点锻炼统筹协调能力。 做事情方面,尽量考虑全面,多做一点准备,哪怕多准备了之后没有用到也好过于准备不足之后再回来安排。明明考虑到了的事情,却没有去做,最后发现考虑的是对的,那是不应该发生的,今后要杜绝这方面的问题。 主动做事,即使是别人统筹安排的,提醒ta或者替他考虑好事情,注重团队协作。2020年要从个人包揽大部分工作的模式改为团队合作的方式,加强沟通能力、协作能力、做事做人Nice一点。 学会拒绝,除了只有我能做的事情、急事、重要的事情之外,尽量拒绝简单的、不重要的事情。可以婉转一点。 汇报工作、回答问题摒除不确定的词语,例如好像、可能、大概等。 将工作时和工作外状态区分出来,工作上严谨认真,不涉及工作外的私交,对工作不对人。 ","date":"2020-01-02","objectID":"/2020/01/annual-plan-2020/:1:0","tags":["年度计划"],"title":"2020年年度计划","uri":"/2020/01/annual-plan-2020/"},{"categories":["Plan"],"content":"学习计划 语言 英语 - ⏸️ 搁置ing 英语6级单词,3000个单词。 日语 - ⏸️ 搁置ing 打算年底报考日语N3考试,目前要争取每周有3-5小时学习时间,力争一次考过。6月底开始 8-1日正式开始 全栈公开课2020课程 近期因为开发公司的一个项目,接触到了 react 框架,所以打算以边学边记笔记的方式把这个公开课学完。 Part 0 Web 应用的基础设施 2 hours - 20201018 Part 1 React 入门 8 hours - 20201021 a React 简介 1 hours b Javascript 1.5 hours c 组件状态,事件处理 2.5 hours d 深入 React 应用调试 3 hours Part 2 与服务端通信 10 hours 22 minites - 20201110 a 从渲染集合到模块学习 52 minutes b 表单 2 hours c 从服务器获取数据 3.5 hours d 在服务端将数据 Alert 出来 3 hours e 给 React 应用加点样式 1 hour Part 3 用NodeJS和Express写服务端程序 11 hours - 20201209 a Node.js 与 Express 2 hours b 把应用部署到网上 1 hour c 将数据存入 MongoDB 7 hours d ESLint 与代码检查 1 hour Part 4 a 从后端结构到测试入门 1.5 hours b 测试后端应用 2 + Part 5 Part 6 Part 7 Part 8 Part 9 Part 10 阅读 年内争取读完10本书,大致类目定位如下: 分类 数量 完成 小说 3本 历史 2本 传记 2本 指导 2本 哲学 1本 [ progress: ■■■■■■■■———— 40% ] 阅读进度: 书名 分类 开始时间 完成时间 耗时 状态 偷影子的人 小说 2020.01.28 2020.02.10 14d ✅ 完成 学会提问 指导 2020.01.02 ? - ▶️ 进行 游戏改变世界 指导 2020.03.23 ? - ⏸️ 搁置 拍电影时我在想的事 传记 2020.07.08 2020.07.21 14d ✅ 完成 人间失格 小说 2020.06.24 2020.07.25 6h 15m ✅ 完成 十日谈 小说 2020.07.28 2020.08.22 16h 22m ✅ 完成 罗马人的故事 I 罗马不是一天造成的 历史 - ? - 🔜 计划 罗马人的故事 II 汉尼拔战记 历史 - ? - 🔜 计划 形而上学 哲学 - ? - 🔜 计划 从人间失格开始,后续的书籍都使用计时软件统计,时间上会更为准确。 练字 - ⏸️ 搁置ing 目前使用的田英章的字帖,主要是临帖为主,计划是每周至少3小时的时间在练习。 从3月23日开始,至今(7.27)共计投入23小时,未完成每周制定的计划,需要注意。 乐器 - ⏸️ 搁置ing 吉他学习南泽大介的指弹练习曲余下的22首全部练完。 曲目 分类 开始时间 完成时间 耗时 状态 练习曲3 练习曲 2020.03.10 2020.04.28 49d ✅ 完成 练习曲4 练习曲 2020.04.28 - - ▶️ 进行 [ progress: ■——————— 4.5% ] ","date":"2020-01-02","objectID":"/2020/01/annual-plan-2020/:2:0","tags":["年度计划"],"title":"2020年年度计划","uri":"/2020/01/annual-plan-2020/"},{"categories":["Plan"],"content":"身心计划 锻炼 ✅ 完成 报一个私教班,维持健康的身体。 规律饮食,保持体重。 已报 2020.05.08 —— 2020.12.15,基本保持每周2-4次的私教训练。 May (total 11) 05.04 - 05.10 / 2 times 05.11 - 05.17 / 3 times 05.18 - 05.24 / 4 times 05.25 - 05.31 / 2 times June (total 11) 06.01 - 06.07 / 3 times 06.08 - 06.14 / 2 times 06.15 - 06.21 / 3 times 06.22 - 06.28 / 3 times July (total 14) 06.29 - 07.05 / 3 times 07.06 - 07.12 / 2 times 07.13 - 07.19 / 4 times 07.20 - 07.26 / 4 times 07.27 - 08.02 / 1 times (教练周四至周日出差,课程暂停) August (total 6) 08.03 - 08.09 / 3 times 08.10 - 08.15 / 3 times (第一期到期) September (total 8) 09.14 - 09.20 / 3 times (第二期开始) 09.21 - 09.27 / 3 times 09.28 - 09.30 / 2 times October (total 12) 10.01 - 10.04 / 1 times 10.05 - 10.11 / 2 times 10.12 - 10.18 / 3 times 10.19 - 10.25 / 3 times 10.26 - 10.31 / 3 times November (total 12) 11.01 - 11.08 / 3 times 11.09 - 11.15 / 3 times 11.16 - 11.22 / 2 times 11.23 - 11.30 / 4 times December (total 8) 12.01 - 12.06 / 4 times 12.07 - 12.15 / 4 times TOTAL 82, ¥ 11,500, ¥ 141 per lesson ","date":"2020-01-02","objectID":"/2020/01/annual-plan-2020/:3:0","tags":["年度计划"],"title":"2020年年度计划","uri":"/2020/01/annual-plan-2020/"},{"categories":["Plan"],"content":"前几次的年度计划执行的不太理想,作为一个杂事王,我都不好意思放上前几年的计划。 今年已经过了一半了,估摸着还是计划一下吧。 降低一些预期,毕竟我没那么优秀。 今年具体规划 阅读 健身 开发 乐器 游戏 这几个方面,希望今年有一点进步吧。 以下是整个计划内容,每个月月底审视当月完成情况以及制定下个月的任务。 加油! 2019.11.22更新 ⬇️ 又到年底了,年会事情开始多起来了,目标看似要完成不了了~ 哎~ 2019.12.17更新⬇️ 年会结束了,看看能不能再完成点什么~ ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:0:0","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"阅读 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:1:0","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"书单 《佐藤可士和的超沟通术》 2019.8.3 done 《稀缺》 《荒木经惟的天才写真术》 2019.8.3 done 《大家的日本语·初级1》 《人间失格》 《游戏改变生活》 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:1:1","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"健身 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:2:0","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"减重 今年体重要减到62.5kg,目前 68.4kg / 2019.07.31 67.8kg / 2019.08.05 64.2kg / 2019.11.22 62.9kg / 2019.11.30 62.4kg / 2019.12.11 done 失败了可是要罚杰伦新专辑的。 2019.12.17更新 总算是完成了,可是周董怎么还没发专辑~ ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:2:1","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"开发 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:3:0","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"盛天乐跑小程序 -[ ] 完成成就系统的开发 -[ ] 完成兑换商店的开发 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:3:1","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"乐器 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:4:0","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"吉他 把南泽大介的指弹练习曲练完 练习曲1 / 2019.08.02 done 练习曲2 / 2019.09.21 done 练习曲3 2019.11.22新增 《平凡之路》 / 2019.10.12 done 《说好不哭》 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:4:1","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Plan"],"content":"游戏 《巫师3》应该要把他玩通关吧。 ","date":"2019-07-26","objectID":"/2019/07/annual-plan-2019/:5:0","tags":["年度计划"],"title":"2019年年度计划","uri":"/2019/07/annual-plan-2019/"},{"categories":["Notes"],"content":"前言 本来购买极路由是为了改善无线质量的,后来仅仅改变无线质量已经不能满足我,加上我之前的电脑CPU和显卡陆续烧坏,闲置了几块硬盘,于是就想折腾起路由器来让我闲置硬盘用起来。 本笔记主要是记录我如何折腾路由器的经历与心得。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:1:0","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"准备 极路由3(已开通开发者权限) 网线一根 电脑一台 移动硬盘 极路由3需要在路由器界面申请开发者权限,这样才能使用ssh。请注意,开启ssh后会失去官方保修服务!请谨慎。 如何申请,请自行摸索或者百度谷歌Bing一下。 我使用的平台是MacOS 10.12,其他平台操作方法类似。 刷机有风险,请小心开车。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:2:0","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"解锁u-boot 极路由的u-boot会验证固件版本,需要解锁才能安装第三方固件,同时为了避免刷固件失败造成变砖的情况,刷上不死u-boot可以有效避免悲剧发生。 首先需要在 http://www.right.com.cn/forum/thread-161906-1-1.html 找到对应的u-boot。 偷懒不看帖子的小伙伴可以直接在这里寻找 http://breed.hackpascal.net/ ,极路由3是 HC5861,对应的u-boot就是 breed-mt7620-hiwifi-hc5861.bin,对应的下载地址就是 http://breed.hackpascal.net/breed-mt7620-hiwifi-hc5861.bin。 接下来就是要用ssh连接到路由器啦,我的路由器地址是 10.0.0.1,那我们打开终端(Terminal)开始使用命令吧。 以下命令的中文仅是提示,请勿复制至命令行!请一个命令执行完再执行下一个命令。 //连接路由器 ssh -p 22 [email protected] //进入tmp目录 cd /tmp //下载固件 wget http://breed.hackpascal.net/breed-mt7620-hiwifi-hc5861.bin //安装u-boot mtd -r write /tmp/breed-mt7620-hiwifi-hc5761.bin u-boot 此时,终端会显示 Rebooting,等待重启完毕后再切断路由器电源,按住路由器 reset 按钮后接通电源,等待路由器电源灯连续闪烁后松开 reset。 电脑会自动获取ip地址,我们通过浏览器访问 192.168.1.1 可以登录Breed Web恢复控制台,有了这个,我们就可以随意开车,不怕翻车啦! ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:3:0","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"Openwrt ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:4:0","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"下载Openwrt 我使用的是 「Pandorabox」的 PandoraBox-ralink-mt7620-mt7620a-evb-2017-01-03-git-6c24a7a-squashfs-sysupgrade.bin 的固件,固件位于 pandorabox-16-10-stable/targets/ralink/mt7620/ 目录下。 我没有选择 PandoraBox-ralink-mt7620-hc5861-2017-01-03-git-6c24a7a-squashfs-sysupgrade.bin 版本的原因是因为这个版本的USB挂载有问题,我也不知道如何解决。(你们有解决方案烦请告诉我!万分感谢!) 懒人可以点击上方固件名字下载。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:4:1","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"安装Openwrt 下载完成后,进入Breed恢复控制台,选择「固件更新」,在右边「常规固件」下方勾选「固件」并上传刚刚下完的固件 PandoraBox-ralink-mt7620-hc5861-2017-01-03-git-6c24a7a-squashfs-sysupgrade.bin,同时勾选「自动重启」后点击「上传」按钮。 重启完成后,等待更新成功。浏览器访问 192.168.1.1 即可进入路由器登录界面,Pandorabox的初始密码是 admin,输入密码后即可进入。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:4:2","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"基本设置 PandoraBox固件内置了两种主题,习惯于Openwrt的 Bootstrap 主题的可以 系统 - 系统 - 语言与界面下更改主题为 Bootstrap。 PPPOE拨号 在 网络 菜单下找到 接口并进入,找到接口 WAN 并编辑,协议改成 PPPOE 并切换协议,填入宽带帐号密码并保存\u0026应用。 无线设置 在 网络 菜单下找到 无线 并进入,有2.4G和5G两个无线接口,自行修改相应的无线即可。 我为了方便,将2.4G和5G的SSID和密码设置都是相同的。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:4:3","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"挂载点 设置位于 系统 - 挂载点。 这个版本的固件会自动挂载USB连接的硬盘(U盘)设备,默认的挂载位置 /mnt,挂载名为 sda1,当然你挂载的硬盘比较多,之后的硬盘的挂载名会是 sda2 sda3,以此类推。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:4:4","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"Samba共享 Samba共享是为了让网内的电脑能够方便地访问挂载的硬盘中的内容。当然,你也可以从路由器上拔下硬盘,连接到电脑上。 设置 找到 服务 - 网络共享,全局设置根据个人喜好设置即可。 共享目录中将 /mnt/sda1 硬盘共享出去即可,如果你希望可以匿名访问,请勾选 允许匿名访问 选项,并可以跳过以下内容(包括添加用户) 编辑模板,为了安全,将模板做以下修改,主要是更改访客访问以及root访问的权限,禁止这2类用户访问。 [global] netbios name = |NAME| display charset = |CHARSET| interfaces = |INTERFACES| server string = |DESCRIPTION| unix charset = |CHARSET| workgroup = |WORKGROUP| browseable = yes deadtime = 30 domain master = |MASTER| encrypt passwords = true enable core files = no # guest account = nobody # guest ok = yes invalid users = root local master = yes load printers = no map to guest = Bad User max protocol = SMB2 min receivefile size = 16384 null passwords = yes obey pam restrictions = yes os level = 250 lm announce = yes lm interval = 10 dns proxy = no passdb backend = smbpasswd preferred master = yes printable = no security = user smb encrypt = disabled smb passwd file = /etc/samba/smbpasswd socket options = TCP_NODELAY IPTOS_LOWDELAY syslog = 2 use sendfile = yes writeable = yes 添加用户 那么,禁用了root和访客访问,我怎么通过网络共享连接到硬盘呢? 我们需要专门添加一个用户,设置相应访问权限,这样就不用担心因为root的权限高而引起的安全问题。 首先我们需要 ssh 到路由器上。 然后我们 cd 到 /etc 目录下,通过 vi passwd 命令来编辑用户表,按下 i 键即可编辑,在文本的最后一行加入以下内容后,保存即可。(什么,你不知道怎么保存?那你只能请教百度谷歌Bing先生们了) 好了,这样我们就新建了一个叫imagicw的用户了,并赋予其 用户组 的权限。 此时,我们还需要把这个用户添加至smbpasswd,输入以下命令 smbpasswd imagicw 123456 即可完成添加用户 imagicw,后面的数字就是密码。 此时我们还需要在共享目录允许用户里填上 imagicw 才算设置完成。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:4:5","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"Aria2 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:5:0","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"安装 在 系统 下的 软件包 中安装 aria2 luci-app-aria2及 luci-i18n-aria2-zh-cn。 当然喜欢手动配置文件的可以不安装 luci-app-aria2及 luci-i18n-aria2-zh-cn,具体就不赘述了。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:5:1","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"配置 然后在 服务 下的 Aria2 配置 配置 Aria2服务。 Aria2 全局设置 认证方式可选择 用户名密码 或者 令牌 的方式。 Aria2 文件及目录设置 我专门给硬盘设置了一个 Downloads 文件夹,便(qiang)于(po)管(zheng)理。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:5:2","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"UI Aria2是轻量级的下载工具,基本上都是用命令行的方式下载,这样并不能很直观的管理下载,此时我们就需要用户图形界面(UI)的帮助了。 使用现成的 网上有许多 Aria2 的WebUI,在各大搜索引擎搜索可以找到,常见的有 YAAW 和 WebUI Aria2。懒人也可以直接访问:WebUI Aria2。 GitHub部署 在GitHub中Fork「Webui-Aria2」即可,具体就不赘述了。 Chrome插件(推荐) 这里推荐的是 YAAW for Chrome,作者是雪月秋水。 如果你是重度Chrome使用者的话,这个插件完完全全可以代替迅雷、QQ旋风等下载工具。 设置界面如下: ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:5:3","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"DDNS ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:6:0","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"安装 在 系统 下的 软件包 中安装 ddns-scripts luci-app-ddns luci-i18n-ddns-zh-cn。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:6:1","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"配置 然后在 服务 下的 动态DNS下修改myddns_ipv4。 设置动态域名 我使用的是花生壳的服务,按照下图设置。 在计时器设定里面你可以设置更新周期,我设置了检查时间周期为1小时,强制更新周期是72小时。 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:6:2","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"},{"categories":["Notes"],"content":"后记 此次折腾路由器走了不少弯路,一直在PandoraBox和 rssnj 大神的固件,一开始 rssnj 的固件除了5G无法使用,一切正常,但使用了一阵子来看,但凡路由器重启过一次,挂载就会失效,其次是没有5G的日子,100M的宽带真的是摆设。 于是我又折腾起了 PandoraBox,为什么是又呢,因为之前用过,但是碍于挂载不了USB硬盘,只好作罢,这次是因为发现了上文所说的版本,总算是完成了下载中心的搭设。 连续用了几天,暂时也没出现什么大问题。 虽然有些不太完满(LED的显示问题),但也无伤大雅。谨以此文,来安慰熬夜折腾的自己。 参考 极路由刷OpenWrt最强攻略——从救砖、刷Breed、编译固件到安装配置 ","date":"2017-03-27","objectID":"/2017/03/how-i-made-my-hiwifi-into-download-center/:7:0","tags":["OpenWrt","Aria2"],"title":"我是如何将路由器打造成我的下载中心的","uri":"/2017/03/how-i-made-my-hiwifi-into-download-center/"}]