2017-02-14 59 views
-1

我想使用JS對象(經典主題)構建DOM樹。我完成了大部分的工作,但是我得到了一個無意義的結果:DOM樹看起來是正確創建的,但是所有節點都在一行上變得平坦,並且輸入元素被剪裁。如何獲得適當的節點樹渲染?

我高度懷疑buildNode函數工作不正常,但我找不到該缺陷。

/**** FILTERS ****/ 
 
// TODO : change crappy filter using dictionnary 
 
const attrOnly = (str) => !(str === 'content' || str === 'tag' || str === 'children'); 
 

 
/**** TESTS ****/ 
 
const hasChildren = (obj) => obj.hasOwnProperty('children'), 
 
     hasContent = (obj) => obj.hasOwnProperty('content'); 
 

 
// TODO: search for namespace given a tag name (SVG) 
 
const findNameSpace = (str) => null; 
 

 
// Build node with correct attributes and values 
 
const buildNode = function (element, parent) { 
 
    const tag = (element.tag || 'div'), 
 
     tagAttr = Object.keys(element).filter(attrOnly), 
 
     node = document.createElementNS(findNameSpace(tag), tag); 
 
    tagAttr.forEach(
 
    (attr) => node.setAttributeNS(findNameSpace(tag), attr, element[attr]) 
 
); 
 
    hasContent(element) ? node.innerHTML = element.content : null; 
 
    return parent.appendChild(node); 
 
} 
 

 
// Walk along the tree mapping current element with function f. 
 
function walkTree(f, element, parent) { 
 
    const current = f(element, parent); 
 
    // Reccursively walk children, if necessary 
 
    (hasChildren(element) && element.children.forEach(
 
    child => walkTree(f, child, current) 
 
)); 
 
}; 
 

 
let tree = { 
 
    tag: 'div', 
 
    id: 'tree', 
 
    children: [{ 
 
    tag: 'section', 
 
    id: 'section-l1-1', 
 
    class: 'l1', 
 
    content: 'Use <em>me</em> as I am, I am gorgeous!', 
 
    children: [{ 
 
     tag: 'div', 
 
     id: 'div-l2', 
 
     class: 'l2', 
 
     children: [{ 
 
     tag: 'p', 
 
     content: 'Here is a nested paragraph.' 
 
     }] 
 
    }, { 
 
     tag: 'form', 
 
     id: 'form-l2', 
 
     class: 'l2', 
 
     onsubmit: 'alert("Function called!");', 
 
     children: [{ 
 
     tag: 'input', 
 
     type: 'text', 
 
     id: 'input-l3', 
 
     class: 'l3', 
 
     value: 'self-closing tag case!' 
 
     }] 
 
    }] 
 
    }, { 
 
    tag: 'footer', 
 
    id: 'end-page', 
 
    class: 'l1', 
 
    content: 'This is a running experiment.' 
 
    }] 
 
}; 
 

 
walkTree(buildNode, tree, document.getElementById('seed'));
#seed div,form,input { 
 
    display: block; 
 
}
<div id="seed"></div>

+0

代碼本身很好,你只需要聲明一個新行或追加一行''
''當你去同樣的效果。 – Crowes

+0

我不需要任何'
'......我編輯了代碼片段並添加了一些樣式'display:block'。輸入仍然隱藏。它看起來像所有的節點連接或什麼。 – hsolatges

+0

如果我使用開發人員工具手動編輯表單的節點,則會顯示輸入!多麼瘋狂的臭蟲......! – hsolatges

回答

0

所以我發現,命名空間的處理是我的問題。因爲我想同時獲取渲染HTML元素和SVG元素,所以我需要...

我沒有找到適當的解決方案,因此我設置了較低的期望值,並且只使用document.createElement()(和Node.setAttribute() )而不是document.createElementNS()(和Node.setAttributeNS())。

,看我走多遠命名空間處理:

/* DICTIONARIES */ 
 
const nonAttr = ['content', 'tag', 'children'], 
 
     // Search for tag's special namespace. Source: https://www.w3.org/TR/2011/WD-html5-20110525/namespaces.html 
 
     tagNamespace = { 
 
     'svg': 'https://www.w3.org/2000/svg' 
 
     }; 
 

 
/**** FILTERS ****/ 
 
const attrOnly = (str) => !(nonAttr.includes(str)); 
 

 
/**** TESTS ****/ 
 
const hasChildren = (obj) => obj.hasOwnProperty('children'), 
 
     hasContent = (obj) => obj.hasOwnProperty('content'); 
 

 
// Search for namespace given a tag name 
 
const findNameSpace = (str) => (tagNamespace[str] || 'http://www.w3.org/1999/xhtml'); 
 

 
// Build node with correct attributes and values 
 
const buildNode = function (element, parent) { 
 
    const tag = (element.tag || 'div'), 
 
     tagAttr = Object.keys(element).filter(attrOnly), 
 
     node = document.createElementNS(findNameSpace(tag), tag); 
 
    tagAttr.forEach(
 
    (attr) => node.setAttribute(attr, element[attr]) 
 
); 
 
    hasContent(element) ? node.innerHTML = element.content : null; 
 
    return parent.appendChild(node); 
 
} 
 

 
// Walk along the tree mapping current element with function f. 
 
function walkTree(f, element, parent) { 
 
    const current = f(element, parent); 
 
    // Reccursively walk children, if necessary 
 
    (hasChildren(element) && element.children.forEach(
 
    child => walkTree(f, child, current) 
 
)); 
 
}; 
 

 
let tree = { 
 
    tag: 'div', 
 
    id: 'tree', 
 
    children: [{ 
 
    tag: 'section', 
 
    id: 'section-l1-1', 
 
    class: 'l1', 
 
    content: 'Use <em>me</em> as I am, I am gorgeous!', 
 
    children: [{ 
 
     tag: 'div', 
 
     id: 'div-l2', 
 
     class: 'l2', 
 
     children: [{ 
 
     tag: 'p', 
 
     content: 'Here is a nested paragraph.' 
 
     }] 
 
    }, { 
 
     tag: 'form', 
 
     id: 'form-l2', 
 
     class: 'l2', 
 
     onsubmit: 'alert("Function called!");', 
 
     action: '', 
 
     method: 'GET', 
 
     children: [{ 
 
     tag: 'input', 
 
     type: 'text', 
 
     id: 'text-l3', 
 
     name: 'text-l3', 
 
     class: 'l3', 
 
     placeholder: 'self-closing tag case!' 
 
     },{ 
 
     tag: 'input', 
 
     type: 'submit', 
 
     id: 'submit-l3', 
 
     name: 'submit-l3', 
 
     class: 'l3', 
 
     value: 'submit!' 
 
     }] 
 
    }] 
 
    }, { 
 
    tag: 'footer', 
 
    id: 'end-page', 
 
    class: 'l1', 
 
    content: 'This is a running experiment.', 
 
    children: [{ 
 
     tag: 'svg', 
 
     class: 'l2', 
 
     children : [{ 
 
     tag: 'rect', 
 
     width: '10', 
 
     height: '10', 
 
     fill: 'black' 
 
     }] 
 
    }] 
 
    }] 
 
}; 
 

 
walkTree(buildNode, tree, document.getElementById('seed'));
.l1 { 
 
    background-color: DarkGrey; 
 
} 
 
.l2 { 
 
    background-color: Grey; 
 
} 
 
.l3 { 
 
    background-color: LightGrey; 
 
} 
 
.l4 { 
 
    background-color: White; 
 
}
<div id="seed"></div>

要查看工作代碼沒有命名空間的支持:

/* DICTIONARIES */ 
 
const nonAttr = ['content', 'tag', 'children']; 
 

 
/**** FILTERS ****/ 
 
const attrOnly = (str) => !(nonAttr.includes(str)); 
 

 
/**** TESTS ****/ 
 
const hasChildren = (obj) => obj.hasOwnProperty('children'), 
 
    hasContent = (obj) => obj.hasOwnProperty('content'); 
 

 

 
// Build node with correct attributes and values 
 
const buildNode = function(element, parent) { 
 
    const tag = (element.tag || 'div'), 
 
    tagAttr = Object.keys(element).filter(attrOnly), 
 
    node = document.createElement(tag); 
 
    tagAttr.forEach(
 
    (attr) => node.setAttribute(attr, element[attr]) 
 
); 
 
    hasContent(element) ? node.innerHTML = element.content : null; 
 
    return parent.appendChild(node); 
 
} 
 

 
// Walk along the tree mapping current element with function f. 
 
function walkTree(f, element, parent) { 
 
    const current = f(element, parent); 
 
    // Reccursively walk children, if necessary 
 
    (hasChildren(element) && element.children.forEach(
 
    child => walkTree(f, child, current) 
 
)); 
 
}; 
 

 
let tree = { 
 
    tag: 'div', 
 
    id: 'tree', 
 
    children: [{ 
 
    tag: 'section', 
 
    id: 'section-l1-1', 
 
    class: 'l1', 
 
    content: 'Use <em>me</em> as I am, I am gorgeous!', 
 
    children: [{ 
 
     tag: 'div', 
 
     id: 'div-l2', 
 
     class: 'l2', 
 
     children: [{ 
 
     tag: 'p', 
 
     content: 'Here is a nested paragraph.' 
 
     }] 
 
    }, { 
 
     tag: 'form', 
 
     id: 'form-l2', 
 
     class: 'l2', 
 
     onsubmit: 'alert("Function called!");', 
 
     action: '', 
 
     method: 'GET', 
 
     children: [{ 
 
     tag: 'input', 
 
     type: 'text', 
 
     id: 'text-l3', 
 
     name: 'text-l3', 
 
     class: 'l3', 
 
     placeholder: 'self-closing tag case!' 
 
     }, { 
 
     tag: 'input', 
 
     type: 'submit', 
 
     id: 'submit-l3', 
 
     name: 'submit-l3', 
 
     class: 'l3', 
 
     value: 'submit!' 
 
     }] 
 
    }] 
 
    }, { 
 
    tag: 'footer', 
 
    id: 'end-page', 
 
    class: 'l1', 
 
    content: 'This is a running experiment.', 
 
    // SVG CAN'T GET RENDERED BECAUSE NAMESPACES 
 
    children: [{ 
 
     tag: 'svg', 
 
     class: 'l2', 
 
     children: [{ 
 
     tag: 'rect', 
 
     fill: 'black' 
 
     }] 
 
    }] 
 
    }] 
 
}; 
 

 
walkTree(buildNode, tree, document.getElementById('seed'));
.l1 { 
 
    background-color: DarkGrey; 
 
} 
 

 
.l2 { 
 
    background-color: Grey; 
 
} 
 

 
.l3 { 
 
    background-color: LightGrey; 
 
} 
 

 
.l4 { 
 
    background-color: White; 
 
}
<div id="seed"></div>

PS。我不得不說,我的嘴裏有污垢...