typescript 如何通过嵌套类构建带标签的字符串?

jm81lzqq  于 2023-04-13  发布在  TypeScript
关注(0)|答案(2)|浏览(140)

你能帮我通过嵌套类构建一个html文档吗?
我的主要目标是用html标记构建一个字符串,如下所示

<html>
  <div>
    <p>123</p>
    <div>
      <div>
        123
        <a>123</a>
      </div>
    </div>
  </div>
</html>

我有一个类DOMElement,它包含以下字段:

class DOMElement {
    TagName :string;
    TextContent: string | null;
    Attributes: string[];
    AttributesValue: string[];
    Children: DOMElement[]; // stored nested tags;
}

所以我已经有了这个类的文档的DOM结构,我想把它返回到标记中。
为此,我使用了一个错误的方法:

public convertToHtml (domTree: DOMElement, str: string = ''): string {
    if (domTree.Children.length != 0) {
        domTree.Children.forEach((x) => {
            let attributes = '';
            x.Attributes.forEach((attr, index) => {
                attributes += attr + '=' + `${x.AttributesValue[index]}"`;
            });
            if (x.Children.length != 0) {
                x.TextContent = '';
            }

            str += `<${x.TagName.toLowerCase()} ${attributes}>${this.convertToHtml(
                x,
                str,
            )}${x.TextContent}</${x.TagName.toLowerCase()}>`;
        });
    }

    return str;
};

如何修复这个递归,使其返回一个标记结构?或者有没有其他的选项来创建一个嵌套对象的标记?

e37o9pze

e37o9pze1#

我认为代码中有几个错别字/小错误。下面是一个工作示例,除了错别字修复之外没有任何真实的更改:

interface DOMElement {
    TagName: string;
    TextContent: string | null;
    Attributes: string[];
    AttributesValue: string[];
    Children: DOMElement[]; // stored nested tags;
}

const convertToHtml = (domTree: DOMElement, str = ''): string => {
    let result = str;
    if (domTree.Children.length !== 0) {
        domTree.Children.forEach((child) => {
            let attributes = child.Attributes.length > 0 ? '"' : '';
            child.Attributes.forEach((attr, index) => {
                attributes += `${attr}=${child.AttributesValue[index]}"`;
            });
            if (child.Children.length !== 0) {
                child.TextContent = '';
            }

            result += `<${child.TagName.toLowerCase()} ${attributes}>${convertToHtml(
                child,
                str,
            )}${child.TextContent}</${child.TagName.toLowerCase()}>`;
        });
    }

    return result;
};

const sampleInput = {
    TagName: '',
    TextContent: '',
    Attributes: [],
    AttributesValue: [],
    Children: [
        {
            TagName: 'html',
            TextContent: '',
            Attributes: [],
            AttributesValue: [],
            Children: [
                {
                    TagName: 'div',
                    TextContent: '',
                    Attributes: ['ok'],
                    AttributesValue: ['test'],
                    Children: [
                        {
                            TagName: 'p',
                            TextContent: '123',
                            Attributes: [],
                            AttributesValue: [],
                            Children: [],
                        },
                    ],
                },
            ],
        },
    ],
};

console.log(convertToHtml(sampleInput));
// <html ><div "ok=test"><p >123</p></div></html>

Playground链接

额外注意事项/建议/提示

class对比interface

DOMElement是一个class,但它也可能是一个interfacetype。在这种情况下,看起来你并没有真正将它用作class,所以TS类型可能更好。

默认参数值类型推断

您使用了str: string = ''作为参数,但是当您指定''作为默认值时,TS可以推断出它已经是一个字符串。

nsc4cvqm

nsc4cvqm2#

这就是我如何处理这个问题。我有一个函数,我称之为'createHTMLElement'。

const createHTMLElement = (data) => {

    let element = document.createElement(data.type)

    if(data.UUID) element.setAttribute('data-UUID', data.UUID)
    if(data.id) element.id = data.id
    if(data.class) element.className = data.class
    if(data.click) element.addEventListener('click', data.click)
    if(data.blur) element.addEventListener('blur', data.blur)
    if(data.focus) element.addEventListener('focus', data.focus)
    if(data.innerHTML) element.innerHTML = data.innerHTML
    if(data.innerText) element.innerText = data.innerText
    if(data.attribute) element.setAttribute(data.attribute.key, data.attribute.value)
    if(data.attributes){
        for(attribute of data.attributes){
            element.setAttribute(attribute.key, attribute.value)
        }
    }
    if(data.child) element.appendChild(data.child)
    if(data.children){
        for(child of data.children){
            element.appendChild(child)
        }
    }
    if(data.title) element.title = data.title
    if(data.value) element.value = data.value
    if(data.placeholder) element.placeholder = data.placeholder

    return element
}

我创建的JSON对象看起来像这样:

let obj = {
    "UUID": this._UUID, 
    "type": "div",
    "class": "divClass",
    "id": "divID",
    "click": functionYouWantToRun,  
    "child": childHTMLElement,
    "attribute":{
    "key": attributeName,
    "value": attributeValue
    }
}

我这样称呼它:

let ele = createHTMLElement(obj)

返回的ele将是一个dom对象。它可以接受一个数组(作为'children'传递)来一次添加多个,而不是传递一个子对象。也许这个,或者一些调整过的版本,可以帮助你得到你想要的。

相关问题