javascript - 我寫的這段把物件資料變成DOM節點的程式碼該怎麼優化?
三叔
三叔 2017-06-12 09:28:43
0
3
927

簡單介紹下想法:
ajax到對象,然後從子到父依序建立對象,設定樣式,新增層級。
然後程式碼長這樣:

function Activity(obj) {
  var activityContent = document.createElement('a');
  activityContent.innerHTML = obj.post.c;
  activityContent.className = 'activity-content';
  activityContent.style.overflow = 'hidden';
  activityContent.href = '/t/'+obj.tid+'#'+obj.pid;
  var activityTitleText = document.createElement('span');
  activityTitleText.innerHTML = obj.oc.t;
  activityTitleText.style.overflow = 'hidden';
  var activityTitle = document.createElement('p');
  activityTitle.className = 'activity-title';
  var activityTitleA = document.createElement('a');
  activityTitleA.appendChild(activityTitleText);
  activityTitleA.href = '/t/'+obj.tid;
  var activityInfo = document.createElement('span');
  activityInfo.className = 'activity-info';
  if(obj.forum) {
    var color = obj.forum.color || 'orange';
    var forum = document.createElement('a');
    forum.href= '/f/'+obj.fid;
    var forumText = document.createElement('span');
    forumText.className = 'activity-title-forum';
    forumText.style.backgroundColor = color;
    forumText.innerHTML = ' '+obj.forum.abbr+' ';
    forum.appendChild(forumText);
    activityTitle.appendChild(forum);
  }
  if(obj.toMyForum) {
    var color = obj.toMyForum.color || 'orange';
    var toMyForum = document.createElement('a');
    toMyForum.href= '/m/'+obj.toMyForum._key;
    var toMyForumText = document.createElement('span');
    toMyForumText.className = 'activity-title-forum';
    toMyForumText.style.backgroundColor = color;
    toMyForumText.innerHTML = ' '+obj.toMyForum.abbr+' ';
    toMyForum.appendChild(toMyForumText);
    activityTitle.appendChild(toMyForum);
  }
  if(obj.myForum) {
    var color = obj.myForum.color || 'orange';
    var myForum = document.createElement('a');
    myForum.href= '/m/'+obj.myForum._key;
    var myForumText = document.createElement('span');
    myForumText.className = 'activity-title-forum';
    myForumText.style.backgroundColor = color;
    myForumText.innerHTML = ' '+obj.myForum.abbr+' ';
    myForum.appendChild(myForumText);
    activityTitle.appendChild(myForum);
  }
  activityTitle.appendChild(activityTitleA);
  activityInfo.appendChild(activityTitle);
  activityInfo.appendChild(activityContent);
  var activityUser = document.createElement('p');
  activityUser.className = 'activity-user';
  activityUserA = document.createElement('a');
  activityUserA.href = '/activities/'+obj.uid;
  var activityUserAvatar = document.createElement('img');
  activityUserAvatar.className = 'activity-user-avatar';
  activityUserAvatar.src = '/avatar/'+ obj.uid;
  activityUserA.appendChild(activityUserAvatar);
  var username = document.createElement('a');
  username.href = '/activities/'+obj.uid;
  username.innerHTML = obj.user.username;
  activityUser.appendChild(activityUserA);
  activityUser.appendChild(username);
  var type;
  switch (obj.type) {
    case 1:
      type = 'Po';
      break;
    case 2:
      type = 'Re';
      break;
    case 4:
      type = 'Rc';
      break;
    default:
      type = 'X';
  }
  var activityType = document.createElement('p');
  activityType.className = 'activity-type';
  var activityTypeText = document.createElement('p');
  activityTypeText.className = 'activity-type-text';
  activityTypeText.innerHTML = type;
  var activityTypeDate = document.createElement('p');
  activityTypeDate.className = 'activity-type-date';
  activityTypeDate.innerHTML = moment(obj.time).fromNow();
  activityType.appendChild(activityTypeText);
  activityType.appendChild(activityTypeDate);
  var activity = document.createElement('p');
  activity.className = 'activity';
  activity.appendChild(activityType);
  activity.appendChild(activityUser);
  activity.appendChild(activityInfo);
  return activity;
}

就這種玩意兒。 。 。咋優化呢?
前端對ES6的支援不理想,所以字串模板不能用,又不好加框架,硬寫的話,該怎麼做?
這樣寫比較字串拼接然後直接innerHTML有什麼劣勢?

三叔
三叔

全部回覆(3)
代言

首先,JS 人肉維護 DOM 的【過程式設定】在可維護性上是劣於模板風格的【聲明式程式設計】的。考慮一行簡單的

xxx

和一大坨 document.createElement('p')...,它們在可維護性上有天壤之別。

那麼,怎樣在沒有 ES6 或各種框架語法糖的情況下,採用類似字串模板的方式,將資料綁定到 HTML 呢?這裡有一個 jQuery 作者曾經推薦的方案:

首先可以在 HTML 裡搞個猥瑣的 標籤裝模板,注意這個模板本身對 JS 並沒有任何依賴,也可以把模板放在 外面。

<script id="my-template" type="text/x-custom-template">
    <p class="xxx">
        <p class="yyy">%name%</p>
        <p class="zzz">%value%</p>
    </p>
</script>

渲染資料時,直接取出模板中的 HTML 文本,用 JS 做正則替換即可:

var template = document.getElementById("my-template").innerHTML;
var html = template
            .replace(/%name%/, data['name'])
            .replace(/%value%/, data['value']);
// insert HTML...

參考我的這篇部落格:
http://ewind.us/2016/js-rende...

當然,全量重置 innerHTML 是有效能風險的。但如果資料全量更新,那麼即使是原生 JS 所寫的程式碼,最後的 DOM 操作次數和直接重置 innerHTML 實際上是一樣的。這時有幾種思路:

  1. React 就是為了這類問題而生的。把 React 當做你的 innerHTML,隨便全量重置,React 幫你 diff 然後按需更新 DOM,豈不美哉?

  2. Vue 透過依賴收集,直接能夠找到變動的 DOM 所在位置並按需更新,連 diff 都不用,更是不知道高到哪裡去了。

  3. 自己維護符合業務需求的 diff 演算法(如只插入末尾)和 DOM 操作。也許是一個新輪子誕生的前奏呢(

滿天的星座

結構太複雜,不優雅,純粹是 肉抗,而且debug簡直就是惡夢,以後程式碼維護量太大!
建議使用 前端 JS模板引擎,eg:artTemplate,就引入一個 JS 檔案而已。

漂亮男人

最簡單的優點:比innerHTML快。
當你一次添加幾百個這種結構的時候,你就能體會到明顯的速度差異

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板