從jQuery到Vue你可能還錯過了一個Backbone

標題有點嚇唬人,不過我希望我能把我想說的說明白。

事情是這個樣子的,昨天的live里我本來應該把這篇文章說出來的,但是因為時間關係就沒有最後完成,開始我說過我會用原生代碼,三種實現方式來做todomvc的實現,我周末其實也寫了,但是可惜的是從想開始做到準備時間我只有一個周末,一個周末的時間把一個backbone和一個簡版的vue就直接寫出來講明白,可能我功力還不太夠。

所以後來我換了一個思路,首先先看下面3個鏈接:

todomvc/examples/jquery at gh-pages · tastejs/todomvc · GitHub

todomvc/examples/backbone at gh-pages · tastejs/todomvc · GitHub

todomvc/examples/vue at gh-pages · tastejs/todomvc · GitHub

這是官方的todomvc的三種實現,其實examples里還有更多框架的todomvc版本實現,大家可以有時間都看看,不少框架我也是見都沒見過,選了這3個最有代表性的來說吧,也正好符合了我一開始說要講的東西的初衷。

還是那句話,這篇文章我想說明的是給一些新人,我們在享受mvvm帶來的便利的同時,但是最好也要搞明白為什麼這樣做,為什麼以前的做法不好,以前是如何做的?

這篇文章也暫時不會講解到底是如何實現一個router,一個jquery,一個backbone,甚至一個vue,我們在享受他們的便利的同時,我的目的是告訴大家,業務代碼是如何一步一步進化的。

正文開始,我們先從jquery的這部分說起,我通過截圖加語言的方式來說,大家也可以用電腦直接打開源碼來自己查看,先來個最直觀的概念,有些人可能沒寫過todoapp,我先來個圖大家看下基本需求。

這是一個標準的todolist的功能,簡單劃分3個區域,當然列表區域還包含編輯,刪除,更改狀態的功能。下面3個按鈕是過濾todo狀態和切換路由的。最後這些數據保存完畢後,都是自動存在本地的localstorage里的。

下面看一下他的html結構,我就說列表的渲染部分,其他部分大家可以自己去看代碼,因為這部分平時業務用的最多,就是取數據插數據,展示數據。

handlebars裡面的這裡等於是直接each this的意思 編譯的時候傳進來的是一個 數組裡面的item是object,每個object都有id,completed,title這幾個屬性,然後渲染出最終的字元串。

這裡的寫法其實和大部分的新手同學寫的已經不一樣了,他把對應的一些屬性和相關的dom操作,還有事件綁定都放到了對應的函數里,並且使用了一個App來掛載這些屬性和方法,說白了就是一個js版本的單例模式,但是本質上還是對dom進行的手工操作,圖裡的1-6步簡單說明了這個list列表的渲染過程,以及單例裡面的方法是如何直接映射到了dom的event上的,如第四步。

總結一下流程基本上是字元串模板編譯數據,然後手動操作dom更新和事件綁定,使用路由控制過濾數據,再進行render進行視圖切換。

基本上一個todomvc的基本實現思路就是這樣,其中就不一一去細說每個功能實現了。下面咱們看進化版本的,backbone是如何來實現同樣的功能的。

前端模板的結構和jq的基本一樣,只不過換了個模板實現,之前是handlerbas,backbone自帶一個template的方法,也就是underscore里的那個方法。

入口部分app是掛在全局window上的,AppView是backbone的view類的一個子類。這裡就升級了,高大上了,有點面向對象的意思了。

這裡分了6步來解釋AppView的一部分邏輯結構,可能要理解這部分知識你要先理解事件通知或者廣播,也叫觀察者模式的用法了,尤其是第6步。

這次我們觀察在initialize也就是jq那個版本的init方法里,同樣顯示拿dom節點,然後監聽了app.todos的一系列廣播,比如todos的增加,重置,屬性修改,過濾行為等,這裡的意思就是通過todos數據的變化來觸發對應的業務邏輯。

然後我們看下面的render方法,同樣在all這個過濾器行為廣播通知時,render函數觸發,render函數對todos的數據做了一些渲染工作,仍然是直接操作的dom元素。

然後我們來看另外一個view,就是todoview,他代表了每一個todolist里的一項,相比之前的jq版本,我們有了根節點的概念,我們有了自動的事件綁定,如events那個對象的定義。這裡的view類對之前jq的那些bindEvent方法又做了一層抽象,最後看initialize里,每一個todo的view對應的model,就是todos里的一個小項,然後每當一個小項有了對應的變化時,如改變行為,刪除了,或者狀態變化了,對應觸發todoview的展示部分業務邏輯,比如render這一類方法。

然後我們看appView和todoView是如何做關聯的,我們在業務函數addOne中是這樣寫的:

通過實例化一個TodoView,然後傳入這個新todo的model,最後再調用這個TodoView的render方法,再append到list元素里,實現了2個視圖的關聯。

再往下我們看一下這個model也就是mvc中的m是如何在backbone中使用的:

在全局的app上掛載了一個backbone的collection集合的實例,這個實例中model參數配置了每一個子項的數據結構,存儲形式和相關過濾方法。

再往下追我們看每一個todo的小項是如何定義的:

Todo是一個繼承於backbone model類的子類,掛載到了app上,然後defaults描述了每一個項的屬性值,然後定義了一個更改屬性值方法的toggle函數。當然backbone的model類自帶了一些方法,比如每個欄位有了更改,刪除操作等都會通過廣播的形式傳遞出去,你需要用就拿去監控,比如下面這樣:

上面應該已經解釋了~

然後我們看下路由部分是怎麼定義的:

這裡是2個過濾器的路由,比如說我點active或者completed的時候會進行list的顯示更新,原理肯定是通過監聽onhashchange事件,這裡backbone也有對應的抽象類Router。

1,2,3說的很清楚了,每當變化過濾器時,也就是說controller變化時,設置一個全局的TodoFIlter為之後的切換class做準備,然後出發一個todos集合的filter廣播。

監聽filter或者單個item的completed的屬性變化對應了2個函數,filterOne和All,下面繼續跟蹤一下吧:

All是對One的一個each操作,對應都是去觸發了一個單項todo模型的visible廣播,這個廣播幹了什麼呢?其實就是告訴todo的model,我的狀態發生了變化。

監聽了model的visible廣播,對應走到了toggleVisible的方法。

ok,狀態發生變化了,我們就對每一個item的視圖做隱藏或者顯示操作,this.$el指向的正是list中的每一個item的dom節點!

這樣基本就搞清楚了,backbone的路由切換時是如何控制的list的切換了。

從backbone的這個todomvc來看,他對業務代碼的各種行為事件,生命周期,業務方法,業務模塊,數據集合和數據項都進行了非常細粒度的抽象封裝。

這算是從jq時代進步到前端mvc的一個跨越。backbone這個mvc框架也是目前市面上做mvc前端解耦非常流行的一個框架,那麼下一個進化是什麼樣的呢?我們看看vue的todomvc是如何實現的?

依然從模板入手:

可以看出來,對比之前backbone和jq的版本,大量的事件和業務方法的集成,數據模型的操作和對dom的值的獲取設置,都直接展示到了模板里,沒有了backbone的events對象使用也沒有了jq的bindEvent函數這種東西什麼事了,包括list的渲染也是直接對filterdTodos這個數據的遍歷。

我們再看js部分:

數據部分,定義了fetch和save方法,都是操作的localstorage。

這部分定義了3個過濾器,拿全部的,已完成的,沒完成的,從一個數組列表裡進行過濾,通過參數傳入。

看一下vue的實例是如何配置的,el也是標記根節點,data就是所有的數據,這裡已經沒有backbone的什麼model和collection。然後watch是對todos這個數組裡面的每一項都進行監聽,如果有變化了就調用handler。

這一部分定義了需要使用到的計算屬性,比如fileredTodos,整個列表一直都是根據這個屬性來進行渲染的,這個filteredtodos通過對應的過濾狀態加過濾器生成的todos,remaining是拿已經完成的todos的長度,allDone是獲取是否全部完成,set方法是設置成全完成,或者不完成,get是拿是否全部完成的狀態。

然後主要業務邏輯部分就沒有了,是不是非常的牛逼?業務方法我這裡不概述了。js部分除了定義業務的js方法和對屬性定義,計算屬性定義後,直接在view層中就可以實現自動更新了,沒有了之前的render方法,因為都是自動render的,vue屬性上的data上的任何屬性值在業務方法中做了修改,那麼視圖就會自動變,視圖中設置的model,如果用戶進行了操作,對應的js中的的屬性也就立刻變化了,再觸發對應的變化事件。

對的,mvvm的世界就是這麼方便,這也是目前來看大家都認可的一種簡化開發的方式了。最後我們看一下路由部分:

每當visibility屬性變化了,他對應的計算屬性filteredtodo也會對應的進行變化,那麼視圖也就跟著一起變化了。

好了,基本的一個進化流程就是這樣子,從jquery到backbone到vue,為什麼我們要一步一步的升級換代,我相信已經基本講清楚了,大家也可以自己對照著源碼再仔細去研究一下,我相信對你的業務代碼的組織無論你處在哪個階段都能有一個新的認識!

感謝閱讀!

最後昨天很多人私信問我模塊開發和lithe原理解析的ppt在哪,我這裡統一發一下:

slideshare.net/xiaojueq

slideshare.net/xiaojueq

推薦閱讀:

「每日一題」MVC 是什麼?(續1)
MVC系列——一個異常消息傳遞引發的思考
Python編程(b三):Python之MVC
MVC 模式的原理,它在 Android 中是如何運用的?
zencart 這個國外商城 CMS 源碼寫得怎樣?

TAG:前端开发 | MVC | MVVM |