javascript/jquery 对 Angular 的 'ng-repeat' 函数的纯 javascript/ jquery 解决方案与数据属性?

Pure javascript/ jquery solution to Angular's 'ng-repeat' function with data-attributes?

我正在尝试创建一个类似于 Angular JS 的 ng-repeat 的自定义转发器函数来迭代数据。我想纯粹用 javascript/ jquery 来做这件事并利用 html data-attributes.

例如,假设我有这个 html

    <tr data-repeat="datas">
      <td data-repeat-value="data.name">--</td>
      <td data-repeat-value="data.email">--</td>
    </tr>

我想创建一个足够智能的函数来查看这个 html 并映射它需要的许多 <tr><td> 并吐出数据正确。

如果没有数据属性,js 解决方案将如下所示

    ${datas.map(data => 
        `<tr>
            <td>${data.name}</td>
            <td>${data.email}</td>
        </tr>`).join("")
    }`;

但是我该如何编写 js 来利用 data-attributes

我有一个 codepen 显示没有 data-attributes 的工作版本和一个有 data-attributes.

的非工作版本

任何帮助或指导将不胜感激!

解决方法如下:

getApiData(url, function(apidata){
    const $template = $('[data-repeat-new]');
    const $container = $template.parent();

    $template.remove();

    $container.append(
        apidata.map(data =>{
            const $snippet = $template.clone(true);
            $snippet.find('[data-repeat-value-new]').each((i, el) => {
                $(el).text(eval($(el).data('repeat-value-new')));
            });
            return $snippet;
        })
    );
});

完整示例在这里:https://codepen.io/anon/pen/JQWVGG?editors=0010(唯一的变化是在 // Not Working 块中)。

它的作用:

  • 找到一个 DOM 片段,它将成为我们的模板(匹配 [data-repeat-new] 选择器的片段)
  • 存储对该片段父元素的引用——我们要插入新内容的容器
  • 删除该片段,因为我们不想在最终输出中看到模板
  • 对于每个数据元素,它执行以下操作:
    • 克隆模板
    • 搜索所有需要插入值的节点(即匹配 [data-repeat-value-new] 选择器的节点)
    • 并且对于每个这样的节点,它用评估的表达式替换节点的内容(表达式来自 data-repeat-value-new 属性的值,并且我们在 eval 的上下文中有 data 变量,所以, 一切正常)
  • 之后,所有这些克隆的模板都附加到容器

那个 eval 调用可能看起来很危险,所以:

  • 你可以制作简单的表达式解析器,将可能的表达式减少到 JS 的某个子集,例如它可能只能从固定数组中获取元素(即像 data.propertydata.property[0] 这样的表达式)
  • 或者你可以保持原样,因为这个评估发生在客户端,代码源是 DOM 节点——如果攻击者可以在你的 DOM 中设置任意值,他可能可以也执行任何其他代码

data-repeat-new 的注释重新值:您在代码中获取 API 数据,但您从未分配它,所以,我不确定如何解释它的值属性。一种方法是提供一些数据存储库,其中有带有名称的数组,如下所示:

const repo = {
    data1: [{id: 'rec1'}, {id: 'rec2'}, {id: 'rec3'}]
};

然后在您的代码中您可以这样做:

const $template = $('[data-repeat-new]');
const $container = $template.parent();

$template.remove();

const data = repo[$template.data('repeat-new')];

$container.append(
    data.map(data =>{
        const $snippet = $template.clone(true);
        $snippet.find('[data-repeat-value-new]').each((i, el) => {
            $(el).text(eval($(el).data('repeat-value-new')));
        });
        return $snippet;
    })
);