นี่คือเว็บแอปพลิเคชันที่เลียนแบบฝั่งพีซีของ NetEase Cloud Music สร้างขึ้นจาก Vue + Element UI ลักษณะหน้าโดยรวมค่อนข้างเรียบง่าย เดสก์ท็อปของ Windows เนื้อหาหลักของแอปพลิเคชันคือหน้าต่างซึ่งสามารถเข้าถึงได้โดยการลากมุมขวาล่างเพื่อเปลี่ยนขนาดหน้าต่างแม้ว่าเว็บแอปพลิเคชันจะดูแปลกไปสักหน่อย แต่ก็ไม่เป็นเช่นนั้น เป็นไปไม่ได้ บางทีเว็บเดสก์ท็อปอาจเกิดขึ้นได้ในอนาคต คล้ายกับความรู้สึกของเดสก์ท็อประบบคลาวด์
ดูเหมือนว่าจะเป็นความคิดที่ดีทีเดียว ในอนาคต คุณสามารถลองสร้างเว็บเดสก์ท็อปดังกล่าว จัดเตรียมแพลตฟอร์มพื้นฐานเพื่อจัดการวงจรชีวิตของแต่ละหน้าต่าง จากนั้นจึงพัฒนาแอปพลิเคชันเว็บโดยใช้แพลตฟอร์มนี้และนำของคุณเอง เว็บแอปพลิเคชันบนนั้น
แบ็กเอนด์โปรเจ็กต์มาจาก API เวอร์ชัน NetEase Cloud Music NodeJS และเอกสารอินเทอร์เฟซที่สมบูรณ์ของโปรเจ็กต์
ไม่สามารถเข้าถึงหน้าเอกสารอินเทอร์เฟซของโครงการนี้ได้อีกต่อไป ฉันสร้างเอกสารออฟไลน์ ซึ่งคุณสามารถดาวน์โหลดได้จากที่นี่
ยังมีบางหน้าของโครงการที่ยังไม่เสร็จสมบูรณ์ แต่หน้าหลักได้เสร็จสิ้นแล้ว และโครงการจะได้รับการอัปเดตและปรับใช้บน NetEase Cloud Music ของฉันอย่างต่อเนื่อง (เลียนแบบ)
เนื่องจากเซิร์ฟเวอร์เป็นเซิร์ฟเวอร์ในประเทศ และการแก้ไขชื่อโดเมนสำหรับโฮสต์ในประเทศจำเป็นต้องมีการลงทะเบียน และเนื่องจากฉันไม่สามารถผ่านการจดทะเบียนได้เนื่องจากฉันไม่มีใบอนุญาตมีถิ่นที่อยู่ ฉันจึงสามารถเข้าถึงได้โดยตรงโดยใช้ IP เท่านั้น
ส่วนนี้จะอธิบายวิธีทำให้โครงการนี้ทำงานได้อย่างถูกต้อง
$ git clone https://github.com/Binaryify/NeteaseCloudMusicApi.git
$ npm install
พอร์ตเริ่มต้นสำหรับการเริ่มต้นเซิร์ฟเวอร์คือ 3000 หากคุณไม่ต้องการใช้พอร์ต 3000 คุณสามารถใช้คำสั่งต่อไปนี้: windows
$ set PORT=4000
ภายใต้ Mac/Linux
$ PORT=4000
$ cd NeteaseCloudMusicApi
$ node app.js
$ git clone https://github.com/ColorlessWin/cloud_music.git
$ npm install
ที่อยู่เซิร์ฟเวอร์เริ่มต้นของโปรเจ็กต์คือ http://localhost
และพอร์ตคือ 3000
หากคุณต้องการแก้ไข ให้สร้างไฟล์ .env.local
ใหม่ในไดเร็กทอรีรากของโปรเจ็กต์นี้ และจดบันทึกคู่คีย์-ค่าต่อไปนี้ .
VUE_APP_HOST=/*这里填你的服务器地址(需要加http或https前缀)*/
VUE_APP_PORT=/*这里填你的服务器端口*/
/**
* 示例
* VUE_APP_HOST=https://webservices.fun
* VUE_APP_PORT=80
*/
$ npm run serve
$ npm run build
โปรเจ็กต์นี้มีปลั๊กอิน webpack ที่เขียนเอง ฟังก์ชันคือการอัปโหลดไฟล์ที่สร้างขึ้นไปยังเซิร์ฟเวอร์โดยอัตโนมัติหลังจากการสร้างเสร็จสมบูรณ์ อย่างไรก็ตาม เนื่องจากการกำหนดค่าไฟล์ .
.env.local
จึงสามารถแก้ไขได้เมื่อสร้างบนเท่านั้น คอมพิวเตอร์ของฉัน ค้นหาเซิร์ฟเวอร์และอัปโหลดไฟล์ ดังนั้นมันจะรายงานข้อผิดพลาดเมื่อสร้างบนคอมพิวเตอร์ของคุณ แต่จะไม่ส่งผลกระทบต่อโครงสร้างของโครงการ
หากคุณเพิ่งใช้งานภายในเครื่อง เพียงเก็บการกำหนดค่าทั้งหมดไว้เป็นค่าเริ่มต้น
ส่วนนี้จะแนะนำให้คุณรู้จักกับ <Rendering/>
ซึ่งเป็นส่วนประกอบหลักในโปรเจ็กต์ โครงการ.
ส่วนประกอบ
<Rendering/>
มีหน้าที่รับผิดชอบในการเรนเดอร์ข้อมูลทั้งหมดในโปรเจ็กต์ที่สามารถสรุปเป็นรูปแบบArray<Object>
ได้ โปรเจ็กต์มีข้อมูลดังกล่าวจำนวนมาก เช่น รายชื่อเพลง รายชื่อนักร้อง รายชื่ออัลบั้ม รายชื่อความคิดเห็น ฯลฯ ข้อมูลที่สอดคล้องกับรูปแบบArray<Object>
และคอมโพเนนต์
<Rendering/>
จะรับหน้าที่โหลดข้อมูลเหล่านี้ การประมวลผลเพจ ฯลฯ สิ่งที่คุณต้องทำนั้นง่ายมาก คุณเพียงแค่ต้องใช้วิธีfilling
และส่งผ่านไปยังคอมโพเนนต์<Rendering/>
อุปกรณ์ประกอบฉาก
เราจะแนะนำส่วนประกอบนี้ผ่านหน้าเรียบง่ายในโครงการ
นี่คือหน้าการจำแนกประเภท MV ด้วยการสลับแท็กการจำแนกประเภทต่างๆ หน้านี้จะแสดงรายการ MV ที่เกี่ยวข้อง นอกจากนี้ยังมีฟังก์ชันเพจอย่างง่ายที่ด้านล่าง มาดูวิธีใช้ <Rendering/>
เพื่อใช้งานฟังก์ชันเหล่านี้ได้อย่างสะดวก
คุณสามารถ ลอง หน้านี้ก่อน
การแบ่งหน้าด้านล่าง
มาดูโครงสร้างทั่วไปของส่วนซอร์สโค้ดของหน้านี้กันดีกว่า
< template >
< span >地区:</ span >
< simple-radio :options = " areaLabel " v-model = " area " /> < br >
< span >类型:</ span >
< simple-radio :options = " typeLabel " v-model = " type " /> < br >
< span >排序:</ span >
< simple-radio :options = " orderLabel " v-model = " order " /> < br >
< rendering
class = " mvs "
:component = " require('@/components/content/matrices/CommonVideoMatrices').default "
:adapter = " adapter "
:show-creator = " true "
:total = " total "
:filling = " filling "
:unique = " area + type + order "
/>
</ template >
< script >
import ...
export default {
name : " Mv " ,
components : {LArea, Rendering, SimpleRadio},
data () {
return {
total : - 1 ,
area : '全部' ,
type : '全部' ,
order : '上升最快' ,
areaLabel : [ '全部' , '内地' , '港台' , '欧美' , '日本' ],
typeLabel : [ '全部' , '官方版' , '原声' , '现场版' , '网易出品' ],
orderLabel : [ '上升最快' , '最热' , '最新' ],
adapter : { ... }
}
},
methods : {
filling ( offset , limit , first_load ) { ... }
}
}
</ script >
เนื้อหาบางส่วนที่ไม่ต้องการความสนใจถูกพับไว้ที่นี่ สำหรับซอร์สโค้ดที่สมบูรณ์ โปรดดูที่นี่
คุณจะเห็นว่าส่วนเทมเพลตของหน้านั้นค่อนข้างง่าย ส่วนแรกคือองค์ประกอบ <simple-radio/>
สามรายการ ฟังก์ชันของพวกเขานั้นเรียบง่ายมาก ป้ายกำกับที่เกี่ยวข้องจะถูกเรนเดอร์ผ่านอาร์เรย์ป้ายกำกับทั้งสามที่กำหนดใน data
และเมื่อ คลิกป้ายกำกับ จากนั้นอัปเดตคุณสมบัติที่ถูกผูกไว้ที่สอดคล้องกันผ่าน v-model
จากนั้นส่วนประกอบ <rendering/>
ที่มีอุปกรณ์ประกอบฉากมากมายผูกไว้
<rendering/>
รายละเอียดส่วนประกอบ ดูเหมือนว่า <rendering/>
จะมีอุปกรณ์ประกอบฉากมากมาย แต่ก็ไม่เป็นเช่นนั้น <rendering/>
มีเพียง 2 อุปกรณ์ประกอบฉาก และอุปกรณ์ประกอบฉากอื่น ๆ จะถูกส่งผ่านไปยัง <component/>
และ <pagination/>
ภายใน
< template >
< div >
< component
:is = " component "
v-bind = " Object.assign(props, $attrs) "
v-on = " $listeners "
/>
< pagination
v-model = " props.datas "
v-on = " $listeners "
v-bind = " $attrs "
:filling = " filling "
/>
</ div >
</ template >
< script >
import Pagination from " @/components/common/Pagination " ;
export default {
name : " Rendering " ,
components : {Pagination},
props : {
component : { type : [ Object , Function ], required : true },
filling : { type : Function , required : true },
},
data () {
return {
props : {
datas : [],
}
}
}
}
</ script >
<Rendering/>
ข้อมูลโค้ดต้นฉบับ เนื้อหาบางส่วนที่ไม่ต้องการความสนใจได้ถูกลบไปแล้วที่นี่ สำหรับซอร์สโค้ดแบบเต็ม โปรดดูที่นี่
<pagination/>
เป็นส่วนประกอบของเพจ มีหน้าที่รับผิดชอบในการแสดงผลส่วนประกอบของเพจเพื่อให้มีการโต้ตอบและยังรับผิดชอบในการจัดการการโหลดข้อมูลอีกด้วย
<component/>
มีหน้าที่โหลดส่วนประกอบที่คุณส่งผ่านเสา component
ในหน้า MV นี้ ฉันจะส่งส่วนประกอบ CommonVideoMatrices
แบบไดนามิกไปยัง component
ผ่าน require([path]).default
component
และคุณจะเห็นว่าฉันพร็อกซีเหตุการณ์ภายใน CommonVideoMatrices
ผ่าน v-on="$listeners"
ซึ่งหมายความว่าคุณสามารถฟังเหตุการณ์ $emit
ภายใน CommonVideoMatrices
ได้โดยตรงบน <rendering/>
CommonVideoMatrices
มีหน้าที่รับผิดชอบในการเรนเดอร์รายการ MV จริง มีหน้าที่รับผิดชอบในการแสดงข้อมูลในหน้านี้ โดยยอมรับdatas
ภายใน (datas
ควรอยู่ในรูปแบบArray<Object>
เสมอ) และแสดงผลผ่านหน้าdatas
มีคอมโพเนนต์มากมายในโปรเจ็กต์ที่คล้ายกับการออกแบบ
CommonVideoMatrices
โดยทั้งหมดจะเรนเดsrc/cmoponents/content/tracks
ร์ข้อมูลของตัวเองผ่านdatas
prop มีเพียงคอมโพเนนต์เดียวที่มีdatas
prop เท่านั้น ที่สามารถ ส่งผ่านใน<rendering/>
src/cmoponents/content/tracks
และภายใต้src/component/content/matrices
<Pagination/>
จะแสดงองค์ประกอบการเพจบนเพจเพื่อให้มีการโต้ตอบคอมโพเนนต์การเพจนี้จะแสดงผลก็ต่อเมื่อคุณระบุ prop
total
มิฉะนั้นจะไม่ถูกเรนเดอร์ แต่คุณยังสามารถจัดการการโหลดข้อมูลได้ สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ<Pagination/>
คุณสามารถดูซอร์สโค้ดได้
ข้างต้นจะแนะนำโครงสร้างภายในและรายละเอียดบางส่วนขององค์ประกอบ <Rendering/>
<Rendering/>
อย่างน้อยเราก็รู้ว่าเราสามารถส่งผ่าน component
ที่มี datas
prop เข้าไปได้ โดยจะช่วยเราเรนเดอร์องค์ประกอบนี้ แต่ใครจะให้คอมโพเนนต์นี้ datas
prop ส่งข้อมูลผ่านวิธีไหนครับ?
ซึ่งจะแสดง filling
เสาอีกอันภายในคอมโพเนนต์ <Rendering/>
filling
ข้อมูล คุณจะต้องส่ง ฟังก์ชัน ไปให้ฟังก์ชันนี้ ฟังก์ชัน นี้จะถูกเรียกใช้โดยอัตโนมัติเมื่อจำเป็น และจำเป็นต้องส่งคืนสัญญา
เราสามารถดูวิธีการใช้ ฟังก์ชัน นี้ได้ในหน้า MV
methods: {
filling ( offset , limit , first_load ) {
return new Promise ( resolve => {
mvs ( this . area , this . type , this . order , offset , limit )
. then ( result => {
if ( first_load ) this . total = result [ 'count' ]
resolve ( result [ 'data' ] )
} )
} )
}
}
ฟังก์ชันนี้จะถูกส่งผ่านเป็นพารามิเตอร์ไปที่
<rendering/>
และฟังก์ชันภายในจะถูกส่งไปที่<pagination/>
และจะตัดสินใจว่าจะเรียกใช้เมื่อใด
mvs(area, type, order, offset, limit)
เป็นอินเทอร์เฟซสำหรับข้อมูล mv ส่วนหลัง พารามิเตอร์สามตัวแรกใช้เพื่อกำหนดประเภทของ mvoffset
และlimit
ที่ใช้สำหรับเพจ
เมื่อคลิกองค์ประกอบการเพจที่แสดงผลบนเพจโดย <pagination/>
วิธีการเติมจะถูกเรียกภายในและพารามิเตอร์บางตัวจะถูกส่งผ่าน พารามิเตอร์เหล่านี้ถูกใช้เป็นพารามิเตอร์การเพจโดยอินเทอร์เฟ mvs
และถูกส่งผ่านการแก้ไขเมื่อข้อมูลอินเทอร์เฟซถูกส่งคืน เรียบร้อยแล้ว ไปที่ด้านในของ <pagination/>
ข้อมูลจะถูกแคชในครั้งนี้ และข้อมูลจะถูกส่งไปยัง CommonVideoMatrices
ผ่าน <Rendering/>
เพื่อให้สามารถแสดงผลข้อมูลได้ตามปกติ
การเติมจะถูกเรียกเมื่อมีการโหลดเพจครั้งแรก
คุณจะเห็นว่าหน้าของเรายังต้องโหลดข้อมูลใหม่หลังจากที่ผู้ใช้เลือกแท็กหรือหมวดหมู่อื่น ๆ คุณอาจนึกถึงการฟังเหตุการณ์การคลิกของ <simple-radio/>
แล้วแจ้งเตือนการเรียก <pagination/>
ในทางใดทางหนึ่ง วิธีการกรอกจะอัพเดตข้อมูลหรือไม่?
ไม่จำเป็น! - เรามีวิธีที่ง่ายกว่าในการใช้ฟังก์ชันนี้
< rendering
...
:unique =" area + type + order "
/>
unique
จะถูกส่งต่อไปยัง<pagination/>
ในที่สุด
order
type
area
พวกมันทั้งหมดเชื่อมโยงกับ<simple-radio/>
สามแบบที่แตกต่างกันผ่านv-model
ฉันแค่ต้องเพิ่มเสา unique
ในองค์ประกอบ <rendering/>
และส่งผ่านค่าที่ใช้เพื่อตอบสนองต่อการอัปเดตข้อมูล เมื่อค่าส่งผ่านไปยังการเปลี่ยนแปลง unique
การเติมจะถูกเรียก สิ่งนี้จะมีประโยชน์มาก ในสถานการณ์สมมตินี้ เช่น เมื่อ ID ของเพลย์ลิสต์มีการเปลี่ยนแปลง ข้อมูลเพลย์ลิสต์ใหม่จะถูกโหลดใหม่ ในเวลานี้ เราเพียงแต่ต้องส่ง ID ไปให้ unique
และใช้วิธีการเติม เมื่อ ID เปลี่ยนแปลง เพลงใหม่ จะถูกโหลดข้อมูลเดี่ยวโดยอัตโนมัติ
คุณจะเห็นว่า <Rendering/>
สะดวกในการใช้งานมากในหน้านี้ เมื่อเขียนหน้านี้ เราจะเน้นไปที่เนื้อหาของ CommonVideoMatrices
เท่านั้น โดยไม่ต้องคำนึงถึงวิธีการเก็บข้อมูลและตรรกะ จริงๆ แล้วข้อมูลในหน้านี้ก็คือ กำลังโหลด เอฟเฟกต์ภาพเคลื่อนไหวจะปรากฏขึ้น สิ่งเหล่านี้จะเสร็จสมบูรณ์โดย <Rendering/>
แต่ส่วนนี้ได้รับการปรับปรุงให้ดีขึ้นในข้อมูลโค้ดที่แสดงที่นี่
ในความเป็นจริงมีอีกสิ่งหนึ่งที่เรียกว่า
adapter
ที่ใช้ในการแก้ปัญหาแบ็กเอนด์ที่ส่งคืนข้อมูลประเภทเดียวกันในที่ต่างกัน แต่มีโครงสร้างข้อมูลต่างกัน แต่ฉันจะไม่แนะนำที่นี่
นี่เป็นโปรเจ็กต์สำหรับมือใหม่ ฉันหวังว่ามันจะสร้างแรงบันดาลใจและอ้างอิงถึงนักเรียนบางคนที่ยังใหม่กับ front-end/Vue และไม่สามารถหาแนวทางปฏิบัติของโปรเจ็กต์ใดๆ ได้ ว่าหลังจากอ่านบทนี้แล้ว ก็จะมีความเข้าใจในส่วนของ Source Code ของ Project นี้ชัดเจนขึ้น