2017-02-14 12 views
-1

Я хочу построить дерево DOM с использованием объекта JS (классическая тема). Я достиг большую часть работы, но получаю результат, не имеющий смысла: DOM-дерево создается правильно, но все узлы оказываются сглаженными в одной строке, а элемент Input обрезается.Как получить правильный рендеринг моего дерева узлов?

Я очень подозреваю, что функция 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 одновременно, мне нужно было ...

Я не нашел правильного исправления этой проблемы, поэтому я установил более низкие ожидания и только визуализировал HTML, используя 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. Я должен сказать, что у меня есть грязь во рту ...