TWaver - 專注UI技術(shù)

          http://twaver.servasoft.com/
          posts - 171, comments - 191, trackbacks - 0, articles - 2
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          接上一回TWaver HTML5 + Node.js + express + socket.io + redis(四), 這一篇您將了解到

          1. 如何保存更改后的拓?fù)鋽?shù)據(jù) (包括新增的, 修改的, 刪除的)
          2. 如何廣播更改后的拓?fù)鋽?shù)據(jù) (僅僅廣播更改的數(shù)據(jù))

          下面是mac和iphone上的效果圖, mac或iphone上的修改都將及時(shí)互相同步:



          一. 先來看后臺(tái)如何實(shí)現(xiàn)
          后臺(tái)需要做兩件事情: 保存修改以及廣播修改; 其中修改又分為是新增, 修改, 還是刪除. 保存修改很容易, 無非就是對(duì)數(shù)據(jù)庫的增刪改, 廣播數(shù)據(jù)也很容易, 調(diào)用Socket.emit之前, 先設(shè)置廣播標(biāo)記就ok了: Socket.broadcast.emit. 而且這個(gè)廣播只會(huì)通知其他客戶端, 發(fā)送這個(gè)廣播的客戶端不會(huì)收到廣播, 這正好是我們需要的, 所以后臺(tái)代碼就好寫了:
          添加保存數(shù)據(jù)的socket.io監(jiān)聽, 里面保存數(shù)據(jù)后, 廣播之:
           1     //保存數(shù)據(jù)
           2     client.on('saveData', function (datas) {
           3         if (!datas) {
           4             return;
           5         }
           6         //保存新增網(wǎng)元
           7         save(datas.add);
           8         //保存修改網(wǎng)元
           9         save(datas.change);
          10         //刪除網(wǎng)元
          11         remove(datas.remove);
          12         //廣播更新
          13         client.broadcast.emit('broadcast', datas);
          14     });
          保存數(shù)據(jù)的函數(shù)如下:
           1 //保存網(wǎng)元
           2 function save (datas) {
           3     if(!datas){
           4         return;
           5     }
           6     var elements = {};
           7     for (var i=0,n=datas.length,data; i<n; i++) {
           8         data = datas[i];
           9         elements[data.id] = JSON.stringify(data);
          10     }
          11     redis.hmset('datas', elements);
          12 };
          13 
          14 //刪除網(wǎng)元
          15 function remove (datas) {
          16     if(!datas){
          17         return;
          18     }
          19     var ids = [];
          20     for (var i=0,n=datas.length; i<n; i++) {
          21         ids.push(datas[i].id);
          22     }
          23     redis.hdel('datas', ids);
          24 };

          二. 前臺(tái)實(shí)現(xiàn)
          分兩步: 監(jiān)聽數(shù)據(jù)的增刪改并自動(dòng)保存, 響應(yīng)廣播更新
          1. 監(jiān)聽數(shù)據(jù)的增刪改并自動(dòng)保存
          TWaver HTML5的數(shù)據(jù)模型提供了各種監(jiān)聽器, 以便在數(shù)據(jù)更改后做響應(yīng)處理. 其中:
          DataBox.addDataPropertyChangeListener用于監(jiān)聽數(shù)據(jù)容器里數(shù)據(jù)的屬性變化, 也即對(duì)數(shù)據(jù)的修改, 其回調(diào)函數(shù)的參數(shù)包含屬性: property(發(fā)生變化的屬性), oldValue(舊值), newValue(新值), source(發(fā)生變化的數(shù)據(jù))
          DataBox.addDataBoxChangeListener用于監(jiān)聽數(shù)據(jù)容器的變化, 也即數(shù)據(jù)的添加, 刪除以及清空, 其回調(diào)函數(shù)的參數(shù)包含屬性: kind(容器變化類型, 可選值為add(新增), remove(刪除), clear(清空)), data(新增或刪除的數(shù)據(jù)), datas(清空的數(shù)據(jù)集合)
          這里實(shí)現(xiàn)保存數(shù)據(jù)的思路是:
          i> 如果有網(wǎng)元被修改, 則將被修改的網(wǎng)元加上change標(biāo)記, 其中判斷isChanging標(biāo)志很重要, 因?yàn)樾枰么藰?biāo)志區(qū)分是用戶更改還是響應(yīng)廣播更新(也即程序更新)
           1     //添加網(wǎng)元屬性更改監(jiān)聽器
           2     box.addDataPropertyChangeListener(function (e) {
           3         //如果正在響應(yīng)廣播更新,則返回
           4         if (isChanging) {
           5             return;
           6         }
           7         //如果屬性為add, change 則返回
           8         if (e.property === 'C:add' || e.property === 'C:change') {
           9             return;
          10         }
          11         //設(shè)置保存數(shù)據(jù)標(biāo)記
          12         needSave = true;
          13         //將有屬性更改的節(jié)點(diǎn)置上change標(biāo)記
          14         e.source.setClient('change', true);
          15     });
          ii> 如果有新增網(wǎng)元, 則將新增網(wǎng)元加上add標(biāo)記, 如果有網(wǎng)元被刪除, 則存入map中
           1     //添加數(shù)據(jù)容器更改監(jiān)聽器
           2     box.addDataBoxChangeListener( function (e) {
           3         //如果正在響應(yīng)廣播更新,則返回
           4         if (isChanging) {
           5             return;
           6         }
           7         //設(shè)置保存數(shù)據(jù)標(biāo)記
           8         needSave = true;
           9         if (e.kind === 'add') {
          10             //將新增的節(jié)點(diǎn)置上add標(biāo)記
          11             e.data.setClient('add', true);
          12         } else if (e.kind === 'remove') {
          13             //如果網(wǎng)元沒有新增標(biāo)記, 則存儲(chǔ)到被刪除網(wǎng)元列表中
          14             if (!e.data.getClient('add')) {
          15                 //存儲(chǔ)被刪除網(wǎng)元
          16                 removedElements[e.data.getId()] = e.data;
          17             }
          18         }
          19     });

          iii> 啟動(dòng)定時(shí)器, 保存更改
          定時(shí)器代碼如下:
           1 //自動(dòng)保存
           2 function setAutoSave (value) {
           3     if(value){
           4         //定時(shí)器,每隔1秒鐘保存修改
           5         timer = setInterval(function(){
           6             save();
           7         }, 1000);
           8     }else{
           9         window.clearTimeout(timer);
          10     }
          11 }
          保存數(shù)據(jù)代碼如下, 需要注意的是, 得到要添加和被修改的網(wǎng)元后, 需要將其add和change標(biāo)記置為false, 以避免重復(fù)保存:
           1 //保存數(shù)據(jù)
           2 function save () {
           3     //如果無數(shù)據(jù)添加、修改、刪除,則直接返回
           4     if(!needSave){
           5         return;
           6     }
           7     
           8     var add = [];
           9     var change = [];
          10     var remove = [];
          11     isChanging = true;
          12     box.forEach(function(data){
          13         //新增的網(wǎng)元
          14         if(data.getClient('add')){
          15             add.push(toData(data));
          16         }
          17         //修改的網(wǎng)元
          18         else if(data.getClient('change')){
          19             change.push(toData(data));
          20         }
          21         //清除網(wǎng)元新增和修改標(biāo)記
          22         data.setClient('add', false);
          23         data.setClient('change', false);
          24     });
          25     isChanging = false;
          26     //刪除的網(wǎng)元
          27     for(var id in removedElements){
          28         remove.push(toData(removedElements[id]));
          29     }
          30     
          31     if(add.length == 0 && change.length == 0 && remove.length == 0){
          32         return;
          33     }
          34     
          35     //初始化待刪除數(shù)據(jù)
          36     removedElements = {};
          37     //還原保存數(shù)據(jù)標(biāo)記
          38     needSave = false;
          39     //構(gòu)造更新數(shù)據(jù)
          40     var datas = {};
          41     if(add.length != 0){
          42         datas.add = add;
          43     }
          44     if(remove.length != 0){
          45         datas.remove = remove;
          46     }
          47     if(change.length != 0){
          48         datas.change = change;
          49     }
          50     socket.emit('saveData', datas);
          51 }
          從網(wǎng)元獲取要持久化的數(shù)據(jù)代碼如下:
           1 //從網(wǎng)元獲取持久化數(shù)據(jù)
           2 function toData (element) {
           3     if(element instanceof twaver.Node) {
           4         return {
           5             id: element.getId(),
           6             name: element.getName(),
           7             location: element.getLocation()
           8         };
           9     } else {
          10         return {
          11             id: element.getId(),
          12             name: element.getName(),
          13             from: element.getFromNode() ? element.getFromNode().getId() : null,
          14             to: element.getToNode() ? element.getToNode().getId() : null
          15         };
          16     }
          17 }

          2. 響應(yīng)廣播更新
          分為新增, 刪除以及修改三種情況, 其中很重要的是在做這些事情之前先設(shè)置isChanging為true, 以防止重復(fù)廣播更新
           1 //響應(yīng)廣播更新
           2 function onBroadcast (data) {
           3     if (!data) {
           4         return;
           5     }
           6     //設(shè)置響應(yīng)廣播更新標(biāo)記,防止重復(fù)更新
           7     isChanging = true;
           8     var i, c, add=data.add, change=data.change, remove=data.remove;
           9     //添加節(jié)點(diǎn)
          10     if (add) {
          11         for (i=0,c=add.length; i<c; i++) {
          12             if (add[i].from) {
          13                 addLink(add[i]);
          14             } else {
          15                 addNode(add[i]);
          16             }
          17         }
          18     }
          19     //修改節(jié)點(diǎn)
          20     if (change) {
          21         for (i=0,c=change.length; i<c; i++) {
          22             changeData(change[i]);
          23         }
          24     }
          25     //刪除節(jié)點(diǎn)
          26     if (remove) {
          27         for (i=0,c=remove.length; i<c; i++) {
          28             removeData(remove[i]);
          29         }
          30     }
          31     //還原更新廣播數(shù)據(jù)
          32     isChanging = false;
          33 }
          增刪改網(wǎng)元代碼如下:
           1 //添加節(jié)點(diǎn)
           2 function addNode (data) {
           3     //構(gòu)造節(jié)點(diǎn)
           4     var node = new twaver.Node(data);
           5     //添加節(jié)點(diǎn)
           6     box.add(node);
           7 }
           8 
           9 //添加節(jié)點(diǎn)
          10 function addLink (data) {
          11     //查找from節(jié)點(diǎn)
          12     var from = box.getDataById(data.from);
          13     //查找to節(jié)點(diǎn)
          14     var to = box.getDataById(data.to);
          15     //構(gòu)造連線
          16     var link = new twaver.Link({id: data.id, name: data.name}, from, to);
          17     //添加連線
          18     box.add(link);
          19 }
          20 
          21 //修改網(wǎng)元
          22 function changeData (data) {
          23     var element = box.getDataById(data.id);
          24     //修改節(jié)點(diǎn)
          25     if (element instanceof twaver.Node) {
          26         element.setLocation(data.location.x, data.location.y);
          27         element.setName(data.name);
          28     }
          29     //修改連線
          30     else if (element instanceof twaver.Link) {
          31         element.setName(data.name);
          32         element.setFromNode(box.getDataById(data.from));
          33         element.setToNode(box.getDataById(data.to));
          34     }
          35     //網(wǎng)元被刪除
          36     else {
          37         //網(wǎng)元被刪除, 無需修改
          38     }
          39 }
          40 
          41 //刪除網(wǎng)元
          42 function removeData (data) {
          43     box.removeById(data.id);
          44 }

          最后, 附上本文的完整demo:TWaverHTML5Demo

           


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 穆棱市| 金塔县| 蒙自县| 东阿县| 梧州市| 团风县| 奉化市| 敖汉旗| 五大连池市| 中牟县| 晋中市| 贵阳市| 西昌市| 大英县| 石家庄市| 泰安市| 贵港市| 冷水江市| 石阡县| 神木县| 纳雍县| 四川省| 拉萨市| 甘南县| 吴桥县| 吐鲁番市| 唐山市| 志丹县| 柳江县| 新余市| 临潭县| 舞钢市| 喀喇| 安义县| 工布江达县| 贞丰县| 寻甸| 浦江县| 全州县| 江油市| 施秉县|