摘要:標(biāo)簽添加監(jiān)聽(tīng)事件文本節(jié)點(diǎn)這一步我們操作頁(yè)面輸入框,可以看到以下效果,證明監(jiān)聽(tīng)事件添加有效。
前言
經(jīng)過(guò)幾天的研究,發(fā)現(xiàn)學(xué)習(xí)框架的底層技術(shù),收獲頗豐,相比只學(xué)習(xí)框架的使用要來(lái)的合算;如果工作急需,快速上手應(yīng)用,掌握如何使用短期內(nèi)更加高效;如果有較多的時(shí)間來(lái)系統(tǒng)學(xué)習(xí),建議研究一下框架的等層技術(shù)、原理。
Vue、React、Angular三大框架對(duì)比1、Vue
Vue是尤雨溪編寫的一個(gè)構(gòu)建數(shù)據(jù)驅(qū)動(dòng)的Web界面的庫(kù),準(zhǔn)確來(lái)說(shuō)不是一個(gè)框架,它聚焦在V(view)視圖層。
它有以下的特性:
1.輕量級(jí)的框架
2.雙向數(shù)據(jù)綁定
3.指令
4.插件化
優(yōu)點(diǎn):
簡(jiǎn)單:官方文檔很清晰,比 Angular 簡(jiǎn)單易學(xué)。
快速:異步批處理方式更新 DOM。
組合:用解耦的、可復(fù)用的組件組合你的應(yīng)用程序。
緊湊:~18kb min+gzip,且無(wú)依賴。
強(qiáng)大:表達(dá)式 無(wú)需聲明依賴的可推導(dǎo)屬性 (computed properties)。
對(duì)模塊友好:可以通過(guò) NPM、Bower 或 Duo 安裝,不強(qiáng)迫你所有的代碼都遵循 Angular 的各種規(guī)定,使用場(chǎng)景更加靈活。
缺點(diǎn):
新生兒:Vue.js是一個(gè)新的項(xiàng)目,沒(méi)有angular那么成熟。
影響度不是很大:google了一下,有關(guān)于Vue.js多樣性或者說(shuō)豐富性少于其他一些有名的庫(kù)。
不支持IE8
2、React
React 起源于 Facebook 的內(nèi)部項(xiàng)目,用來(lái)架設(shè) Instagram 的網(wǎng)站, 并于 2013年 5 月開(kāi)源。React 擁有較高的性能,代碼邏輯非常簡(jiǎn)單,越來(lái)越多的人已開(kāi)始關(guān)注和使用它。
它有以下的特性:
1.聲明式設(shè)計(jì):React采用聲明范式,可以輕松描述應(yīng)用。
2.高效:React通過(guò)對(duì)DOM的模擬,最大限度地減少與DOM的交互。
3.靈活:React可以與已知的庫(kù)或框架很好地配合。
優(yōu)點(diǎn):
速度快:在UI渲染過(guò)程中,React通過(guò)在虛擬DOM中的微操作來(lái)實(shí)現(xiàn)對(duì)實(shí)際DOM的局部更新。
跨瀏覽器兼容:虛擬DOM幫助我們解決了跨瀏覽器問(wèn)題,它為我們提供了標(biāo)準(zhǔn)化的API,甚至在IE8中都是沒(méi)問(wèn)題的。
模塊化:為你程序編寫?yīng)毩⒌哪K化UI組件,這樣當(dāng)某個(gè)或某些組件出現(xiàn)問(wèn)題是,可以方便地進(jìn)行隔離。
單向數(shù)據(jù)流:Flux是一個(gè)用于在JavaScript應(yīng)用中創(chuàng)建單向數(shù)據(jù)層的架構(gòu),它隨著React視圖庫(kù)的開(kāi)發(fā)而被Facebook概念化。
同構(gòu)、純粹的javascript:因?yàn)樗阉饕娴呐老x(chóng)程序依賴的是服務(wù)端響應(yīng)而不是JavaScript的執(zhí)行,預(yù)渲染你的應(yīng)用有助于搜索引擎優(yōu)化。
兼容性好:比如使用RequireJS來(lái)加載和打包,而B(niǎo)rowserify和Webpack適用于構(gòu)建大型應(yīng)用。它們使得那些艱難的任務(wù)不再讓人望而生畏。
缺點(diǎn):
React本身只是一個(gè)V而已,并不是一個(gè)完整的框架,所以如果是大型項(xiàng)目想要一套完整的框架的話,基本都需要加上ReactRouter和Flux才能寫大型應(yīng)用。
3、Angular
Angular是一款優(yōu)秀的前端JS框架,已經(jīng)被用于Google的多款產(chǎn)品當(dāng)中。
它有以下的特性:
1.良好的應(yīng)用程序結(jié)構(gòu)
2.雙向數(shù)據(jù)綁定
3.指令
4.HTML模板
5.可嵌入、注入和測(cè)試
優(yōu)點(diǎn):
模板功能強(qiáng)大豐富,自帶了極其豐富的angular指令。
是一個(gè)比較完善的前端框架,包含服務(wù),模板,數(shù)據(jù)雙向綁定,模塊化,路由,過(guò)濾器,依賴注入等所有功能;
自定義指令,自定義指令后可以在項(xiàng)目中多次使用。
ng模塊化比較大膽的引入了Java的一些東西(依賴注入),能夠很容易的寫出可復(fù)用的代碼,對(duì)于敏捷開(kāi)發(fā)的團(tuán)隊(duì)來(lái)說(shuō)非常有幫助。
angularjs是互聯(lián)網(wǎng)巨人谷歌開(kāi)發(fā),這也意味著他有一個(gè)堅(jiān)實(shí)的基礎(chǔ)和社區(qū)支持。
缺點(diǎn):
angular 入門很容易 但深入后概念很多, 學(xué)習(xí)中較難理解.
文檔例子非常少, 官方的文檔基本只寫了api, 一個(gè)例子都沒(méi)有, 很多時(shí)候具體怎么用都是google來(lái)的, 或直接問(wèn)misko,angular的作者.
對(duì)IE6/7 兼容不算特別好, 就是可以用jQuery自己手寫代碼解決一些.
指令的應(yīng)用的最佳實(shí)踐教程少, angular其實(shí)很靈活, 如果不看一些作者的使用原則,很容易寫出 四不像的代碼, 例如js中還是像jQuery的思想有很多dom操作.
DI 依賴注入 如果代碼壓縮需要顯示聲明.
通過(guò)以上相比較,您更加傾向于學(xué)習(xí)哪一個(gè)呢?
正題:Vue的基本原理1、建立虛擬DOM Tree,通過(guò)document.createDocumentFragment(),遍歷指定根節(jié)點(diǎn)內(nèi)部節(jié)點(diǎn),根據(jù){{ prop }}、v-model等規(guī)則進(jìn)行compile;
2、通過(guò)Object.defineProperty()進(jìn)行數(shù)據(jù)變化攔截;
3、截取到的數(shù)據(jù)變化,通過(guò)發(fā)布者-訂閱者模式,觸發(fā)Watcher,從而改變虛擬DOM中的具體數(shù)據(jù);
4、通過(guò)改變虛擬DOM元素值,從而改變最后渲染dom樹(shù)的值,完成雙向綁定
完成數(shù)據(jù)的雙向綁定在于Object.defineProperty()
Vue雙向綁定的實(shí)現(xiàn)1、簡(jiǎn)易雙綁
首先,我們把注意力集中在這個(gè)屬性上:Object.defineProperty。
Object.defineProperty() 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性, 并返回這個(gè)對(duì)象。
語(yǔ)法:Object.defineProperty(obj, prop, descriptor)
什么叫做,定義或修改一個(gè)對(duì)象的新屬性,并返回這個(gè)對(duì)象呢?
var obj = {}; Object.defineProperty(obj,"hello",{ get:function(){ //我們?cè)谶@里攔截到了數(shù)據(jù) console.log("get方法被調(diào)用"); }, set:function(newValue){ //改變數(shù)據(jù)的值,攔截下來(lái)額 console.log("set方法被調(diào)用"); } }); obj.hello//輸出為“get方法被調(diào)用”,輸出了值。 obj.hello = "new Hello";//輸出為set方法被調(diào)用,修改了新值
通過(guò)以上方法可以看出,獲取對(duì)象屬性值觸發(fā)get、設(shè)置對(duì)象屬性值觸發(fā)set,因此我們可以想象到數(shù)據(jù)模型對(duì)象的屬性設(shè)置和讀取可以驅(qū)動(dòng)view層的數(shù)據(jù)變化,view的數(shù)據(jù)變化傳遞給數(shù)據(jù)模型對(duì)象,在set里面可以做很多事情。
在這基礎(chǔ)上,我們可以做到數(shù)據(jù)的雙向綁定:
let obj = {}; Object.defineProperty(obj, "name", { set: function(newValue){ console.log("觸發(fā)setter"); document.querySelector(".text-box").innerHTML = newValue; document.querySelector(".inp-text").value = newValue; }, get: function(){ console.log("觸發(fā)getter"); } }); document.querySelector(".inp-text").addEventListener("keyup", function(e){ obj.name = e.target.value; }, false);
html
以上只是vue的核心思想,通過(guò)對(duì)象底層屬性的set和get進(jìn)行數(shù)據(jù)攔截,vue的虛擬dom又是怎么實(shí)現(xiàn)的,且看以下分解。
2、虛擬DOM樹(shù)
創(chuàng)建虛擬DOM:
var frag = document.createDocumentFragment();
view層的{{msg}}和v-model的編譯規(guī)則如下:
html:
{{ msg }}
{{ msg }}
view層做了多層嵌套,這樣測(cè)試更多出現(xiàn)錯(cuò)誤的可能性。
var container = document.getElementById("container"); //這里我們把vue實(shí)例中的data提取出來(lái),更加直觀 var data = { msg: "Hello world!", inpText: "Input text" }; var fragment = virtualDom(container, data); container.appendChild(fragment); //虛擬dom創(chuàng)建方法 function virtualDom(node, data){ let frag = document.createDocumentFragment(); let child; // 遍歷dom節(jié)點(diǎn) while(child = node.firstChild){ compile(child, data); frag.appendChild(child); } return frag; } //編譯規(guī)則 function compile(node, data){ let reg = /{{(.*)}}/g; if(node.nodeType === 1){ // 標(biāo)簽 let attr = node.attributes; for(let i = 0, len = attr.length; i < len; i++){ // console.log(attr[i].nodeName, attr[i].nodeValue); if(attr[i].nodeName === "v-model"){ let name = attr[i].nodeValue; node.value = data[name]; } } if(node.hasChildNodes()){ node.childNodes.forEach((item) => { compile(item, data); // 遞歸 }); } } if(node.nodeType === 3){ // 文本節(jié)點(diǎn) if(reg.test(node.nodeValue)){ let name = RegExp.$1; name = name.trim(); node.nodeValue = data[name]; } } }
解釋:
1、通過(guò)virtualDom創(chuàng)建虛擬節(jié)點(diǎn),將目標(biāo)盒子內(nèi)所有子節(jié)點(diǎn)添加到其內(nèi)部,注意這里只是子節(jié)點(diǎn);
2、子節(jié)點(diǎn)通過(guò)compile進(jìn)行編譯,a:如果節(jié)點(diǎn)為元素,其nodeType = 1,b:如果節(jié)點(diǎn)為文本,其nodeType = 3,具體可以查看詳情http://www.w3school.com.cn/js...;
3、如果第二步子節(jié)點(diǎn)仍有子節(jié)點(diǎn),通過(guò)hasChildNodes()來(lái)確認(rèn),如果有遞歸調(diào)用compile方法。
3、響應(yīng)式原理
核心思想:Object.defineProperty(obj, key, {set, get})
function defineReact(obj, key, value){ Object.defineProperty(obj, key, { set: function(newValue){ console.log(`觸發(fā)setter`); value = newValue; console.log(value); }, get: function(){ console.log(`觸發(fā)getter`); return value; } }); }
這里是針對(duì)data數(shù)據(jù)的屬性的響應(yīng)式定義,但是如何去實(shí)現(xiàn)vue實(shí)例vm綁定data每個(gè)屬性,通過(guò)以下方法:
function observe(obj, vm){ Object.keys(obj).forEach((key) => { defineReact(vm, key, obj[key]); }) }
vue的構(gòu)造函數(shù):
function Vue(options){ this.data = options.data; let id = options.el; observe(this.data, this); // 將每個(gè)data屬相綁定到Vue的實(shí)例上this }
通過(guò)以上我們可以實(shí)現(xiàn)Vue實(shí)例綁定data屬性。
如何去實(shí)現(xiàn)Vue,通常我們實(shí)例化Vue是這樣的:
var vm = new Vue({ el: "container", data: { msg: "Hello world!", inpText: "Input text" } }); console.log(vm.msg); // Hello world! console.log(vm.inpText); // Input text
實(shí)現(xiàn)以上效果,我們必須在vue內(nèi)部初始化虛擬Dom
function Vue(options){ this.data = options.data; let id = options.el; observe(this.data, this); // 將每個(gè)data屬相綁定到Vue的實(shí)例上this //------------------------添加以下代碼 let container = document.getElementById(id); let fragment = virtualDom(container, this); // 這里通過(guò)vm對(duì)象初始化 container.appendChild(fragment); }
這是我們?cè)賹?duì)Vue進(jìn)行實(shí)例化,則可以看到以下頁(yè)面:
至此我們實(shí)現(xiàn)了dom的初始化,下一步我們?cè)趘-model元素添加監(jiān)聽(tīng)事件,這樣就可以通過(guò)view層的操作來(lái)修改vm對(duì)應(yīng)的屬性值。在compile編譯的時(shí)候,可以準(zhǔn)確的找到v-model屬相元素,因此我們把監(jiān)聽(tīng)事件添加到compile內(nèi)部。
function compile(node, data){ let reg = /{{(.*)}}/g; if(node.nodeType === 1){ // 標(biāo)簽 let attr = node.attributes; for(let i = 0, len = attr.length; i < len; i++){ // console.log(attr[i].nodeName, attr[i].nodeValue); if(attr[i].nodeName === "v-model"){ let name = attr[i].nodeValue; node.value = data[name]; // ------------------------添加監(jiān)聽(tīng)事件 node.addEventListener("keyup", function(e){ data[name] = e.target.value; }, false); // ----------------------------------- } } if(node.hasChildNodes()){ node.childNodes.forEach((item) => { compile(item, data); }); } } if(node.nodeType === 3){ // 文本節(jié)點(diǎn) if(reg.test(node.nodeValue)){ let name = RegExp.$1; name = name.trim(); node.nodeValue = data[name]; } } }
這一步我們操作頁(yè)面輸入框,可以看到以下效果,證明監(jiān)聽(tīng)事件添加有效。
到這里我們已經(jīng)實(shí)現(xiàn)了MVVM的,即Model -> vm -> View || View -> vm -> Model 中間橋梁就是vm實(shí)例對(duì)象。
4、觀察者模式原理
觀察者模式也稱為發(fā)布者-訂閱者模式,這樣說(shuō)應(yīng)該會(huì)更容易理解,更加形象。
訂閱者:
var subscribe_1 = { update: function(){ console.log("This is subscribe_1"); } }; var subscribe_2 = { update: function(){ console.log("This is subscribe_2"); } }; var subscribe_3 = { update: function(){ console.log("This is subscribe_3"); } };
三個(gè)訂閱者都有update方法。
發(fā)布者:
function Publisher(){ this.subs = [subscribe_1, subscribe_2, subscribe_3]; // 添加訂閱者 } Publisher.prototype = { constructor: Publisher, notify: function(){ this.subs.forEach(function(sub){ sub.update(); }) } };
發(fā)布者通過(guò)notify方法對(duì)訂閱者廣播,訂閱者通過(guò)update來(lái)接受信息。
實(shí)例化publisher:
var publisher = new Publisher(); publisher.notify();
這里我們可以做一個(gè)中間件來(lái)處理發(fā)布者-訂閱者模式:
var publisher = new Publisher(); var middleware = { publish: function(){ publisher.notify(); } }; middleware.publish();
5、觀察者模式嵌入
到這一步,我們已經(jīng)實(shí)現(xiàn)了:
1、修改v-model屬性元素 -> 觸發(fā)修改vm的屬性值 -> 觸發(fā)set
2、發(fā)布者添加訂閱 -> notify分發(fā)訂閱 -> 訂閱者update數(shù)據(jù)
接下來(lái)我們要實(shí)現(xiàn):更新視圖,同時(shí)把訂閱——發(fā)布者模式嵌入。
發(fā)布者:
function Publisher(){ this.subs = []; // 訂閱者容器 } Publisher.prototype = { constructor: Publisher, add: function(sub){ this.subs.push(sub); // 添加訂閱者 }, notify: function(){ this.subs.forEach(function(sub){ sub.update(); // 發(fā)布訂閱 }); } };
訂閱者:
考慮到要把訂閱者綁定data的每個(gè)屬性,來(lái)觀察屬性的變化,參數(shù):name參數(shù)可以有compile中獲取的name傳參。由于傳入的node節(jié)點(diǎn)類型分為兩種,我們可以分為兩訂閱者來(lái)處理,同時(shí)也可以對(duì)node節(jié)點(diǎn)類型進(jìn)行判斷,通過(guò)switch分別處理。
function Subscriber(node, vm, name){ this.node = node; this.vm = vm; this.name = name; } Subscriber.prototype = { constructor: Subscriber, update: function(){ let vm = this.vm; let node = this.node; let name = this.name; switch(this.node.nodeType){ case 1: node.value = vm[name]; break; case 3: node.nodeValue = vm[name]; break; default: break; } } };
我們要把訂閱者添加到compile進(jìn)行虛擬dom的初始化,替換掉原來(lái)的賦值:
function compile(node, data){ let reg = /{{(.*)}}/g; if(node.nodeType === 1){ // 標(biāo)簽 let attr = node.attributes; for(let i = 0, len = attr.length; i < len; i++){ // console.log(attr[i].nodeName, attr[i].nodeValue); if(attr[i].nodeName === "v-model"){ let name = attr[i].nodeValue; // --------------------這里被替換掉 // node.value = data[name]; new Subscriber(node, data, name); // ------------------------添加監(jiān)聽(tīng)事件 node.addEventListener("keyup", function(e){ data[name] = e.target.value; }, false); } } if(node.hasChildNodes()){ node.childNodes.forEach((item) => { compile(item, data); }); } } if(node.nodeType === 3){ // 文本節(jié)點(diǎn) if(reg.test(node.nodeValue)){ let name = RegExp.$1; name = name.trim(); // ---------------------這里被替換掉 // node.nodeValue = data[name]; new Subscriber(node, data, name); } } }
既然是對(duì)虛擬dom編譯初始化,Subscriber要初始化,即Subscriber.update,因此要對(duì)Subscriber作進(jìn)一步的處理:
function Subscriber(node, vm, name){ this.node = node; this.vm = vm; this.name = name; this.update(); } Subscriber.prototype = { constructor: Subscriber, update: function(){ let vm = this.vm; let node = this.node; let name = this.name; switch(this.node.nodeType){ case 1: node.value = vm[name]; break; case 3: node.nodeValue = vm[name]; break; default: break; } } };
發(fā)布者添加到defineReact,來(lái)觀察數(shù)據(jù)的變化:
function defineReact(data, key, value){ let publisher = new Publisher(); Object.defineProperty(data, key, { set: function(newValue){ console.log(`觸發(fā)setter`); value = newValue; console.log(value); publisher.notify(); // 發(fā)布訂閱 }, get: function(){ console.log(`觸發(fā)getter`); if(Publisher.global){ //這里為什么來(lái)添加判斷條件,主要是讓publisher.add只執(zhí)行一次,初始化虛擬dom編譯的時(shí)候來(lái)執(zhí)行 publisher.add(Publisher.global); // 添加訂閱者 } return value; } }); }
這一步將訂閱者添加到發(fā)布者容器內(nèi),對(duì)訂閱者改造:
function Subscriber(node, vm, name){ Publisher.global = this; this.node = node; this.vm = vm; this.name = name; this.update(); Publisher.global = null; } Subscriber.prototype = { constructor: Subscriber, update: function(){ let vm = this.vm; let node = this.node; let name = this.name; switch(this.node.nodeType){ case 1: node.value = vm[name]; break; case 3: node.nodeValue = vm[name]; break; default: break; } } };
6、完整效果
html:
{{ msg }}
{{ inpText }}
{{ msg }}
javascript:
function Publisher(){ this.subs = []; } Publisher.prototype = { constructor: Publisher, add: function(sub){ this.subs.push(sub); }, notify: function(){ this.subs.forEach(function(sub){ sub.update(); }); } }; function Subscriber(node, vm, name){ Publisher.global = this; this.node = node; this.vm = vm; this.name = name; this.update(); Publisher.global = null; // 清空 } Subscriber.prototype = { constructor: Subscriber, update: function(){ let vm = this.vm; let node = this.node; let name = this.name; switch(this.node.nodeType){ case 1: node.value = vm[name]; break; case 3: node.nodeValue = vm[name]; break; default: break; } } }; function virtualDom(node, data){ let frag = document.createDocumentFragment(); let child; // 遍歷dom節(jié)點(diǎn) while(child = node.firstChild){ compile(child, data); frag.appendChild(child); } return frag; } function compile(node, data){ let reg = /{{(.*)}}/g; if(node.nodeType === 1){ // 標(biāo)簽 let attr = node.attributes; for(let i = 0, len = attr.length; i < len; i++){ // console.log(attr[i].nodeName, attr[i].nodeValue); if(attr[i].nodeName === "v-model"){ let name = attr[i].nodeValue; // node.value = data[name]; // ------------------------添加監(jiān)聽(tīng)事件 node.addEventListener("keyup", function(e){ data[name] = e.target.value; }, false); new Subscriber(node, data, name); } } if(node.hasChildNodes()){ node.childNodes.forEach((item) => { compile(item, data); }); } } if(node.nodeType === 3){ // 文本節(jié)點(diǎn) if(reg.test(node.nodeValue)){ let name = RegExp.$1; name = name.trim(); // node.nodeValue = data[name]; new Subscriber(node, data, name); } } } function defineReact(data, key, value){ let publisher = new Publisher(); Object.defineProperty(data, key, { set: function(newValue){ console.log(`觸發(fā)setter`); value = newValue; console.log(value); publisher.notify(); // 發(fā)布訂閱 }, get: function(){ console.log(`觸發(fā)getter`); if(Publisher.global){ publisher.add(Publisher.global); // 添加訂閱者 } return value; } }); } // 將data中數(shù)據(jù)綁定到vm實(shí)例對(duì)象上 function observe(data, vm){ Object.keys(data).forEach((key) => { defineReact(vm, key, data[key]); }) } function Vue(options){ this.data = options.data; let id = options.el; observe(this.data, this); // 將每個(gè)data屬相綁定到Vue的實(shí)例vm上 //------------------------ let container = document.getElementById(id); let fragment = virtualDom(container, this); // 這里通過(guò)vm對(duì)象初始化 container.appendChild(fragment); } var vm = new Vue({ el: "container", data: { msg: "Hello world!", inpText: "Input text" } });
未完待續(xù)......
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/116002.html
摘要:前言最近在學(xué)習(xí)框架的基本原理,看了一些技術(shù)博客以及一些對(duì)源碼的簡(jiǎn)單實(shí)現(xiàn),對(duì)數(shù)據(jù)代理數(shù)據(jù)劫持模板解析變異數(shù)組方法雙向綁定有了更深的理解。 前言 最近在學(xué)習(xí)vue框架的基本原理,看了一些技術(shù)博客以及一些對(duì)vue源碼的簡(jiǎn)單實(shí)現(xiàn),對(duì)數(shù)據(jù)代理、數(shù)據(jù)劫持、模板解析、變異數(shù)組方法、雙向綁定有了更深的理解。于是乎,嘗試著去實(shí)踐自己學(xué)到的知識(shí),用vue的一些基本原理實(shí)現(xiàn)一個(gè)簡(jiǎn)單的todo-list,完成...
寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】Props - 源碼版 今天記錄 Props 源碼流程,哎,這東西,就算是研究過(guò)了,也真是會(huì)隨著時(shí)間慢慢忘記的。 幸好我做...
摘要:當(dāng)東西發(fā)售時(shí),就會(huì)打你的電話通知你,讓你來(lái)領(lǐng)取完成更新。其中涉及的幾個(gè)步驟,按上面的例子來(lái)轉(zhuǎn)化一下你買東西,就是你要使用數(shù)據(jù)你把電話給老板,電話就是你的,用于通知老板記下電話在電話本,就是把保存在中。剩下的步驟屬于依賴更新 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【...
摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理依賴更新源碼版如果對(duì)依賴收集完 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...
摘要:背景個(gè)人背景就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí)前端方向,自學(xué),技術(shù)棧時(shí)間背景大概是在月日準(zhǔn)備好簡(jiǎn)歷開(kāi)始投遞秋招差不多已經(jīng)結(jié)束招聘崗位不多,投遞對(duì)象為大一些的互聯(lián)網(wǎng)公司事件背景第一個(gè)入職的是好未來(lái)的前端實(shí)習(xí)崗,待遇工 背景 個(gè)人背景 就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí) 前端方向,自學(xué),vue技術(shù)棧 時(shí)間背景 大概是在11月9日準(zhǔn)備...
摘要:背景個(gè)人背景就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí)前端方向,自學(xué),技術(shù)棧時(shí)間背景大概是在月日準(zhǔn)備好簡(jiǎn)歷開(kāi)始投遞秋招差不多已經(jīng)結(jié)束招聘崗位不多,投遞對(duì)象為大一些的互聯(lián)網(wǎng)公司事件背景第一個(gè)入職的是好未來(lái)的前端實(shí)習(xí)崗,待遇工 背景 個(gè)人背景 就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí) 前端方向,自學(xué),vue技術(shù)棧 時(shí)間背景 大概是在11月9日準(zhǔn)備...
閱讀 3896·2021-09-27 13:35
閱讀 1080·2021-09-24 09:48
閱讀 2910·2021-09-22 15:42
閱讀 2348·2021-09-22 15:28
閱讀 3153·2019-08-30 15:43
閱讀 2622·2019-08-30 13:52
閱讀 2978·2019-08-29 12:48
閱讀 1457·2019-08-26 13:55