การปิดกั้น COVID-19 ทำให้พวกเราหลายคนติดอยู่ที่บ้านบางทีอาจจะหวังว่าไข้ในห้องโดยสารจะเป็นไข้ที่เลวร้ายที่สุดที่เราจะพบ พวกเราหลายคนบริโภคเนื้อหาวิดีโอมากขึ้นกว่าเดิม แม้ว่าการออกกำลังกายจะมีความสำคัญเป็นพิเศษในตอนนี้ แต่บางครั้งก็มีความคิดถึงความหรูหราของรีโมทคอนโทรลที่ดูดีแบบเก่าเมื่อแล็ปท็อปอยู่ไกลเกินเอื้อม
นั่นคือที่มาของโครงการนี้: โอกาสในการเปลี่ยนสมาร์ทโฟนทุกเครื่องแม้กระทั่งเครื่องเก่าที่ไม่มีประโยชน์หากไม่มีการอัปเดตให้เป็นรีโมทที่ใช้งานง่ายสำหรับ Netflix / YouTube / Amazon Prime Video / ฯลฯ เครื่องถัดไป การดื่มสุราชม. นอกจากนี้ยังมีบทช่วยสอนแบ็คเอนด์ Node.js: โอกาสในการเรียนรู้พื้นฐานของ JavaScript แบ็คเอนด์โดยใช้เฟรมเวิร์ก Express และเอ็นจินเทมเพลต Pug (เดิมชื่อ Jade)
หากฟังดูน่ากลัวก็เสร็จสมบูรณ์ โหนด js โครงการจะนำเสนอในตอนท้าย ผู้อ่านต้องการเรียนรู้เท่าที่พวกเขาสนใจในการเรียนรู้เท่านั้นและจะมีคำอธิบายพื้นฐานบางอย่างที่อ่อนโยนกว่าพอสมควรซึ่งผู้อ่านที่มีประสบการณ์มากกว่าสามารถข้ามไปได้
ผู้อ่านอาจสงสัยว่า 'ทำไมต้องเข้ารหัส Node.js back end?' (นอกเหนือจากโอกาสในการเรียนรู้แน่นอน) 'ยังไม่มีแอพสำหรับสิ่งนั้น?'
แน่นอนว่ามีมากมาย แต่มีสองสาเหตุหลักที่อาจไม่เป็นที่ต้องการ:
ปัญหาเหล่านี้มีมานานแล้วและยังเป็นแรงจูงใจสำหรับโครงการที่คล้ายกันจากปี 2014 ที่พบใน GitHub nvm
ทำให้การติดตั้ง Node.js เวอร์ชันเก่าเป็นเรื่องง่ายและแม้ว่าจะต้องมีการอัปเกรดที่ต้องพึ่งพาเพียงเล็กน้อย แต่ Node.js ก็มีชื่อเสียงอย่างมากในเรื่องความเข้ากันได้แบบย้อนหลัง
น่าเสียดายที่ bitrot ชนะ วิธีการที่ดื้อรั้นและความเข้ากันได้ของแบ็คเอนด์ของ Node.js นั้นไม่ตรงกับการเลิกใช้งานที่ไม่มีที่สิ้นสุดและการพึ่งพาที่เป็นไปไม่ได้ระหว่าง Grunt, Bower และส่วนประกอบอื่น ๆ อีกมากมาย หลายชั่วโมงต่อมามันชัดเจนเกินกว่าที่จะเริ่มต้นใหม่ตั้งแต่ต้น - คำแนะนำของผู้เขียนเอง การคิดค้นล้อใหม่ อย่างไรก็ตาม
ก่อนอื่นโปรดทราบว่าปัจจุบันโครงการ Node.js นี้มีไว้สำหรับ Linux โดยเฉพาะซึ่งพัฒนาและทดสอบบน Linux Mint 19 และ Linux Mint 19.3 โดยเฉพาะ แต่สามารถเพิ่มการสนับสนุนสำหรับแพลตฟอร์มอื่น ๆ ได้อย่างแน่นอน มัน อาจ ทำงานบน Mac แล้ว
สมมติว่าเป็นรุ่นที่ทันสมัยของ โหนด js ได้รับการติดตั้งและพรอมต์คำสั่งเปิดอยู่ในไดเร็กทอรีใหม่ซึ่งจะทำหน้าที่เป็นรูทโปรเจ็กต์เราพร้อมที่จะเริ่มต้นใช้งาน Express:
npx express-generator --view=pug
หมายเหตุ: ที่นี่ npx
เป็นเครื่องมือแสนสะดวกที่มาพร้อมกับ npm
ตัวจัดการแพ็คเกจ Node.js ที่มาพร้อมกับ Node.js เรากำลังใช้มันเพื่อเรียกใช้โปรแกรมสร้างโครงกระดูกของแอปพลิเคชัน Express จากการเขียนนี้เครื่องกำเนิดไฟฟ้าสร้างโปรเจ็กต์ Express / Node.js ซึ่งตามค่าเริ่มต้นยังคงดึงเอ็นจิ้นเทมเพลตที่เรียกว่า Jade แม้ว่าโปรเจ็กต์ Jade เปลี่ยนชื่อตัวเองเป็น“ ปั๊ก” ตั้งแต่เวอร์ชัน 2.0 เป็นต้นไป ดังนั้นเพื่อให้เป็นปัจจุบันและใช้ Pug ทันทีบวกหลีกเลี่ยงคำเตือนการเลิกใช้งาน - เราจัดการกับ --view=pug
ซึ่งเป็นตัวเลือกบรรทัดคำสั่งสำหรับ express-generator
สคริปต์ถูกเรียกใช้โดย npx
.
เมื่อเสร็จแล้วเราจำเป็นต้องติดตั้งแพ็กเกจบางอย่างจากรายการการอ้างอิงที่สร้างขึ้นใหม่ของโปรเจ็กต์ Node.js ใน package.json
วิธีทำแบบดั้งเดิมคือเรียกใช้ npm i
(i
สำหรับ 'ติดตั้ง') แต่บางคนก็ยังชอบความเร็วของ เส้นด้าย ดังนั้นหากคุณติดตั้งไว้เพียงแค่เรียกใช้ yarn
โดยไม่มีพารามิเตอร์
ในกรณีนี้ควรละเว้น (หวังว่าจะได้รับการแก้ไขในไม่ช้า) คำเตือนการเลิกใช้งาน จากการขึ้นต่อกันย่อยของ Pug ตราบใดที่ยังคงมีการเข้าถึงตามความจำเป็นบนเครือข่ายท้องถิ่น
ด่วน yarn start
หรือ npm start
ตามด้วย ไปที่ localhost:3000
ในเบราว์เซอร์แสดงให้เห็นว่าแบ็คเอนด์ Node.js พื้นฐานของ Express ทำงานได้ เราสามารถฆ่ามันได้ด้วย Ctrl+C
.
กับ ระยะไกล ทำไปได้ครึ่งทางแล้วเรามาดูกันที่ ควบคุม ส่วน. เราต้องการบางสิ่งบางอย่างที่สามารถควบคุมเครื่องโดยทางโปรแกรมที่เราจะเรียกใช้แบ็คเอนด์ Node.js โดยแสร้งทำเป็นว่ามันกำลังกดปุ่มบนแป้นพิมพ์
จากนั้นเราจะติดตั้ง xdotool
โดยใช้ คำแนะนำอย่างเป็นทางการ . การทดสอบตัวอย่างคำสั่งอย่างรวดเร็วในเทอร์มินัล:
xdotool search 'Mozilla Firefox' windowactivate --sync key --clearmodifiers ctrl+l
…ควรทำตามที่กล่าวไว้โดยสมมติว่า Mozilla Firefox เปิดให้บริการในเวลานั้น ดีแล้ว! การทำให้โปรเจ็กต์ Node.js ของเราเรียกใช้เครื่องมือบรรทัดคำสั่งเช่น xdotool
เป็นเรื่องง่ายดังที่เราจะได้เห็นในเร็ว ๆ นี้
สิ่งนี้อาจไม่เป็นความจริงสำหรับทุกคน แต่โดยส่วนตัวแล้วฉันพบว่ารีโมทคอนโทรลทางกายภาพสมัยใหม่จำนวนมากมีปุ่มมากถึงห้าเท่าที่ฉันเคยใช้ ดังนั้นสำหรับโปรเจ็กต์นี้เรากำลังดูการจัดวางแบบเต็มหน้าจอที่มีตารางสามโดยสามปุ่มที่สวยงามใหญ่และง่ายต่อการกำหนดเป้าหมาย ขึ้นอยู่กับความชอบส่วนบุคคลว่าปุ่มทั้งเก้าอาจเป็นอย่างไร
ปรากฎว่าแป้นพิมพ์ลัดสำหรับฟังก์ชันที่ง่ายที่สุดก็ไม่เหมือนกัน Netflix , Youtube และ วิดีโอ Amazon Prime . บริการเหล่านี้ไม่ทำงานร่วมกับคีย์สื่อทั่วไปเช่นแอปเครื่องเล่นเพลงเนทีฟ นอกจากนี้ฟังก์ชันบางอย่างอาจใช้ไม่ได้กับบริการทั้งหมด
ดังนั้นสิ่งที่เราต้องทำคือกำหนดรูปแบบการควบคุมระยะไกลที่แตกต่างกันสำหรับแต่ละบริการและระบุวิธีการสลับระหว่างบริการต่างๆ
มาสร้างต้นแบบสั้น ๆ ที่ทำงานร่วมกับค่าที่ตั้งไว้ล่วงหน้าจำนวนหนึ่ง เราจะใส่ไว้ใน common/preset_commands.js
-“ common” เพราะเราจะรวมข้อมูลนี้จากไฟล์มากกว่าหนึ่งไฟล์:
module.exports = { // We could use ️ but some older phones (e.g., Android 5.1.1) won't show it, hence ️ instead 'Netflix': { commands: { '-': 'Escape', '+': 'f', '': 'Up', '⇤': 'XF86Back', '️': 'Return', '': 'Down', '': 'Left', '': 'Right', '': 'm', }, }, 'YouTube': { commands: { '⇤': 'shift+p', '⇥': 'shift+n', '': 'Up', 'CC': 'c', '️': 'k', '': 'Down', '': 'j', '': 'l', '': 'm', }, }, 'Amazon Prime Video': { window_name_override: 'Prime Video', commands: { '⇤': 'Escape', '+': 'f', '': 'Up', 'CC': 'c', '️': 'space', '': 'Down', '': 'Left', '': 'Right', '': 'm', }, }, 'Generic / Music Player': { window_name_override: '', commands: { '⇤': 'XF86AudioPrev', '⇥': 'XF86AudioNext', '': 'XF86AudioRaiseVolume', '': 'r', '️': 'XF86AudioPlay', '': 'XF86AudioLowerVolume', '': 'Left', '': 'Right', '': 'XF86AudioMute', }, }, };
ค่าคีย์โค้ดสามารถเป็นได้ พบโดยใช้ xev
. (สำหรับฉัน 'ปิดเสียง' และ 'เล่นเสียง' ไม่สามารถค้นพบได้โดยใช้วิธีนี้ดังนั้นฉันจึงปรึกษาด้วย รายการคีย์สื่อ .)
ผู้อ่านอาจสังเกตเห็นความแตกต่างในกรณีระหว่าง space
และ Return
- โดยไม่คำนึงถึงเหตุผลนี้รายละเอียดนี้จะต้องได้รับเกียรติสำหรับ xdotool
ทำงานได้อย่างถูกต้อง เกี่ยวกับเรื่องนี้เรามีคำจำกัดความสองสามคำที่เขียนไว้อย่างชัดเจนเช่น shift+p
แม้ว่า P
ก็ใช้ได้เช่นกันเพียงแค่รักษาความตั้งใจของเราให้ชัดเจน
เราจำเป็นต้องมีจุดสิ้นสุดเพื่อ POST
ซึ่งจะจำลองการกดแป้นพิมพ์โดยใช้ xdotool
เนื่องจากเราจะมีกลุ่มคีย์ที่แตกต่างกันที่เราสามารถส่งได้ (หนึ่งกลุ่มสำหรับแต่ละบริการ) เราจึงเรียกจุดสิ้นสุดสำหรับคีย์ที่ต้องการ group
เราจะนำ users
ที่สร้างขึ้นใหม่ จุดสิ้นสุดโดยเปลี่ยนชื่อ routes/users.js
ถึง routes/group.js
และทำการเปลี่ยนแปลงที่เกี่ยวข้องใน app.js
:
// ... var indexRouter = require('./routes/index'); var groupRouter = require('./routes/group'); // ... app.use('/', indexRouter); app.use('/group', groupRouter); // ...
สำคัญ ฟังก์ชันการทำงานใช้ xdotool
ผ่านทางเชลล์ระบบใน routes/group.js
. เราจะฮาร์ดโค้ด YouTube
เป็นเมนูที่เลือกใช้ในขณะนี้เพื่อการทดสอบเท่านั้น
const express = require('express'); const router = express.Router(); const debug = require('debug')('app'); const cp = require('child_process'); const preset_commands = require('../common/preset_commands'); /* POST keystroke to simulate */ router.post('/', function(req, res, next) { const keystroke_name = req.body.keystroke_name; const keystroke_code = preset_commands['YouTube'].commands[keystroke_name]; const final_command = `xdotool search 'YouTube' windowactivate --sync key --clearmodifiers ${keystroke_code}`; debug(`Executing ${final_command}`); cp.exec(final_command, (err, stdout, stderr) => { debug(`Executed ${keystroke_name}`); return res.redirect(req.originalUrl); }); }); module.exports = router;
ที่นี่เราคว้าคีย์ที่ร้องขอ“ ชื่อ” จาก POST
request’s body (req.body
) ภายใต้พารามิเตอร์ชื่อ keystroke_name
จะเป็นอย่างนั้น ️
จากนั้นเราจะใช้เพื่อค้นหารหัสที่เกี่ยวข้องจาก preset_commands['YouTube']
ของ commands
วัตถุ.
คำสั่งสุดท้ายอยู่ในมากกว่าหนึ่งบรรทัดดังนั้น s ที่ท้ายแต่ละบรรทัดจะรวมส่วนทั้งหมดเป็นคำสั่งเดียว:
search 'YouTube'
ดึงหน้าต่างแรกที่มี 'YouTube' อยู่ในชื่อwindowactivate --sync
เปิดใช้งานหน้าต่างที่ดึงข้อมูลและรอจนกว่าจะพร้อมรับการกดแป้นพิมพ์key --clearmodifiers ${keystroke_code}
ส่งการกดแป้นพิมพ์ตรวจสอบให้แน่ใจว่าได้ล้างคีย์ตัวปรับแต่งชั่วคราวเช่น Caps Lock ที่อาจรบกวนสิ่งที่เรากำลังส่งณ จุดนี้โค้ดจะถือว่าเราป้อนข้อมูลที่ถูกต้องซึ่งเป็นสิ่งที่เราจะต้องระวังให้มากขึ้นในภายหลัง
เพื่อความเรียบง่ายโค้ดจะถือว่ามีหน้าต่างแอปพลิเคชันเพียงหน้าต่างเดียวที่เปิดขึ้นพร้อมกับ 'YouTube' ในชื่อหากมีการจับคู่มากกว่าหนึ่งรายการไม่มีการรับประกันว่าเราจะส่งการกดแป้นไปยังหน้าต่างที่ต้องการ หากเป็นปัญหาอาจช่วยให้สามารถเปลี่ยนชื่อหน้าต่างได้ง่ายๆโดยการสลับแท็บเบราว์เซอร์ในทุกหน้าต่างนอกเหนือจากที่ต้องควบคุมจากระยะไกล
เมื่อพร้อมแล้วเราสามารถเริ่มเซิร์ฟเวอร์ของเราอีกครั้ง แต่คราวนี้เมื่อเปิดใช้งานการดีบักเราจึงสามารถเห็นผลลัพธ์ของ debug
โทร. ในการทำเช่นนั้นให้เรียกใช้ DEBUG=old-fashioned-remote:* yarn start
หรือ DEBUG=old-fashioned-remote:* npm start
. เมื่อทำงานแล้วให้เล่นวิดีโอบน YouTube เปิดหน้าต่างเทอร์มินัลอื่นแล้วลองโทร cURL:
curl --data 'keystroke_name=️' http://localhost:3000/group
ที่ส่ง POST
ขอด้วยชื่อการกดแป้นพิมพ์ที่ร้องขอในร่างกายไปยังเครื่องท้องถิ่นของเราที่พอร์ต 3000
พอร์ตส่วนหลังของเรากำลังฟังอยู่ การรันคำสั่งนั้นควรแสดงบันทึกเกี่ยวกับ Executing
และ Executed
ใน npm
หน้าต่างและที่สำคัญกว่านั้นคือเปิดเบราว์เซอร์และหยุดวิดีโอชั่วคราว การดำเนินการคำสั่งนั้นอีกครั้งควรให้ผลลัพธ์เดียวกันและยกเลิกการหยุดชั่วคราว
ส่วนหลังของเรายังไม่เสร็จสมบูรณ์ นอกจากนี้เรายังต้องการให้สามารถ:
preset_commands
common/preset_commands.js
ได้โดยตรงที่ส่วนหน้าเนื่องจากเป็น JavaScript อยู่แล้วและกรองที่นั่นนั่นเป็นข้อดีอย่างหนึ่งของแบ็คเอนด์ Node.js เราไม่ได้ใช้ที่นี่ .)คุณลักษณะทั้งสองนี้เป็นที่ที่การสอนแบ็คเอนด์ Node.js ของเราตัดกับส่วนหน้าที่ใช้ Pug ที่เราจะสร้างขึ้น
ส่วนหลังสุดของสมการหมายถึงการปรับเปลี่ยน routes/index.js
มีลักษณะดังนี้:
const express = require('express'); const router = express.Router(); const preset_commands = require('../common/preset_commands'); /* GET home page. */ router.get('/', function(req, res, next) { const group_names = Object.keys(preset_commands); res.render('index', { title: 'Which Remote?', group_names, portrait_css: `.group_bar { height: calc(100%/${Math.min(4, group_names.length)}); line-height: calc(100vh/${Math.min(4, group_names.length)}); }`, landscape_css: `.group_bar { height: calc(100%/${Math.min(2, group_names.length)}); line-height: calc(100vh/${Math.min(2, group_names.length)}); }`, }); }); module.exports = router;
ที่นี่เราคว้าชื่อเลย์เอาต์การควบคุมระยะไกลของเรา (group_names
) โดยเรียก Object.keys
บน preset_commands
ของเรา ไฟล์. จากนั้นเราจะส่งข้อมูลเหล่านั้นและข้อมูลอื่น ๆ ที่จำเป็นไปยังเครื่องมือเทมเพลต Pug ที่เรียกโดยอัตโนมัติผ่าน res.render()
ระวังอย่าสับสนความหมายของ keys
ที่นี่ด้วยคีย์ จังหวะ เรากำลังส่ง: Object.keys
ทำให้เรามีอาร์เรย์ (รายการสั่งซื้อ) ที่มีไฟล์ คีย์ ของ คู่คีย์ - ค่า ที่ประกอบเป็นวัตถุใน JavaScript:
const my_object = { 'a key': 'its corresponding value', 'another key': 'its separate corresponding value', };
หากเราดู common/preset_commands.js
เราจะเห็นรูปแบบด้านบนและ คีย์ (ในความหมายของวัตถุ) คือชื่อของกลุ่มของเรา: 'Netflix'
, 'YouTube'
ฯลฯ ค่าที่สอดคล้องกันไม่ใช่สตริงธรรมดา ๆ เช่น my_object
มีข้างต้น - เป็นวัตถุทั้งหมดในตัวเองโดยมีกุญแจของตัวเองเช่น commands
และอาจเป็น window_name_override
.
CSS ที่กำหนดเองที่ส่งผ่านที่นี่เป็นที่ยอมรับว่าเป็นการแฮ็กเล็กน้อย เหตุผลที่เราต้องการมันเลยแทนที่จะใช้โซลูชันที่ทันสมัยและทำงานบน Flexbox คือเพื่อให้เข้ากันได้ดีขึ้นกับโลกมหัศจรรย์ของเบราว์เซอร์มือถือในชาติเก่าที่ยอดเยี่ยมยิ่งขึ้น ในกรณีนี้สิ่งสำคัญที่ควรทราบก็คือในโหมดแนวนอนเราจะทำให้ปุ่มมีขนาดใหญ่โดยแสดงไม่เกินสองตัวเลือกต่อหนึ่งหน้าจอ ในโหมดแนวตั้งสี่
แต่ที่จริงแล้วจะเปลี่ยนเป็น HTML เพื่อส่งไปยังเบราว์เซอร์ได้ที่ไหน? นั่นคือที่ views/index.pug
เข้ามาซึ่งเราจะมีลักษณะดังนี้:
extends layout block header_injection style(media='(orientation: portrait)') #{portrait_css} style(media='(orientation: landscape)') #{landscape_css} block content each group_name in group_names span(class='group_bar') a(href='/group/?group_name=' + group_name) #{group_name}
บรรทัดแรกมีความสำคัญ: extends layout
หมายความว่า Pug จะใช้ไฟล์นี้ในบริบทของ views/layout.pug
ซึ่งเป็นเทมเพลตหลักที่เราจะใช้ซ้ำที่นี่และในมุมมองอื่นด้วย เราจะต้องเพิ่มสองสามบรรทัดหลัง link
บรรทัดเพื่อให้ไฟล์สุดท้ายมีลักษณะดังนี้:
doctype html html head title= title link(rel='stylesheet', href='/stylesheets/style.css') block header_injection meta(name='viewport', content='user-scalable=no') body block content
เราจะไม่เข้าใจพื้นฐานของ HTML ที่นี่ แต่สำหรับผู้อ่านที่ไม่คุ้นเคยรหัส Pug นี้จะสะท้อนโค้ด HTML ค่าโดยสารมาตรฐานที่พบได้ทุกที่ เทมเพลต ลักษณะเริ่มต้นด้วย title= title
ซึ่งตั้งค่าหัวเรื่อง HTML เป็นค่าใดก็ได้ที่สอดคล้องกับ title
คีย์ของวัตถุที่เราส่งผ่าน Pug ผ่าน res.render
เราสามารถเห็นแง่มุมที่แตกต่างของการสร้างเทมเพลตสองบรรทัดในภายหลังด้วย block
เรากำลังตั้งชื่อ header_injection
บล็อกเหล่านี้เป็นตัวยึดตำแหน่งที่สามารถแทนที่ได้ด้วยเทมเพลตที่ขยายปัจจุบัน (ไม่เกี่ยวกันบรรทัด meta
เป็นเพียงวิธีแก้ปัญหาอย่างรวดเร็วสำหรับเบราว์เซอร์มือถือดังนั้นเมื่อผู้ใช้แตะระดับเสียงจะควบคุมหลายครั้งติดต่อกันโทรศัพท์จะละเว้นจากการซูมเข้าหรือออก)
กลับไปที่ block
s: นี่คือเหตุผลที่ views/index.pug
กำหนด block
s ของตัวเองด้วยชื่อเดียวกันที่พบใน views/layout.pug
ในกรณีของ header_injection
สิ่งนี้ช่วยให้เราใช้ CSS เฉพาะกับแนวตั้งหรือแนวนอนที่โทรศัพท์จะอยู่
content
เป็นที่ที่เราวางส่วนที่มองเห็นได้หลักของหน้าเว็บซึ่งในกรณีนี้:
group_names
อาร์เรย์ที่เราส่งผ่านมัน
องค์ประกอบสำหรับแต่ละองค์ประกอบด้วยคลาส CSS group_bar
นำไปใช้กับมันและ
ขึ้นอยู่กับ group_name
.คลาส CSS group_bar
เราสามารถกำหนดในไฟล์ที่ดึงผ่าน views/layout.pug
คือ public/stylesheets/style.css
:
html, body, form { padding: 0; margin: 0; height: 100%; font: 14px 'Lucida Grande', Helvetica, Arial, sans-serif; } .group_bar, .group_bar a, .remote_button { box-sizing: border-box; border: 1px solid white; color: greenyellow; background-color: black; } .group_bar { width: 100%; font-size: 6vh; text-align: center; display: inline-block; } .group_bar a { text-decoration: none; display: block; }
ณ จุดนี้ถ้า npm start
ยังคงทำงานอยู่ไปที่ http://localhost:3000/
ในเบราว์เซอร์เดสก์ท็อปควรแสดงปุ่มขนาดใหญ่มากสองปุ่มสำหรับ Netflix และ YouTube ส่วนที่เหลือสามารถใช้งานได้โดยการเลื่อนลง
แต่ถ้าเราคลิกที่จุดนี้พวกเขาจะใช้ไม่ได้เพราะเรายังไม่ได้กำหนดเส้นทางที่พวกเขาเชื่อมโยงไป (the GET
ting of /group
.)
ในการทำเช่นนั้นเราจะเพิ่มสิ่งนี้ใน routes/group.js
ก่อนรอบชิงชนะเลิศ module.exports
ไลน์:
router.get('/', function(req, res, next) { const group_name = req.query.group_name || ''; const group = preset_commands[group_name]; return res.render('group', { keystroke_names: Object.keys(group.commands), group_name, title: `${group_name.match(/([A-Z])/g).join('')}-Remote` }); });
สิ่งนี้จะได้รับชื่อกลุ่มที่ส่งไปยังปลายทาง (เช่นโดยใส่ ?group_name=Netflix
ต่อท้าย /group/
) และใช้เพื่อรับค่าของ commands
จากกลุ่มที่เกี่ยวข้อง ค่านั้น (group.commands
) คือวัตถุและกุญแจของวัตถุนั้นคือชื่อ (keystroke_names
) ที่เราจะแสดงในรูปแบบรีโมทคอนโทรลของเรา
หมายเหตุ: นักพัฒนาที่ไม่มีประสบการณ์ไม่จำเป็นต้องลงรายละเอียดวิธีการทำงาน แต่เป็นค่าสำหรับ title
ใช้บิตของ นิพจน์ทั่วไป เพื่อเปลี่ยนชื่อกลุ่ม / เลย์เอาต์ของเราให้เป็นตัวย่อตัวอย่างเช่นรีโมท YouTube ของเราจะมีชื่อเบราว์เซอร์ YT-Remote
ด้วยวิธีนี้หากเรากำลังแก้ไขข้อบกพร่องบนเครื่องโฮสต์ของเราก่อนที่จะลองใช้กับโทรศัพท์เราจะไม่มี xdotool
คว้าหน้าต่างเบราว์เซอร์การควบคุมระยะไกลขึ้นมาเองแทนที่จะเป็นหน้าต่างที่เราพยายามควบคุม ในขณะเดียวกันในโทรศัพท์ของเราชื่อจะดีและสั้นเราควรจะบุ๊กมาร์กรีโมทคอนโทรล
เช่นเดียวกับการเผชิญหน้าครั้งก่อนของเรากับ res.render
อันนี้กำลังส่งข้อมูลไปปะปนกับเทมเพลต views/group.pug
เราจะสร้างไฟล์นั้นและกรอกข้อมูลนี้:
extends layout block header_injection script(type='text/javascript', src='/javascript/group-client.js') block content form(action='/group?group_name=' + group_name, method='post') each keystroke_name in keystroke_names input(type='submit', name='keystroke_name', value=keystroke_name, class='remote_button')
เช่นเดียวกับ views/index.pug
เรากำลังลบล้างบล็อกทั้งสองจาก views/layout.pug
คราวนี้ไม่ใช่ CSS ที่เราใส่ไว้ในส่วนหัว แต่เป็น JavaScript ฝั่งไคลเอ็นต์ซึ่งเราจะใช้งานได้ในไม่ช้า (และใช่ในช่วงเวลาแห่งความพากเพียรฉันเปลี่ยนชื่อพหูพจน์ไม่ถูกต้อง javascripts
…)
หลัก content
นี่คือรูปแบบ HTML ที่ประกอบด้วยปุ่มส่งที่แตกต่างกันหลายปุ่มสำหรับแต่ละปุ่ม keystroke_name
แต่ละปุ่มจะส่งแบบฟอร์ม (สร้าง POST
คำขอ) โดยใช้ชื่อการกดแป้นพิมพ์ที่แสดงเป็นค่าที่ส่งไปพร้อมกับแบบฟอร์ม
นอกจากนี้เรายังต้องการ CSS อีกเล็กน้อยในไฟล์สไตล์ชีตหลักของเรา:
.remote_button { float: left; width: calc(100%/3); height: calc(100%/3); font-size: 12vh; }
ก่อนหน้านี้เมื่อเราตั้งค่าปลายทางเราได้จัดการคำขอเสร็จสิ้นด้วย:
return res.redirect(req.originalUrl);
ซึ่งหมายความว่าอย่างมีประสิทธิภาพเมื่อเบราว์เซอร์ส่งแบบฟอร์มส่วนหลังของ Node.js จะตอบสนองโดยการบอกให้เบราว์เซอร์กลับไปที่หน้าที่ส่งแบบฟอร์มนั่นคือรูปแบบรีโมทคอนโทรลหลัก มันจะสวยงามมากขึ้นโดยไม่ต้องสลับหน้า อย่างไรก็ตามเราต้องการความเข้ากันได้สูงสุดกับโลกที่แปลกประหลาดและน่าอัศจรรย์ของเบราว์เซอร์มือถือที่เสื่อมโทรม ด้วยวิธีนี้แม้จะไม่มี JavaScript ส่วนหน้าทำงานเลย แต่โปรเจ็กต์แบ็คเอนด์ Node.js ของเรา ควร ยังคงทำงาน
ข้อเสียของการใช้แบบฟอร์มเพื่อส่งการกดแป้นพิมพ์คือเบราว์เซอร์ต้องรอจากนั้นจึงเรียกใช้งานแบบไปกลับพิเศษ: จากนั้นจะต้องขอหน้าและการอ้างอิงจากส่วนหลังของ Node.js และส่งมอบ จากนั้นเบราว์เซอร์จะต้องแสดงผลอีกครั้ง
ผู้อ่านอาจสงสัยว่าสิ่งนี้อาจมีผลกระทบมากเพียงใด ท้ายที่สุดเพจมีขนาดเล็กการอ้างอิงนั้นน้อยมากและโปรเจ็กต์ Node.js สุดท้ายของเราจะทำงานผ่านการเชื่อมต่อ wifi ในพื้นที่ ควรจะเป็นการตั้งค่าเวลาแฝงต่ำใช่ไหม
ตามที่ปรากฎ - อย่างน้อยที่สุดเมื่อทดสอบกับสมาร์ทโฟนรุ่นเก่าที่ใช้ Windows Phone 8.1 และ Android 4.4.2 ผลกระทบที่เห็นได้ชัดเจนในกรณีทั่วไปของการแตะอย่างรวดเร็วเพื่อเพิ่มหรือลดระดับเสียงการเล่นเพียงไม่กี่รอย นี่คือสิ่งที่ JavaScript สามารถช่วยได้โดยไม่ต้องละทิ้งทางเลือกที่สวยงามของคู่มือ POST
s ผ่านรูปแบบ HTML
ณ จุดนี้ JavaScript ไคลเอนต์สุดท้ายของเรา (ที่จะใส่ public/javascript/group-client.js
) ต้องเข้ากันได้กับเบราว์เซอร์มือถือรุ่นเก่าที่ไม่รองรับอีกต่อไป แต่เราไม่ต้องการมันมาก:
(function () { function form_submit(event) { var request = new XMLHttpRequest(); request.open('POST', window.location.pathname + window.location.search, true); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); request.send('keystroke_name=' + encodeURIComponent(event.target.value)); event.preventDefault(); } window.addEventListener('DOMContentLoaded', function() { var inputs = document.querySelectorAll('input'); for (var i = 0; i นี่คือ form_submit
ฟังก์ชันเพียงแค่ส่งข้อมูลผ่านการโทรแบบอะซิงโครนัสและบรรทัดสุดท้ายจะป้องกันพฤติกรรมการส่งปกติของเบราว์เซอร์โดยที่หน้าใหม่จะโหลดตามการตอบสนองของเซิร์ฟเวอร์ ครึ่งหลังของตัวอย่างข้อมูลนี้จะรอจนกว่าหน้าเว็บจะโหลดจากนั้นจึงเชื่อมต่อทุกปุ่มส่งเพื่อใช้ form_submit
ของทั้งหมดถูกห่อด้วย IIFE .
สัมผัสสุดท้าย
มีจำนวน การเปลี่ยนแปลง ไปยังส่วนย่อยด้านบนในโค้ดการสอนแบ็คเอนด์ Node.js เวอร์ชันสุดท้ายของเราซึ่งส่วนใหญ่มีวัตถุประสงค์เพื่อการจัดการข้อผิดพลาดที่ดีขึ้น:
- ตอนนี้ส่วนหลังของ Node.js จะตรวจสอบชื่อของกลุ่มและการกดแป้นพิมพ์ที่ส่งไปให้เพื่อให้แน่ใจว่ามีอยู่ รหัสนี้อยู่ในฟังก์ชันที่ใช้ซ้ำสำหรับทั้ง
GET
และ POST
หน้าที่ของ routes/group.js
. - เราใช้ประโยชน์จาก Pug
error
แม่แบบหากไม่มี - ตอนนี้ JavaScript และ CSS ส่วนหน้าทำให้ปุ่มเป็นโครงร่างเป็นสีเทาชั่วคราวในขณะที่รอการตอบกลับจากเซิร์ฟเวอร์เป็นสีเขียวทันทีที่สัญญาณผ่าน
xdotool
และกลับมาโดยไม่มีปัญหาและเป็นสีแดงหากสิ่งใดไม่เป็นไปตามที่คาดไว้ - ส่วนหลังของ Node.js จะพิมพ์การติดตามสแต็กหากมันตายซึ่งจะมีโอกาสน้อยกว่าที่ระบุข้างต้น
ผู้อ่านสามารถอ่าน (และ / หรือโคลน) โครงการ Node.js ที่สมบูรณ์ได้ บน GitHub .
Node.js Back-end Tutorial ขั้นตอนที่ 5: การทดสอบในโลกแห่งความจริง
ได้เวลาทดลองใช้กับโทรศัพท์จริงที่เชื่อมต่อกับเครือข่าย wifi เดียวกันกับโฮสต์ที่ใช้งาน npm start
และเครื่องเล่นภาพยนตร์หรือเพลง เป็นเพียงเรื่องของการชี้เว็บเบราว์เซอร์ของสมาร์ทโฟนไปยังที่อยู่ IP ในพื้นที่ของโฮสต์ (โดยมี :3000
ต่อท้าย) ซึ่งอาจพบได้ง่ายที่สุดโดยการเรียกใช้ hostname -I | awk '{print }'
ในเทอร์มินัลบนโฮสต์
ปัญหาหนึ่งที่ผู้ใช้ Windows Phone 8.1 อาจสังเกตเห็นคือการพยายามนำทางไปยังสิ่งต่างๆเช่น 192.168.2.5:3000
จะให้ป๊อปอัปข้อผิดพลาด:

โชคดีที่ไม่จำเป็นต้องท้อถอย: เพียงแค่ขึ้นต้นด้วย http://
หรือเพิ่มต่อท้าย /
ได้รับเพื่อดึงที่อยู่โดยไม่ต้องร้องเรียนเพิ่มเติม

การเลือกตัวเลือกควรนำเราไปสู่รีโมทคอนโทรลที่ใช้งานได้

เพื่อความสะดวกยิ่งขึ้นผู้ใช้อาจต้องการปรับการตั้งค่า DHCP ของเราเตอร์เพื่อกำหนดที่อยู่ IP เดียวกันให้กับโฮสต์เสมอและบุ๊กมาร์กหน้าจอการเลือกเค้าโครงและ / หรือรูปแบบที่ชื่นชอบ
ดึงคำขอยินดีต้อนรับ
มีแนวโน้มว่าไม่ใช่ทุกคนที่จะชอบโครงการนี้อย่างที่เป็นอยู่ ต่อไปนี้เป็นแนวคิดในการปรับปรุงสำหรับผู้ที่ต้องการเจาะลึกโค้ดเพิ่มเติม:
การเอาชนะอุปสรรคการสื่อสารข้ามวัฒนธรรม
- ควรปรับแต่งเลย์เอาต์หรือเพิ่มรูปแบบใหม่สำหรับบริการอื่น ๆ เช่น Disney Plus อย่างตรงไปตรงมา
- บางทีบางคนอาจชอบเค้าโครง 'โหมดแสง' และตัวเลือกในการสลับไปมา
- การกลับออกจาก Netflix เนื่องจากไม่สามารถย้อนกลับได้อาจใช้คำว่า“ แน่ใจหรือ” การยืนยันบางประเภท
- โครงการจะได้รับประโยชน์อย่างแน่นอน Windows สนับสนุน.
- เอกสารของ
xdotool
กล่าวถึง OSX - โครงการนี้ (หรืออาจจะ) ใช้ได้กับ Mac รุ่นใหม่หรือไม่ - สำหรับการพักผ่อนขั้นสูงวิธีค้นหาและเรียกดูภาพยนตร์แทนที่จะต้องเลือกภาพยนตร์ Netflix / Amazon Prime Video เดียวหรือสร้างเพลย์ลิสต์ YouTube จากคอมพิวเตอร์
- ชุดทดสอบอัตโนมัติในกรณีที่การเปลี่ยนแปลงที่แนะนำทำให้ฟังก์ชันการทำงานเดิมไม่สมบูรณ์
ฉันหวังว่าคุณจะสนุกกับการสอนแบ็คเอนด์ Node.js และประสบการณ์การใช้งานสื่อที่ดีขึ้น ขอให้สนุกกับการสตรีมและเขียนโค้ด!
ที่เกี่ยวข้อง: การสร้าง Node.js / TypeScript REST API ตอนที่ 1: Express.js ทำความเข้าใจพื้นฐาน
Node.js สำหรับแบ็คเอนด์หรือไม่
ใช่. Node.js เป็นโปรแกรมบรรทัดคำสั่งที่เรียกใช้โค้ด JavaScript และโดยปกติจะใช้บนโฮสต์เว็บเพื่อแสดงหน้าเว็บเชื่อมต่อกับฐานข้อมูลและอื่น ๆ
Node.js เพียงพอสำหรับแบ็คเอนด์หรือไม่
อย่างแน่นอน จัดวางอย่างถูกต้องส่วนหลังของ Node.js สามารถปรับขนาดได้เช่นเดียวกับเทคโนโลยีใด ๆ ที่กล่าวว่ามักจะรวมเข้ากับส่วนประกอบสำคัญอื่น ๆ เช่นการเข้าถึงชั้นฐานข้อมูลของแอป
Express.js คืออะไร?
Express เป็นโมดูลสำหรับ Node.js ที่ลดจำนวนโค้ดสำเร็จรูปที่ต้องใช้ในการเขียนฟังก์ชันการทำงานทั่วไปของเว็บเซิร์ฟเวอร์ มีระบบนิเวศย่อยที่เป็นผู้ใหญ่ของตัวเอง เว็บเซิร์ฟเวอร์ Node.js ส่วนใหญ่ใช้ Express
ปั๊ก / หยกคืออะไร?
Pug (เดิมชื่อ Jade) เป็นเครื่องมือจำลองที่ทำงานร่วมกับ Express ในความเป็นจริงเป็นเวลาหลายปีแล้วที่เป็นเครื่องมือแม่แบบเริ่มต้นที่ตัวสร้างโครงการ Express รวมอยู่ในโครงการใหม่
xdotool คืออะไร?
โปรแกรมบรรทัดคำสั่ง xdotool จำลองการกดแป้นพิมพ์บนคอมพิวเตอร์ที่ทำงานอยู่ โปรเจ็กต์นี้ช่วยให้โทรศัพท์สามารถดำเนินการดังกล่าวบนคอมพิวเตอร์ผ่านทางหน้าเว็บโดยเปลี่ยนเป็นการควบคุมระยะไกล