很easy的js雙向繫結架構(二):控制器繼承

來源:互聯網
上載者:User

標籤:cut   alt   pen   class   document   input   函數定義   data   r.js   

初衷

上一篇已經實現了資料的雙向繫結,但model的控制範圍是整個文檔。在實際project中必需要有作用範圍,以便做ui模組的拆分。
這一篇,我們希望實現像angularjs一樣的控制器繼承:
1. 父controller的Model能夠在子controller裡被訪問到
2. 子controller的model不影響父controller
3. controller繼承關係在html中指定。而不是js中指定

目標

html裡,用isi-controller屬性去聲明控制器:

<body>    <div isi-controller="ParentController">        <input data-bind="name">        <div isi-controller="SubController">            <input data-bind="name">        </div>    </div></body

希望上面的input name 改了。以下的會跟著變,而以下的變了,上面的不變。


js裡,用和上面isi-controller屬性值同名的函數定義控制器:

function ParentController() {    var model = new Model();    model.set(‘name‘, ‘parent‘);}function ParentController() {    var model = new Model();    model.set(‘name‘, ‘sub‘);}

對使用者來說,僅僅要寫這些。就完事兒了。

實現版本號碼1

這個版本號碼採用最簡單直觀的思路:架構去找$(‘[isi-controller]’)的元素。然後給這些元素分別去綁定監聽器、運行控制器函數
代碼先列了:
index.html:

<html>  <head>    <title>simple MVVM</title>    <script src="js/ParentController.js"></script>    <script src="js/SubController.js"></script>    <script src="js/frame_v2.js"></script>  </head>  <body isi-controller="ParentController">    <input type="text" data-bind="name">    <div isi-controller="SubController">      <input type="text" data-bind="name">    </div>  </body></html>

ParentController.js:

function ParentController() {    var model = new Model();    model.set(‘name‘, ‘parent‘);}

SubController.js:

function SubController() {    var model = new Model();    model.set(‘name‘,‘sub‘);}

frame_v2.js: (對比上一篇,主要修改在綁監聽器和new Model的自己主動化)

var pubsub = ... //見上一篇var Model = ...  //見上一篇// listener capture view changes --> publish model.change eventvar changeHandler = function(event) {    var target = event.target,        propName = target.getAttribute(‘data-bind‘);    if( propName && propName !== ‘‘ ) {        pubsub.pub(‘model.change‘, propName, target.value);    }    event.stopPropagation();}/*----------- Init --------------*/window.onload = function() {    /* first step:     * find controllers‘ dom     */    var controllerRanges = document.querySelectorAll(‘[isi-controller]‘);    /* second step:     * bind listeners for each controllers‘ range,     * view.change event --> change each controllers‘ range     */    for(var i=0, len=controllerRanges.length; i<len; i++) {        controllerRanges[i].addEventListener(‘change‘, changeHandler, false);        // view.change event --> change view        (function(index){            pubsub.sub(‘view.change‘, function(propName, newVal) {                var elements = controllerRanges[index].querySelectorAll(‘[data-bind=‘ + propName +‘]‘),                    tagName;                for(var i=0,l=elements.length; i<l; i++) {                    tagName = elements[i].tagName.toLowerCase();                    if(tagName===‘input‘ || tagName===‘textarea‘ || tagName===‘select‘) {                        elements[i].value = newVal;                    } else {                        elements[i].innerHTML = newVal;                    }                }            });        })(i);    }     /* third step:     * execute each controller function     */    for(var i=0, len=controllerRanges.length; i<len; i++) {        var controllerName = controllerRanges[i].getAttribute(‘isi-controller‘);        eval(controllerName+‘()‘);    }}

看看效果:

悲劇了。

沒有實現第二個初衷:子控制器不影響父控制器。
這個問題該怎樣解決呢?

版本號碼二,子不影響父

細緻看代碼,之所以會出現故障,是由於view.change通道的作用範圍是有問題的。無論哪個model發出的view.change事件,兩個控制器的view都會改變。
所以,我們給公布view.change事件的時候,多公布一個控制器名。好讓接收view.change的時候知道應不應該修改html:

var Model = function(controllerName) {    var model = {        controllerName:controllerName,        props: {},        set: function(propName, value) {            this.props[propName] = value;            pubsub.pub(‘view.change‘, propName, value, this.controllerName); //就是這裡!

} }

控制器裡new Model的時候注意把controller的名字初始化進去:
ParentController.js:

function ParentController() {    var model = new Model(‘ParentController‘);    model.set(‘name‘, ‘parent‘);}

最後接收view.change通道訊息的時候,推斷下controllerName:

pubsub.sub(‘view.change‘, function(propName, newVal, controllerName) {                ....                thisControllerName = controllerRanges[index].getAttribute(‘isi-controller‘),                if(thisControllerName !== controllerName)                    return;                ....}

當然。監聽器公布model.change的時候也是一樣。要把控制器名稱公布出去。代碼就不貼了。


再看看效果:

妥了

全部代碼:
github/victorisildur

很easy的js雙向繫結架構(二):控制器繼承

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.