哎,不知道多久之前說的要說說vue原理的,后來就忘記了,嘿嘿,這次就來看看vue的大概原理吧!
看過我博客的人應該知道,我不是很喜歡用那種太專業的術語的,喜歡用小白都能看懂的話來說,所以可能有的地方表達的不是很專業,不要打我╮(╯_╰)╭
前提:起碼要簡單使用過vue,知道怎么用
1.vue的作用
首先,我們知道有一個東西叫做mvvm,不懂這個沒關系,其實就是簡稱雙向資料系結,可以拆成三部分,m(model),v(view),vm(viewmodel);
想一想,假如我們要把html標簽中的資料和js中的資料相互產生聯系,一般會怎么做?傳統的做法就是獲取dom節點,然后向其中設定新的值覆寫舊的值就行了,類似下面這樣的:

但是每次都要去獲取這個dom節點真的很煩,當html標簽很多的時候看找這個節點的選擇器都看花了眼,想偷個懶怎么辦?最好是在<script>標簽中寫js代碼的地方,有個變數和html標簽中的變數是一個共同體,只要修改了其中一個另外一個就會發生變化;
那么現在的問題就是,怎么將那個變數和html標簽中的變數建立聯系呢?俗話說得好,解決不了兩個物件之間的關系,那就建立一個中間層就好了,如果建立一個還解決不了,那就再建立一個中間層!
所以這里,我們就需要建立一個中間層來維持js中變數和html中變數的關系,下圖所示,那個vue.js檔案就是中間層;

用專業一點的圖就是這樣的,下圖所示;

現在應該大概懂了啥叫做mvvm了吧!然后我們只需要再深入一下從view->model,然后反著model->view的系結程序就ok了;兩個方向都要看看嘛,所以就叫做雙向系結啊!
2.Object.defineProperty()
第一次看到這個方法肯定比較懵逼,這方法干嘛的啊?
我們可以看看這樣的一個場景,一個物件let a = { name: 0 },如果我要給這個物件的那么屬性修改應該怎么做?我的話,肯定在想,尼瑪誰的name居然是0啊肯定寫錯了,我上去就是一個滑鏟就寫了a.name = "小王";(牛批!鼓掌╮(╯_╰)╭)
那么有沒有想過a.name="小王"這到底是怎么呼叫的啊?為啥一個點然后加個屬性名就可以給這個物件增加一個屬性啊?
我找了一下,有興趣的可以參考這個老哥的博客 ,用一句話來說明就是在你宣告一個物件的時候,js會偷偷的給這個物件添加一個set和get方法,然后這個方法還不讓你看到,只是會在你去a.name的時候會判斷后面有沒有賦值陳述句,有的話就呼叫set方法,沒有的話就呼叫get方法;
如果有小伙伴學過其他的面向物件的語言的,比如java,應該知道這種get/set方法肯定是我們需要自己生成的,能夠實際看得到;
那么現在又來一個奇葩的場景,在使用a.name="小王"的時候,同時還要列印這樣一句話:“呵呵,現在是在修改值哦?乛?乛?”;
第一種方式,我們可以這樣做,手動的去修改a物件去覆寫自帶的set方法:
let a = { // 加了下劃線可以當作私有屬性啊(當然,這個不是真正的私有屬性啊,有興趣的可以看看這個博客真正私有屬性的實作https://www.cnblogs.com/Mr-O-o-Lee/p/13781362.html) _name: 0, // 覆寫自帶的set方法 set name(val) { console.log('呵呵,現在是在修改值哦?乛?乛?'); this._name = val; } } a.name = "小王";
一番波折我們也是完成了,不錯不錯!但是有沒有考慮一個問題,如果這個物件是別人寫的呢?你去把別人寫的東西給改了......,那么我們有沒有什么方法在不修改代碼的情況下實作上面的功能呢?
第二種方法:我們可以使用Object.defineProperty(),我們把上面代碼這樣修改一下,也是可以的(同理,也可以添加get方法,自己試試;)
let a = { _name: 0, } // 在不改變物件的前提下添加功能 Object.defineProperty(a, 'name', { configurable: true, set: (val)=>{ console.log('呵呵,現在是在修改值哦?乛?乛?'); _name = val; } }) a.name = "小王";
瞎比比了大半天,終于快把Object.defineProperty()說完了,上面代碼中有configurable表示描述屬性是否配置,以及可否洗掉,還有enumerable表示該屬性是否能被for in 或者 Object.keys()遍歷到;當然還有其他的屬性自行了解;
而vue中就是使用到了Object.defineProperty(),在上面的例子中可以看到,我們可以給一個物件的屬性添加get/set方法,在修改屬性值的時候,呼叫set方法中拿到新的值的同時還可以做自定義處理的,專業說法叫做資料劫持,
3.資料代理
一句話解釋清楚什么叫做資料代理:就是將data中的所有資料的地址丟到vue實體中一份,以便于我們可以直接使用vue.xxx去獲取屬性值vue.data.xxx,偽代碼如下:

上面這個圖中,假如我們這樣寫myVue.message="world",實際上呼叫的是myVue.data.message="world",所以就會觸發message屬性的資料劫持,呼叫set方法!
4.手動實作的代碼
html部分:
<body> <div id="app"> <h1>{{message}}</h1> </div> <script src="./mvvm.js"></script> <script> //1.myVue中不能在data中新增不存在的屬性,例如,不能在初始化之后還使用myVue.data.name="小王",變成了下面這樣,此時的name沒有經過資料劫持 //2.對于data中屬性值的獲取或者修改都會觸發資料劫持,也就是在初始化的程序中會給的所有屬性添加get/set方法 // 自定義的myVue實體 let myVue = new MyVue({ el: '#app', data: { message: { a: { b: 1 } } } }) </script> </body>
js部分:
function MyVue (options = {}) { //第一步:首先就是得到data物件 this.$options = options; this._data = https://www.cnblogs.com/wyq1995/archive/2020/12/28/this.$options.data; //第二步:資料劫持,將data物件中每一個屬性都設定get/set方法 observe(this._data); //第三步:資料代理,這里就是將_data的物件屬性放到myVue實體中一份,如果修改屬性值實際上修改的還是data中的資料,會觸發資料劫持 for (let key in this._data) { //這里的this代表當前myVue實體物件 Object.defineProperty(this, key, { enumerable: true, get () { return this._data[key]; }, set (newVal) { this._data[key] = newVal; } }) } } //資料劫持操作 function observe (data) { // 如果data不是物件,就結束,不然遞回呼叫會堆疊溢位的 if (typeof data !== 'object') return; return new Observe(data); } function Observe (data) { // 遍歷data所有屬性 for (let key in data) { let val = data[key]; //初始化的時候, data中就有復雜物件的時候,例如data: { message:{a:{b:1}}} ,就需要遞回的遍歷這個物件中每一個屬性都添加get和set方法 observe(val); Object.defineProperty(data, key, { enumerable: true, get () { return val; }, set (newVal) { if (val === newVal) return; val = newVal; //當后續可能因為業務邏輯使得_data.message = {name: "小王"},設定物件型別的屬性值,就需要遞回的給物件中{name: "小王"}的每個屬性也添加get和set方法 //否則name是沒有get/set方法的 observe(val); } }) } }
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/241810.html
標籤:其他
上一篇:去哪里了?幾部關于IT的劇推薦
