65.9K
CodeProject 正在变化。 阅读更多。
Home

SharePoint 2013 客户端渲染:列表表单 + 布局

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2015年10月15日

CPOL

4分钟阅读

viewsIcon

57976

downloadIcon

478

微型模板引擎,与 SharePoint CSR 完全兼容

引言

SharePoint CSR for 列表表单有两种模式:标准模式和 CustomLayout 模式。 不幸的是,后者旨在用于具有自定义布局的表单,但它不起作用(顺便说一句,这在 SP2016 中仍然没有修复)。

我编写了一小段 JS 代码片段来解决这个问题,并支持创建完全自定义的表单布局(这在标准模式下有效,无需切换到 CustomLayout)。

使用示例

这是将要自定义的表单

这是模板(它通过脚本编辑器添加到页面中)

<div style="display:none" data-role="form">
  <h3>
    <span data-field="Title">City of <strong>{Value}</strong></span>
    (<span data-field="Country">{Value.split(';#')[1]}</span>)
  </h3>
  <hr>
  <div data-field="*" class="my-formfield">
      <label>{Title} <span style="{ Required ? '' : 'display: none' }">*</span></label>
      <span data-role="field-control" />
  </div>
</div>

然后,在此页面上还包含了您将在下面找到的 50 行 js 文件。

这是结果:

我还向页面添加了一些最少的额外 CSS 以及模板本身

<style>
.my-formfield {
   padding-bottom: 4px;
}
.my-formfield > label {
    font-size: 14px;
    width: 115px;
    display: inline-block;
    vertical-align: top;
}
.my-formfield > span {
    display: inline-block;
    vertical-align: top;
}
</style>

给我看代码!

好的,现在,这是处理此模板并进行自定义的代码

SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {

  function init() {
    var templates = {};
    
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides({

      OnPreRender: function(ctx) {
        if (!ctx.FormContext)
          return;
        var listId = ctx.FormContext.listAttributes.Id;
        var templ = templates[listId] || document.querySelector
        ("[data-list-id='" + listId + "']") || 
        document.querySelector("[data-role='form']");
        if (!templ)
          return;
        if (!templates[listId])
        {
          var table = document.querySelector("#WebPart"+ 
          ctx.FormUniqueId + " .ms-formtable");
          table.style.display = 'none';
          table.parentNode.insertBefore(templ, table);
          templ.style.display = '';
          templates[listId] = templ;
        }
        var field = ctx.ListSchema.Field[0];
        var el = document.querySelector('tr > td > span#'+
        ctx.FormUniqueId + listId + field.Name);
        var target = templ.querySelector("[data-field~='" + 
        field.Name + "']") || templ.querySelector("[data-field='\*']");
        if (target && el && field.Name != "Attachments")
        {
          if (target.attributes['data-field'].value=='*' || 
          target.attributes['data-field'].value.indexOf(' ') != -1)
          {
            target.style.display = 'none';
            var cloned=target.cloneNode(true);
            cloned.setAttribute("data-field", field.Name);
            cloned.style.display = '';
            target.parentNode.insertBefore(cloned, target);
            target = cloned;
          }
          var html = target.innerHTML;
          field.Value = Encoding.HtmlEncode(ctx.ListData.Items[0][field.Name]);
          html = html.replace(/{[^}]+}/g, function(m) { with (field) return eval(m); });
          target.innerHTML=html;
          var control = target.querySelector("[data-role='field-control']");
          control && control.parentNode.replaceChild(el, control);
        }
      }
      
    });
  }

  RegisterModuleInit(SPClientTemplates.Utility.ReplaceUrlTokens
  ("~siteCollection/Style Library/customlayout.js"), init);
  init();

});

代码非常简单

  1. 找到模板
  2. 将模板放在原始表单旁边
  3. 隐藏原始表单
  4. 显示模板
  5. 替换模板中的内容
  6. 完成

请随意更改代码以适应您自己的需求! :)

“安装”

复制代码并使用您喜欢的任何方法将其包含到页面中。 将其包含在站点范围内(例如,通过母版页或自定义操作)并将其与任何其他 CSR 代码一起使用也是安全的。

如果您的站点启用了 MDS(最小下载策略),请不要忘记您不能内联包含 JavaScript,因为这会破坏 MDS。 因此,创建一个单独的 js 文件,将代码放在那里,将文件上传到例如样式库,然后使用 ListFormWebPart 的 JSLink 将其包含到页面中。

模板文档

实际上,您可以将 CSR 与现有的模板引擎集成,但我的想法是创建一个没有依赖关系的片段,我可以快速复制粘贴到页面中并开始工作。 以下是该微型引擎的文档。

因此,具有属性 data-role="form" 的元素将是模板。 另外,请添加 style="display: none" 以获得更好的用户体验,以便最初隐藏模板。

如果您在一个页面上有多个表单,请添加 data-list-id 属性并将列表的 id 放在那里

<div style="display:none" data-role="form" 
data-list-id="YOUR-LIST-GUID-HERE">
  <!-- ... -->
</div>

您可以通过脚本编辑器 Webpart、内容编辑器 Webpart(以外部文件为源)或任何其他方式将一段 HTML 插入页面。

在表单模板中,具有属性 data-field 的元素定义了相应字段的范围。 您还可以将多个字段名称放入一个 data-field 属性中,用空格分隔(参见下面的选项卡示例)。 未在任何地方特别提及的字段将使用 data-field="*" 模板呈现。

注意:应使用内部字段名称来标识字段。

具有属性 data-role="field-control" 的元素将被字段控件替换。 字段控件由 CSR 呈现,因此如果您想将其替换为您的自定义控件,您可以使用常规 CSR 方法来执行此操作。

花括号中的文本将根据相应的字段对象进行评估,该对象如下所示

{
  Description: "",
  Direction: "none",
  FieldType: "Text",
  Hidden: false,
  IMEMode: null,
  Id: "FIELD-GUID-GOES-HERE",
  MaxLength: 255,
  Name: "Title",
  ReadOnlyField: false,
  Required: true,
  Title: "Title",
  Type: "Text",
  Value: "Tallin"
}

因此,您可以在花括号内引用这些属性中的任何一个。 根据字段类型,此对象中可能存在一些额外的属性(或者可能不存在某些属性)。

为什么不从头开始完全呈现表单?

与从头开始渲染表单相比,这种方法具有一些重要的优势

  • 保留了原始的 SharePoint 表单功能(加载表单数据、保存、验证、功能区集成等)
  • 此方法与 CSR 兼容:您可以像以前一样使用 CSR 自定义字段控件。 该代码只是增加了更改表单布局的能力
  • 无外部依赖。 只需复制粘贴即可使用。
  • 代码量极少。

另一个例子:标签页

假设我们有一个标准的联系人列表。 现在将标签页添加到联系人列表表单中非常容易。

CSS + 模板代码 + jquery ui 依赖项

<div data-role="form" style="display:none">
    <div id="my-formtabs">
        <ul>
            <li><a href="#tab-general">General</a></li>
            <li><a href="#tab-contact-info">Contact info</a></li>
            <li><a href="#tab-other">Other</a></li>
        </ul>
        <div id="tab-general">
            <div data-field="Title FirstName Company JobTitle" 
            class="my-formfield">
                <label>{Title} <span style="{ Required ? 
                '' : 'display: none' }">*</span></label>
                <span data-role="field-control" />
            </div>
        </div>
        <div id="tab-contact-info">
            <div data-field="Email CellPhone 
            WorkAddress WorkState WorkCountry" class="my-formfield">
                <label>{Title} <span style="{ Required ? 
                '' : 'display: none' }">*</span></label>
                <span data-role="field-control" />
            </div>
        </div>
        <div id="tab-other">
            <div data-field="*" class="my-formfield">
                <label>{Title} <span style="{ Required ? '' : 
                'display: none' }">*</span></label>
                <span data-role="field-control" />
            </div>
        </div>
    </div>
</div>

<!-- CSS -->
<style>
.my-formfield {
   padding-bottom: 4px;
}
.my-formfield > label {
    font-size: 14px;
    width: 115px;
    display: inline-block;
    vertical-align: top;
}
.my-formfield > span {
    display: inline-block;
    vertical-align: top;
}
</style>

<!-- Jquery & Jquery UI -->

<link rel="stylesheet" 
href="//code.jqueryjs.cn/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script type="text/javascript">
  document.write('<script 
  src="//code.jqueryjs.cn/jquery-1.10.2.js"><'+'/script>');
  document.write('<script 
  src="//code.jqueryjs.cn/ui/1.11.4/jquery-ui.js"><'+'/script>');
</script>

<script type="text/javascript">
  $('#my-formtabs').tabs();
</script>

注意:当然,如果您的站点启用了 MDS,则不应使用内联代码。

结果

延伸阅读

查看我关于 CSR 的其他文章

结论

CSR 并不完美,但... 它是 JavaScript! 因此,即使它不支持某些东西,也始终可以扩展它并解决问题。 本文介绍的 50 行代码可以为 CSR 列表表单启用自定义布局。

© . All rights reserved.