แนะนำการอ่าน:
ใช้การเชื่อมโยงข้อมูลสองทาง JS ที่ง่ายมาก
MVVM เป็นรูปแบบการพัฒนาที่ได้รับความนิยมอย่างมากสำหรับ Web Front-end การใช้ MVVM สามารถทำให้รหัสของเรามุ่งเน้นไปที่การจัดการกับตรรกะทางธุรกิจมากกว่าที่จะใส่ใจเกี่ยวกับการดำเนินงาน DOM ปัจจุบันเฟรมเวิร์ก MVVM ที่มีชื่อเสียง ได้แก่ Vue, Avalon, React, ฯลฯ กรอบเหล่านี้มีข้อได้เปรียบของตัวเอง แต่แนวคิดการใช้งานนั้นเหมือนกัน: การเชื่อมโยงข้อมูล + ดูการรีเฟรชดู จากความอยากรู้อยากเห็นและความเต็มใจที่จะดิ้นรนฉันยังเขียนห้องสมุด MVVM ที่ง่ายที่สุด (MVVM.JS) ตามทิศทางนี้ด้วยรหัสทั้งหมดมากกว่า 2,000 บรรทัด การตั้งชื่อและการใช้คำแนะนำนั้นคล้ายกับ Vue ที่นี่ฉันจะแบ่งปันหลักการของการดำเนินการและแนวคิดการจัดระเบียบรหัสของฉัน
การเรียงลำดับความคิด
MVVM เป็นแนวคิดที่แยกมุมมองออกจากตรรกะข้อมูลอย่างแท้จริงและ ViewModel เป็นจุดสนใจของรูปแบบทั้งหมด ในการใช้ ViewModel คุณต้องเชื่อมโยงโมเดลข้อมูล (โมเดล) และมุมมอง (มุมมอง) แนวคิดการใช้งานทั้งหมดสามารถสรุปได้เพียง 5 คะแนน:
ใช้คอมไพเลอร์เพื่อสแกนและแยกคำแนะนำสำหรับแต่ละโหนดขององค์ประกอบ
ใช้ตัวแยกวิเคราะห์เพื่อแยกวิเคราะห์คำแนะนำเกี่ยวกับองค์ประกอบซึ่งสามารถอัปเดตความตั้งใจของคำสั่งไปยัง DOM ผ่านฟังก์ชั่นรีเฟรช (โมดูลที่อาจรับผิดชอบโดยเฉพาะสำหรับการรีเฟรชมุมมองอาจจำเป็นต้องมีการรีเฟรชตรงกลาง) ตัวอย่างเช่นเมื่อวิเคราะห์โหนด <p v-show = "iSshow"> </p> ก่อนอื่นให้ได้ค่าของ isshow ในแบบจำลองก่อนจากนั้นเปลี่ยน node.style.display ตาม ISShow เพื่อควบคุมการแสดงผลและซ่อนองค์ประกอบ;
การใช้งานผู้เฝ้าดูสามารถเชื่อมโยงฟังก์ชั่นรีเฟรชของแต่ละคำสั่งในตัวแยกวิเคราะห์กับฟิลด์ที่สอดคล้องกับโมเดล
ใช้ผู้สังเกตการณ์เพื่อตรวจสอบการเปลี่ยนแปลงค่าของฟิลด์ทั้งหมดของวัตถุและเมื่อมีการเปลี่ยนแปลงเกิดขึ้นค่าล่าสุดสามารถรับได้และสามารถเรียกการโทรกลับการแจ้งเตือนได้
ใช้ผู้สังเกตการณ์เพื่อสร้างการตรวจสอบโมเดลในผู้เฝ้าดู เมื่อค่าในโมเดลเปลี่ยนแปลงการตรวจสอบจะถูกทริกเกอร์ หลังจากที่ผู้เฝ้าดูได้รับค่าใหม่จะเรียกฟังก์ชันรีเฟรชที่เกี่ยวข้องในขั้นตอนที่ 2 ซึ่งสามารถบรรลุวัตถุประสงค์ในการรีเฟรชมุมมองในขณะที่ข้อมูลเปลี่ยนไป
ตัวอย่างผล
ก่อนอื่นมาดูตัวอย่างการใช้งานขั้นสุดท้ายซึ่งคล้ายกับการสร้างอินสแตนซ์ของกรอบ MVVM อื่น ๆ :
<div id = "Mobile-List"> <h1 v-text = "title"> </h1> <ul> <li v-for = "รายการในแบรนด์"> <b v-text = "item.name"> </b> <span v-show = "showrank" document.QuerySelector ('#mobile-list'); var vm = new mvvm (องค์ประกอบ, {'title': 'รายการมือถือ', 'showrank': จริง, 'แบรนด์': [{'ชื่อ': 'Apple', 'Rank': 1}, {'ชื่อ': 'Galaxy' 3}]}); vm.set ('title', 'อันดับ 3 อันดับแรกอันดับต้น ๆ '); // => <h1> รายการอันดับมือถือ 3 อันดับแรก </h1>การแบ่งโมดูล
ฉันแบ่ง MVVM ออกเป็นห้าโมดูลเพื่อนำไปใช้: คอมไพเลอร์คอมไพเลอร์, ตัวแยกวิเคราะห์, ดูโมดูลรีเฟรชโมดูล, ผู้เฝ้าดูโมดูลการสมัครสมาชิกข้อมูลและผู้สังเกตการณ์โมดูลการฟังข้อมูล กระบวนการสามารถอธิบายสั้น ๆ ได้ว่า: หลังจากคอมไพเลอร์คอมไพล์คำสั่งข้อมูลคำสั่งจะถูกส่งไปยังตัวแยกวิเคราะห์สำหรับการแยกวิเคราะห์ Parser จะอัปเดตค่าเริ่มต้นและสมัครรับข้อมูลไปยังผู้เฝ้าดูสำหรับการเปลี่ยนแปลงข้อมูล ผู้สังเกตการณ์ตรวจสอบการเปลี่ยนแปลงข้อมูลจากนั้นป้อนกลับไปที่ผู้เฝ้าดู ผู้เฝ้าดูแจ้งให้ทราบถึงการปรับปรุงผลการเปลี่ยนแปลงและค้นหาฟังก์ชั่นรีเฟรชที่สอดคล้องกันเพื่อรีเฟรชมุมมอง
กระบวนการด้านบนแสดงในรูป:
ต่อไปนี้เป็นคำอธิบายของหลักการพื้นฐานของการใช้งานของทั้งห้าโมดูลเหล่านี้ (รหัสถูกโพสต์เฉพาะในส่วนสำคัญโปรดไปที่ GitHub ของฉันเพื่อการใช้งานที่สมบูรณ์)
1. คอมไพล์คอมไพล์คอมไพเลอร์
ความรับผิดชอบของคอมไพเลอร์ส่วนใหญ่จะสแกนและแยกคำแนะนำสำหรับแต่ละโหนดขององค์ประกอบ เนื่องจากกระบวนการรวบรวมและการแยกวิเคราะห์จะสำรวจต้นไม้โหนดทั้งหมดหลายครั้งเพื่อปรับปรุงประสิทธิภาพการรวบรวมในตัวสร้าง MVVM จึงแปลงองค์ประกอบแรกเป็นสำเนาของชิ้นส่วนเอกสาร วัตถุรวบรวมเป็นส่วนของเอกสารนี้และไม่ควรเป็นองค์ประกอบเป้าหมาย หลังจากรวบรวมโหนดทั้งหมดชิ้นส่วนเอกสารจะถูกเพิ่มกลับไปยังโหนดจริงดั้งเดิม
VM.complielement ใช้การสแกนและการสกัดคำสั่งของโหนดทั้งหมดขององค์ประกอบ:
vm.compilelement = ฟังก์ชั่น (ชิ้นส่วน, รูท) {var node, childNodes = fragment.childnodes; // สแกนโหนดเด็กสำหรับ (var i = 0; i <childnodes.length; i ++) {node = childNodes [i]; ถ้า (node) สแกนโหนดลูกของโหนดลูกถ้า (node.childnodes.length) {this.compilelement (โหนด, เท็จ);}} // สแกนโหนดลูกถ้า (รูท) ถ้า (รูท)วิธี VM.CompileAllNodes จะรวบรวมแต่ละโหนดในนี้ $ uncompilenodes (ทิ้งข้อมูลคำสั่งไว้ที่ parser) หลังจากรวบรวมโหนดมันจะถูกลบออกจากคิวแคช ในเวลาเดียวกันตรวจสอบสิ่งนี้ $ uncompilenodes.length เมื่อความยาว === 0 หมายความว่าการรวบรวมทั้งหมดเสร็จสมบูรณ์ คุณสามารถผนวกชิ้นส่วนเอกสารเข้ากับโหนดจริง
2. คำสั่งแยกโมดูลแยกวิเคราะห์ตัวแยกวิเคราะห์
เมื่อคอมไพเลอร์คอมไพเลอร์สกัดคำแนะนำจากแต่ละโหนดจะสามารถส่งไปยังตัวแยกวิเคราะห์เพื่อแยกวิเคราะห์ แต่ละคำสั่งมีวิธีการแยกวิเคราะห์ที่แตกต่างกัน คำแนะนำทั้งหมดต้องทำสองสิ่งเท่านั้น: หนึ่งคือการอัปเดตค่าข้อมูลไปยังมุมมอง (สถานะเริ่มต้น) และอีกสิ่งหนึ่งคือการสมัครรับฟังก์ชั่นรีเฟรชไปยังการตรวจสอบการเปลี่ยนแปลงของโมเดล ที่นี่เราใช้การแยกวิเคราะห์ V-text เป็นตัวอย่างเพื่ออธิบายวิธีการวิเคราะห์ทั่วไปของคำสั่ง:
parser.parsEvtext = ฟังก์ชั่น (โหนด, โมเดล) {// รับค่าเริ่มต้นที่กำหนดไว้ในโมเดล var text = this. $ model [model]; // อัปเดต node text.textContent = text; // ฟังก์ชั่นการรีเฟรชที่สอดคล้องกัน: // updater.updatenodetextcontent (Node, Text) {node.TextContent = last; // updater.upDatenodeTextContent (โหนด, ข้อความ);});}3. ผู้เฝ้าดูโมดูลสมัครสมาชิกข้อมูล
ในตัวอย่างก่อนหน้า Watcher มีวิธีการดูเพื่อสมัครรับการเปลี่ยนแปลงข้อมูล พารามิเตอร์หนึ่งคือโมเดลฟิลด์โมเดลและอื่น ๆ คือฟังก์ชั่นการโทรกลับ ฟังก์ชั่นการโทรกลับถูกเรียกผ่านผู้สังเกตการณ์ ค่าใหม่ค่าเก่าและเก่าเก่าจะถูกส่งผ่านในพารามิเตอร์ หลังจากที่ผู้เฝ้าดูได้รับค่าใหม่มันสามารถค้นหาการเรียกกลับที่เกี่ยวข้อง (ฟังก์ชั่นรีเฟรช) ของโมเดลเพื่ออัปเดตมุมมอง ฟังก์ชั่นโมเดลและรีเฟรชเป็นความสัมพันธ์แบบหนึ่งต่อหลายคนนั่นคือโมเดลสามารถมีฟังก์ชั่นการโทรกลับ (ฟังก์ชั่นรีเฟรช) ที่จัดการได้เช่น: v-text = "title" และ v-html = "title" คำสั่งแชร์ฟิลด์โมเดลข้อมูล
เพิ่มการสมัครสมาชิกข้อมูลไปยังวิธีการใช้งาน Watch Watch คือ:
watcher.watch = function (ฟิลด์, การโทรกลับ, บริบท) {var callbacks = this. $ watchCallbacks; if (! object.hasownProperty.call (นี้. $ รุ่น, ฟิลด์)) {console.warn ('ฟิลด์:' + ฟิลด์ + 'ไม่ได้อยู่ในแบบจำลอง!'); [];} // การโทรกลับแคช [ฟิลด์] .push ([การโทรกลับ, บริบท]);}เมื่อฟิลด์ฟิลด์ของโมเดลข้อมูลเปลี่ยนไปผู้เฝ้าดูจะเรียกการโทรกลับทั้งหมดในอาร์เรย์แคชที่สมัครสมาชิกไปยังฟิลด์
4. ผู้สังเกตการณ์โมดูลการตรวจสอบข้อมูล
ผู้สังเกตการณ์เป็นรากฐานหลักของการใช้งาน MVVM ทั้งหมด ฉันอ่านบทความที่บอกว่า OO (Object.observe) จะจุดประกายการปฏิวัติข้อมูลที่มีผลผูกพันและนำอิทธิพลอย่างมากมาสู่ส่วนหน้า น่าเสียดายที่ร่าง ES7 ได้ละทิ้ง OO! ปัจจุบันไม่มีการสนับสนุนเบราว์เซอร์! โชคดีที่ยังมี Object.defineProperty ที่สามารถจำลองผู้สังเกตการณ์ง่ายๆโดยการสกัดกั้นตัวบ่งชี้การเข้าถึง (รับและตั้งค่า) ของคุณสมบัติของวัตถุ:
// สกัดกั้นวิธีการรับและการตั้งค่าของคุณสมบัติ POP ของ Object Object.defineProperty (วัตถุ, prop, {get: function () {return this.getValue (prop, prop);}, set: function (newValue) {var oldValue = this.getValue prop); // ทริกเกอร์เปลี่ยนการโทรกลับ this.triggerChange (prop, newValue, oldValue);}}});จากนั้นมีคำถามอื่น: วิธีการตรวจสอบการดำเนินการอาร์เรย์ (พุช, กะ ฯลฯ )? เฟรมเวิร์ก MVVM ทั้งหมดถูกนำมาใช้โดยการเขียนต้นแบบของอาร์เรย์ใหม่:
Observer.RewriteArrayMethods = ฟังก์ชั่น (อาร์เรย์) {var self = this; var arrayproto = array.prototype; var arraymethods = object.create (arrayproto); วิธี var = 'push | pop | shift | unshife | splice | sort | reverse'.split Methods.foreach (ฟังก์ชั่น (วิธีการ) {object.defineProperty (arrayMethods, วิธี, ฟังก์ชัน () {var i = อาร์กิวเมนต์ความยาว; วิธี); ผลตอบแทนผลลัพธ์});}); อาร์เรย์ .__ proto__ = arraymethods;}วิธีการใช้งานนี้อ้างอิงจาก Vue ฉันคิดว่ามันใช้งานได้ดีมาก แต่แอตทริบิวต์ความยาวของอาร์เรย์ไม่สามารถฟังได้ดังนั้นใน MVVM ควรหลีกเลี่ยงการทำงานของอาร์เรย์ความยาว
5. ดูอัพเดทโมดูลรีเฟรช
Updater เป็นวิธีที่ง่ายที่สุดในห้าโมดูลคุณจะต้องรับผิดชอบฟังก์ชั่นรีเฟรชที่สอดคล้องกับแต่ละคำสั่ง หลังจากชุดของการโยนและออกจากผลลัพธ์สุดท้ายไปยัง updater สำหรับการอัปเดตมุมมองหรือการอัปเดตเหตุการณ์เช่นฟังก์ชั่นการรีเฟรชของข้อความ V คือ:
updater.upDatenodeTextContent = function (node, text) {node.TextContent = text;}ฟังก์ชั่นรีเฟรชของ V-bind: Style:
updater.updatenodestyle = function (โหนด, คุณสมบัติ, ค่า) {node.style [propperty] = value;}การใช้งานการเชื่อมโยงข้อมูลสองทาง
การเชื่อมข้อมูลแบบสองทิศทางขององค์ประกอบแบบฟอร์มเป็นหนึ่งในคุณสมบัติที่ใหญ่ที่สุดของ MVVM:
ในความเป็นจริงหลักการใช้งานของฟังก์ชั่นเวทมนตร์นี้ก็ง่ายมากเช่นกัน มีเพียงสองสิ่งที่ต้องทำ: หนึ่งคือการอัปเดตค่าฟอร์มเมื่อข้อมูลเปลี่ยนแปลงและอีกสิ่งหนึ่งคือการอัปเดตข้อมูลเมื่อค่าฟอร์มเปลี่ยนแปลงเพื่อให้ค่าข้อมูลถูกผูกไว้กับค่าฟอร์ม
การเปลี่ยนแปลงข้อมูลเพื่ออัปเดตค่าฟอร์มสามารถทำได้อย่างง่ายดายโดยใช้โมดูล Watcher ที่กล่าวถึงข้างต้น:
watcher.watch (โมเดล, ฟังก์ชั่น (สุดท้าย, เก่า) {input.value = สุดท้าย;}); 'ในการอัปเดตข้อมูลในการเปลี่ยนแปลงรูปแบบคุณจะต้องฟังเหตุการณ์ที่คุ้มค่าในแบบฟอร์มแบบเรียลไทม์และอัปเดตฟิลด์ที่เกี่ยวข้องของรูปแบบข้อมูล:
var model = this. $ model; input.addeventListenr ('เปลี่ยน', function () {model [field] = this.value;}); 'วิทยุรูปแบบอื่น ๆ ช่องทำเครื่องหมายและเลือกเป็นหลักการเดียวกัน
ข้างต้นกระบวนการทั้งหมดและแนวคิดการใช้งานพื้นฐานของแต่ละโมดูลได้รับการอธิบาย ครั้งแรกที่ฉันโพสต์บทความในชุมชนทักษะการแสดงออกทางภาษาของฉันไม่ค่อยดีนัก หากมีคำที่ผิดและสิ่งเลวร้ายที่เขียนฉันหวังว่าทุกคนจะสามารถวิพากษ์วิจารณ์และแก้ไขได้!
บทสรุป
ฉันกำลังลอง mvvm.js ง่าย ๆ นี้เพราะฉันใช้ vue.js ในโครงการเฟรมเวิร์กของฉัน แต่ฉันเพิ่งใช้ระบบการเรียนการสอน มีฟังก์ชั่นจำนวนมากเพียงประมาณหนึ่งในสี่เท่านั้น ฉันคิดว่ามันจะเพียงพอที่จะใช้การเชื่อมโยงข้อมูลและการดูฟรี เป็นผลให้ฉันไม่พบไลบรารี JavaScript ดังนั้นฉันจึงสร้างล้อด้วยตัวเอง
แม้ว่าฟังก์ชั่นและความเสถียรจะน้อยกว่าเฟรมเวิร์ก MVVM ยอดนิยมเช่น Vue และการใช้งานรหัสอาจค่อนข้างหยาบ แต่มีความรู้มากมายที่เพิ่มเข้ามาโดยการสร้างล้อนี้ ~ ความคืบหน้าอยู่ในการโยน!
ในปัจจุบัน MVVM.JS ของฉันใช้ฟังก์ชั่นพื้นฐานที่สุดเท่านั้น ฉันจะปรับปรุงและเสริมสร้างมันต่อไปในอนาคต หากคุณสนใจโปรดพูดคุยและปรับปรุงด้วยกัน ~