搜尋
首頁web前端js教程vue實踐小結之mvvm學習

vue實踐小結之mvvm學習

Mar 12, 2018 pm 04:37 PM
mvvm學習

MVVM是Model-View-ViewModel的簡寫。微軟的WPF帶來了新的技術體驗。本文主要和大家分享vue實作小結之mvvm學習,希望能幫助大家。

1 mvvm 學習

1.1 實作原理

mvvm類別框架的實作原理不複雜,大致如下:

  • ##範本分析得到依賴的屬性

  • 透過某種變動監測手段監測這些依賴的屬性

  • 當屬性變動的時候,觸發對應的directive的處理邏輯即可

實際上,directive的處理邏輯不一定是對view進行操作,例如回報。但是,在mv的思想下,建議對view的操作都集中在directive裡實現

#從最核心上看,mv思想只是一個觀察者模式的具體應用於延展而已

1.2 核心技術點

1.2.1 模板分析

模板分析是比較基礎的,凡是和view相關的基本都會涉及模板,這是原始資料,這裡的關鍵點是模板來源的問題,實際上,它應該可以是任何字串

這裡暗示了框架需要一個模板解析器,不管這個解析器複雜還是簡單,它都處於一個模式:【輸入–> 模板引擎–> 輸出】

於是,mvvm的模板解析器特點如下:

    ##輸入:任何符合規則的字符字串
  • 輸出:需要監聽的data.attr,directive,filter
  • 在設計一個框架的時候,如果想要有更好的可擴展性,則

輸入應該足夠靈活,從來源上來說,模板可以是someDomHere.html(),也可以是動態輸入,那就更有可適用性;從內容上來說,如果引擎可以辨識更高階的語法,那就更有功能性

輸出應該足夠收斂,收斂的意思是有限且規則,像mvvm框架,最後出來的只是directive和filter,具體的處理都集中在這兩個概念中,僅擴展這兩個概念,即可對系統進行擴展

1.2.2 變動監測

在眾多mvvm類框架中,實現變動監測有3種:

    門面方法setter,getter:例如knockout,q。限定可以變動的入口,並且讓入口使用權放給使用者決定。
  1. 利用defineProperty:例如vue,avalon。本質上也是setter,getter,但是沒有把入口使用權放給用戶來決定。
  2. dirty check:例如angular。 angular的研究已經夠多了,這裡也不贅述了。
1

#2

3

##4

#5

6

7

8

9

10

##11

<span class="comment">//方式1 vs. 方式2</span>
<span class="comment">//方式1:</span>
vm.<span class="variable">$set</span>(aaa, <span class="number">1</span>);    <span class="comment">//会触发变动逻辑</span>
vm._data.aaa = <span class="number">2</span>;   <span class="comment">//不会触发变动逻辑,不过这不是框架希望的操作,可以被hack</span>
vm.<span class="variable">$get</span>(aaa);       <span class="comment">//2</span>
<span class="comment">//方式2:</span>
vm.aaa = <span class="number">1</span>;         <span class="comment">//一定会触发变动逻辑</span>
vm._data.aaa = <span class="number">2</span>;   <span class="comment">//也可以找到内部的data进行修改,但是没用</span>
vm.aaa;             <span class="comment">//1</span>


#

1.2.3 小結與延伸

對一類複雜並且常見的問題進行分析,解耦,抽象,在實踐的過程中獲得廣泛的認可,那就形成了一種模式,mvvm也是一種模式,它不一定叫mvvm模式,這也不是筆者能決定的

對於這個模式的核心,筆者理解如下:系統根據配置得到了對某些資料來源的某些處理規則,當資料來源變動時就會引發對應的處理規則。模式的擴展是雙向性,這由系統實作來決定,當符合某些規則的時候,可以對資料來源進行更新。

我們跳脫view的概念禁錮,聯想實現一個監控系統,其實這個模式非常適合用在監控系統上面。

一般的監控系統的處理邏輯是:由收集來源對監控資料進行收集整理,然後儲存到資料庫中,監控系統即時監控資料來源,繪製即時的圖線(回饋),當資料來源當發生了符合某些規則的變動時,就會觸發對應的動作,例如警報。

如何實現這個系統,讓系統有更高的擴充性?參考mvvm模式,可以這樣:

收集系統獨立於監控系統,各不相同,暫且不論。監控系統透過某些設定檔取得需要監控的資料來源與對應的處理邏輯規則,當資料來源變更時觸發對應的處理。

依照mvvm模式,進行一些抽象。

  • 資料來源不一定限定在資料庫中,他可以在任何地方,只需要係統可以透過某些可設定的規則來取得

  • 處理規則進行抽象,讓它更容易被擴展,例如發郵件,發短信,發微信,發qq訊息等等

對應前端的mvvm框架,模板就是配置文件,directive就是處理規則,data對應資料來源。

  • 當系統需要新增一個資料來源的時候,只需要更新設定文件,讓系統讀取即可啟動資料監控

  • 當需要新增一個處理規則的時候,可以透過一個熱插拔的處理規則插件系統,擴展一個新的處理規則,再更新配置文件,系統即可接受新的處理規則

2 vue實作

vue介紹就不用了,太多資源了。這裡講述vue實踐過程中的一些收穫

2.1 組織結構

#1

2

3

4

5

6

7

8

9

10

11

12

13
#14

##+ src

     + -- common

           +-- vue

                

#                +-- filters

              -- vue.js

                +-- vue.ext.js

     +-- #  

                 +-- index.js

                 +-- vue.ext.js

                 +-- xxx.mixin.js

2.2 Vue扩展

vue的扩展非常方便,与vue相关的资源都放置在src/common/vue/下面,比如coms(组件),directive,filter

src/common/vue/vue.ext.js是对vue进行全局公共的扩展,对于所有页面共有的扩展放在这个文件下面,内容如下:

可以看到,扩展vue库本身有4个扩展点:

  • 扩展Vue库的全局方法/属性,方式:Vue.xxx = …

  • 扩展Vue实例的方法/属性,方式:Vue.prototype = …

  • 扩展directive,方式:Vue.directive(‘directiveName’, options);

  • 扩展filter,方式:Vue.filter(‘filterName’, function(){});

对于页面单独需要的扩展,集中在src/pages/pageName/vue.ext.js里面,形式与全局的vue.ext.js一样

在实例化Vue的过程中也有许多可以扩展与优化的地方,在实践过程中只是应用了mixin功能,其他的可以慢慢深入

mixin的作用是在实例化Vue的时候混入一些功能,它可以混入许多特性,格式与实例化Vue时用到的option格式一样,比如index页面的mixin.js的内容如下:

这个mixin混入了两个方法,多个Vue实例共享的options可以放置到mixin中,从而避免了代码重,比如在实例化Vue的时候这样使用mixin:

可以看到mixin是个数组,因此可以同时使用多个mixin

实际上这里的mixin主要不是为了避免代码重复(实践的时候只是这样用),mixin是一种模式,一个mixin内聚了实现一项功能的方法/属性集合,在定义/生成实例的时候,通过混入mixin就可以让该实例拥有某项功能,归根结底是组合vs继承问题的产物

2.3 vue组件插入问题

2.3.1 首屏

对于首屏的vue组件,直接把模板放在主页面中即可,初始化的时候只需要把el参数传入,Vue就会用el的html作为模板来初始化Vue实例:

这里需要注意的是在模板中不能使用{{}},否则在还没初始化之前,页面会显示奇怪的东西,比如:

1

2

3

4

5

6

7

<p>hello, {{name}}</p>      <!--初始化前,页面会直接展示hello, {{name}}-->
<img src=<span class="s
tring">"{{imgSrc}}"</span> />    <!--初始化前,会报错,can not find http:<span class="comment">//xxx.com/{{imgSrc}}--></span>
 
<!--正确的写法:-->
<p v-text=<span class="string">"&#39;hello, &#39;+name"</span>>hello</p>
<img  v-attr=<span class="string" alt="vue實踐小結之mvvm學習" >"src: imgSrc"</span> />

 

{{}} 只是一个语法糖,不建议使用

2.3.2 非首屏

对于非首屏的组件,使用vue的方式和原始方式差不多,先生成节点,然后append,譬如:

el参数可以接收query string,也可以直接是一个dom节点,如果是dom节点则直接编译dom的内容。如果dom节点不在文档树中,则利用vueObj.$appendTo方法将vue实例的根节点插入到文档树中

上面这种方式是在页面中没有组件的【坑】的情况下使用的,如果页面为组件留了【坑】,比如:

1

2

class="hotRecord" id="js-hotRecord">

 

那么,我们可以这样初始化vue实例:

利用template参数传入模板,并指定el,那么vue实例在初始化之后就会自动把内容插入到el中

通过vue实现组件的主要核心也就这些,更方便的组件写法也只是对这些进行封装

2.4 自定义 directive

在vue中自定义directive是非常简单明了的,要自定义一个directive,可以注册3个钩子函数:

  • bind:仅调用一次,当指令第一次绑定元素的时候。

  • update:第一次调用是在 bind之后,用的是初始值;以后每当绑定的值发生变化就会被调用,新值与旧值作为参数。

  • unbind:仅调用一次,当指令解绑元素的时候。

下面简单介绍一个自定义directive——lazyload:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

<span class="keyword">function</span> addSrc(){}
<span class="keyword">function</span> load(){}
 
module.exports = {
    bind: <span class="keyword">function</span>() {
        <span class="keyword">if</span> (!hasBind) { <span class="comment">//全局事件只绑定一次</span>
            hasBind = <span class="keyword">true</span>;
            (document.querySelector(<span class="string">&#39;.z-scroller&#39;</span>) || window).addEventListener(<span class="string">&#39;scroll&#39;</span>, T.debounce(load, <span class="number">100</span>), <span class="keyword">false</span>);
        }
        <span class="comment">//这里也可以使用data属性来获取</span>
        <span class="keyword">var</span> defaultSrc = <span class="keyword">this</span>.el.getAttribute(<span class="string">&#39;data-defaultsrc&#39;</span>);
        <span class="keyword">if</span> (defaultSrc) addSrc(<span class="keyword">this</span>.el, defaultSrc);    <span class="comment">//先使用默认图片</span>
    },
    update: <span class="keyword">function</span>(src) {
        <span class="comment">//directive初始化时,会调用一次bind和update,bind没有传入src,只有update才会传入src</span>
        <span class="comment">//因此只能在update这里拿到需要lazyload的src</span>
        <span class="comment">//lazyload不允许修改src,这里限制只会执行一次update,防止src被修改造成的影响</span>
        <span class="comment">//注:接受src改变可以实现,只是需要一些复杂的处理,这里为了简单起见不让src改变</span>
        <span class="keyword">if</span> (<span class="keyword">this</span>.init) <span class="keyword">return</span>;  
        <span class="keyword">this</span>.init = <span class="keyword">true</span>;
 
        <span class="comment">//如果图片已经加载了,就不需要注册了,这里也可以使用data属性来区分</span>
        <span class="keyword">var</span> isLoad = parseInt(<span class="keyword">this</span>.el.getAttribute(<span class="string">&#39;data-isload&#39;</span>));
        <span class="keyword">if</span> (isLoad) <span class="keyword">return</span>;
 
        <span class="comment">//注册需要lazyload的图片</span>
        <span class="keyword">list</span>[index++] = <span class="keyword">this</span>;
        <span class="keyword">list</span>[index++] = src;
    }
    <span class="comment">//这里有一个最大的问题:由于有local的存在,会创建两个一模一样的lazyload directive</span>
    <span class="comment">//按理说应该定义一个unbind,但是在unbind中找到并除掉local创建出来的lazyload directive会比较麻烦</span>
    <span class="comment">//因此在load函数里面做了一个处理:如果发现需要lazyload的节点不在文档树中,则剔除掉这个lazyload</span>
    <span class="comment">//通过这个直接省掉了unbind函数</span>
};

 

自訂filter也很簡單,只是定義一個處理函數而已,這裡就不多介紹了

2.5 實踐過程中的痛點與小技巧

2.5.1 沒有事件代理

用習慣了事件代理,突然沒有了會有點不習慣,但是回頭想想,事件代理真的很重要嗎?還是說我們只是習慣了事件代理而已?

透過vue註冊相同的事件並不費事。另一個問題,只要事件不多,大約不超過50,100,也不至於耗掉很大的內存,因此有時候還真不需要事件代理。如果真的需要,也只是實作一個contain方法而已

2.5.2 沒有if-else的奇怪

最初看到下面的程式碼真的會覺得很奇怪

1

2

3

#

if="hasTitle">xxx

if="!hasTitle">xxx

 

#2.5.3 單值

雖然vue有語法解析器,可以在directive的值中使用表達式,但是當出現一個複雜的表達式時,會污染模板,讓程式碼可讀性變得很差,又或者,表達式完成不了這個任務的時候。

因此,在mvvm實踐的過程中,深深發現,利用單值(最多只用一個?:表達式)來寫模板會讓程式碼變得很清晰,更加可讀,增加程式碼的可維護性,而且這也更符合mvvm的核心思想:f(state) = view

有些函式庫連語法解析器都沒有,例如q,但也能很好的工作。

那麼,複雜的操作放在哪裡呢?

  • 對於不會變的值來說,也就是常數,要在初始化之前完成處理

  • #對於會變的值來說,把複雜的操作放在filter裡面,在filter裡面不僅可以進行複雜處理,甚至可以同時應用到其他字段,這不完全等同於computed attribute

2.5.4 替代$(document).on

用jquery/zepto的時候,習慣了用$(document).on來充當一個全局的事件代理,在使用vue的時候,需要拋棄zepto,因此需要解決這個問題

因為vue實例本身就有event功能,因此這裡解決的辦法是建立一個全域的空vue對象,把它當作全域的事件代理:

##1

2

3

4

#5

6

7

8

9

//common/vue/vue.ext.js 回頭看前面對該文件的介紹可以看到這句話

Vue.noopVue = new Vue({});

############################################################################################################################################################################### ## ######//a.js######Vue.noopVue.$on('someEvent', function() {});####### ######//b.js######Vue.noopVue.$emit> ;('someEvent', [opts]);###############


3 總結

雖然,最後在付出產出比權衡中放棄了對現有專案的vue改造,但這並不妨礙我們研究mvvm類別框架

mvvm模式還是值得我們去深入學習的,而在實踐中,我們也能學習到許多

用一種不一樣的思想和思維去開發的體驗也會令我們在看待問題,處理問題的道路上有所收穫。

相關推薦:

Angularjs如何實作mvvm式選項卡?案例+程式碼

js實作一個簡單的MVVM框架範例分享

什麼是MVVM架構和資料綁定?

以上是vue實踐小結之mvvm學習的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
幕後:什麼語言能力JavaScript?幕後:什麼語言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在瀏覽器和Node.js環境中運行,依賴JavaScript引擎解析和執行代碼。 1)解析階段生成抽象語法樹(AST);2)編譯階段將AST轉換為字節碼或機器碼;3)執行階段執行編譯後的代碼。

Python和JavaScript的未來:趨勢和預測Python和JavaScript的未來:趨勢和預測Apr 27, 2025 am 12:21 AM

Python和JavaScript的未來趨勢包括:1.Python將鞏固在科學計算和AI領域的地位,2.JavaScript將推動Web技術發展,3.跨平台開發將成為熱門,4.性能優化將是重點。兩者都將繼續在各自領域擴展應用場景,並在性能上有更多突破。

Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器