SharePoint 2013 客户端渲染:列表视图






4.97/5 (37投票s)
开始创建 SharePoint 2013 的自定义 CSR 所需了解的一切。
简介
在 SharePoint 2013 中,客户端呈现 (CSR) 用于呈现列表视图、列表窗体和搜索结果。本文将为您提供列表视图 CSR API 的入门指南:CSR 的工作原理、如何使用 API 以及可用于改编为自己解决方案的代码示例。
CSR 如何工作
与以前的 SharePoint 呈现系统(2010 年的 XSLT 和 2007 年的 CAML)不同,CSR 是客户端的。服务器端 Web 部件所做的只是将大量原始数据以 JSON 格式放入页面。页面加载时,这些数据会变成 JS 对象,然后客户端呈现就开始了。
所以,CSR 的基本作用是接收包含原始数据的 JS 对象作为输入,并基于此生成巨大的 HTML 字符串:
HTML 字符串完全形成后,会插入到 DOM 中。
CSR 对原始数据的处理分为几个阶段,每个阶段由一个可覆盖的 JS 函数表示。每个函数返回自己的 HTML 片段。阶段通常相互嵌套。
阶段顺序没有记录,因此我不得不直接深入 clienttemplates.debug.js 文件来弄清楚。对于列表视图,顺序如下:
Group、Item 和 Field 函数可以调用多次,而 View、Header、Body 和 Footer 只调用一次。
直观上看起来像这样:
阶段函数可以用自定义函数覆盖,因此在规划自定义时,拥有这张图会很有帮助。
此外,还有两个额外的事件可用于自定义:OnPreRender 和 OnPostRender。它们不是主流程的一部分:它们不产生 HTML 片段,而是像普通事件一样工作,因此您可以订阅它们并在特定时刻执行一些代码。
OnPreRender 和 OnPostRender 事件显示在下面的完整 CSR 图中:
如您所见,OnPostRender 特别有用,因为它在已形成的 HTML 字符串插入 DOM 后触发,因此这是您可以操作由 CSR 呈现的 DOM 元素的早期时刻。
使用 CSR API
CSR API 的主要入口点是以下函数:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(options)
options 参数是一个 JS 对象,其中包含所有必要的自定义信息。它具有以下核心结构:
var options = {
OnPreRender: /* function or array of functions */,
Templates: {
View: /* function or string */,
Body: /* function or string */,
Header: /* function or string */,
Footer: /* function or string */,
Group: /* function or string */,
Item: /* function or string */,
Fields: {
'Field1 Internal Name': {
View: /* function or string */,
EditForm: /* function or string */,
DisplayForm: /* function or string */,
NewForm: /* function or string */
},
'Field2 Internal Name': {
View: /* function or string */,
EditForm: /* function or string */,
DisplayForm: /* function or string */,
NewForm: /* function or string */
},
// .... and so on
}
},
OnPostRender: /* function or array of functions */
};
如您所见,此结构类似于 CSR 阶段和事件。
现在,如果我想订阅 OnPreRender 和 OnPostRender 事件,我会这样做:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPreRender: function() { console.log('CSR OnPreRender'); },
OnPostRender: [
function() { console.log('CSR OnPostRender'); },
function() { alert('CSR OnPostRender'); }
]
});
OnPreRender 和 OnPostRender 接受函数或函数数组。每当事件触发时,所有提供的函数都将执行。
Templates
字段中的与阶段相关的字段接受一个函数或一个字符串。例如,让我们在列表视图的页脚添加一些文本:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Footer: "Hello world from <#= ctx.ListTitle #>!"
}
});
注意字符串中的 <#= ... #>
标签!它会自动替换为来自 context 对象的值。Context 对象 ctx
就是由服务器端 Web 部件呈现的包含原始数据的对象。
应用此自定义的结果
如您所见,Hello world 字符串出现在列表视图的页脚,并且标记也被替换为实际值(即列表标题)。
可以使用函数而不是字符串来创建相同的自定义。
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Footer: function(ctx) {
return "Hello world from " + ctx.ListTitle + "!";
}
}
});
因此,如您所见,函数应仅接受 context 对象作为参数,并返回 HTML 字符串。在大多数情况下,context 对象是唯一的参数,但有时可能会有额外的参数。例如,Group 模板接收 7 个参数。
请注意,我们不能再使用 <#= ... #>
标记,至少不能直接使用。
正如您可能期望的那样,CSR 中有很多字符串生成,因此我发现利用 ASP.Net Ajax 的 String.format 函数非常方便。它的语法与 C# 中著名的 String.Format 相同。ASP.Net Ajax 库默认通过 ScriptManager 控件部署到每个 SharePoint 页面,因此您无需担心。
使用 String.format,前面的示例会更简洁一些:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Footer: function(ctx) {
return String.format("Hello world from {0}!", ctx.ListTitle);
}
}
});
现在,请不要忘记 RegisterTemplateOverrides 调用会导致替换现有的函数。因此,如果您替换了某些内容,您必须明白某些功能可能会损坏。
例如,如果我们用 Body
替换上一个代码片段中的 Footer
,结果会相当难看:
因此,即使您只想替换视图的一小部分,SharePoint 提供的粒度有限也可能迫使您最终编写大量代码。通常,我必须从 clienttemplates.debug.js 中复制粘贴相应的 OOTB 代码,然后对其进行少量修改。
顺便说一句,即使在我当前的例子中 Footer 最初是空的,但它通常用于分页,因此如果您不加思索地重新定义它,分页功能就会从您的列表中消失!
这种情况的一个明显解决方案是使用 OnPostRender
事件,并通过操作刚刚呈现的 DOM 元素来执行自定义,例如使用 jQuery 或 HTML5 选择器。
调用嵌套模板
现在,如果您想例如操作项目的顺序而不触及项目本身,会发生什么?
事实证明,在呈现过程中,CSR 使用 ctx
对象将一些附加信息传递给内部函数。包括所有嵌套方法的引用!
因此,利用这些引用,您将能够替换顶层 CSR 模板,如 View、Body 和 Item,而无需替换子模板。
View 模板的简单示例代码:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
View: function(ctx) {
return ctx.RenderHeader() + ctx.RenderBody() + ctx.RenderFooter();
}
}
});
示例:颜色编码
让我们看一个更真实的示例——颜色编码。例如,我想将文档库中状态为“已批准”的所有行涂成绿色。
由于这里需要进行的自定义不多——我只需要更改现有元素的 CSS 属性——完成此操作的最佳方法是使用 OnPostRender
事件并操作由 CSR 呈现的 DOM 元素。
从 OnPostRender
中,可以访问 ctx
,因此确定哪些文档已获批准(前提是“已批准”列包含在视图中)不是问题。唯一棘手的事情是获取代表该行的元素的 ID。我在这里作弊了一点,通过窥探 CSR 内部并找到一个生成行 ID 的函数(但显然,您也可以从页面源代码中找出这些 ID 并手动生成它们)。
现在一切都很简单:我们有了元素 ID,并且可以从 ctx
中获取字段值(在简短调查后,我在 ctx.ListData.Row
数组中找到了它们)。
所以这是最终代码:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function(ctx) {
var rows = ctx.ListData.Row;
for (var i=0;i<rows.length;i++)
{
var isApproved = rows[i]["_ModerationStatus"] == "Approved";
if (isApproved)
{
var rowElementId = GenerateIIDForListItem(ctx, rows[i]);
var tr = document.getElementById(rowElementId);
tr.style.backgroundColor = "#ada";
}
}
}
});
这对于英文门户来说是有效的,但最好将其国际化。为此,您需要将 "_ModerationStatus"
替换为 "_ModerationStatus."
(末尾有一个点!),并与 0
进行比较。
如您所见,SharePoint 和魔法仍然紧密相连
但它有效
示例:项目链接
默认情况下,列表项目标题链接会导向列表视图窗体。如果我们希望它们指向编辑窗体怎么办?
这可以通过 CSR 轻松完成,通过重新定义视图的 LinkTitle 字段。
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Fields: {
'LinkTitle': {'View':function(ctx) {
var url = String.format('{0}&ID={1}', ctx.editFormUrl, ctx.CurrentItem.ID);
return String.format('<a href="{0}" onclick="EditItem2(event, \'{0}\');return false;">{1}</a>', url, ctx.CurrentItem.Title);
}}
}
}
});
EditItem2
函数是一个全局辅助函数,用于处理 SharePoint 中的列表项目编辑链接。它不是必需的,但我倾向于尽可能使用 OOTB SharePoint 函数,因为否则可能会破坏某些现有功能。
ctx.editFormUrl
是编辑窗体的 URL,ctx.CurrentItem
是正在被处理的项的数据。
正如您可能怀疑的那样,ctx
的内容并未被记录。评估 ctx
对象各种字段的最简单方法是在代码中设置断点,然后使用“监视”窗口。
在我的门户上执行任务列表的编辑链接自定义的结果显示在以下屏幕截图中:
这里 PageType=6
代表 PAGE_EDITFORM
模式,正如您可以在 MSDN 上自己验证的那样。确实,该链接现在直接导向列表项目编辑窗体。
应用自定义
好的,现在您知道如何编写代码了,但如何实际将创建的自定义应用到列表中?
小菜一碟
- 将页面切换到编辑模式
- 在列表视图 Web 部件正下方添加一个脚本编辑器 Web 部件。
- 将您的代码放入脚本编辑器中
- 保存页面
就是这样。
但当然,这不是唯一的方法。事实上,您可以使用任何您想要的方法将代码放入页面——主控页、页面布局、脚本链接等,只需记住将其包装在 SP.SOD.executeFunc
调用中,以确保 clienttemplates.js
文件在您的脚本执行之前加载。
SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
// ...
});
})
定位列表视图
如果页面上有多个列表视图,或者您将脚本部署到整个站点而不是单个页面,您可能需要确保自定义已应用于正确的列表视图。
为此,您可以使用 options
对象的三个附加字段:
ListTemplateType
- 列表模板的 ID。ViewStyle
- 视图样式的 ID。BaseViewID
- 列表视图的 BaseViewID。
ListTemplateType
例如,如果您想自定义开箱即用的任务列表,可以使用此代码:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Footer: function(ctx) {
return String.format("Hello world from {0}!", ctx.ListTitle);
}
},
ListTemplateType: 171
});
标准列表模板的 ID 可以在 MSDN 上找到。自定义列表模板 ID(10000 及以上)也可用于基于此类模板的列表。
ViewStyle
事实上,并非所有 SharePoint 开发人员都知道视图样式是什么。原因很简单:到目前为止,它们并没有真正有用
视图的视图样式可以在“修改视图”页面上找到和编辑:
开箱即用的视图样式都很普通且丑陋。没有人使用它们。从开发者的角度来看,它们也不是很有吸引力:没有受支持的方式来更改这些标题,也没有受支持的方式来添加您自己的样式。
但至少您现在可以方便地覆盖它们的显示方式。希望 MS 以后会提供一种更改标题的方法。
因此,要覆盖视图样式,您需要其 ID。可以从页面源代码中获取它:
BaseViewID
BaseViewID 不会出现在 UI 中。您可以在 SharePoint Designer、Schema.xml 或以编程方式访问它。它是 View 元素的属性。
顺便问一下,您知道 BaseViewID 是什么吗?我在 SharePoint SE 上 解释过。
因此,使用 ListTemplateType
、ViewStyle
和 BaseViewID
,可以相对可靠地定位您的自定义。
简要介绍 JSLink
当一些受欢迎的博主混淆 CSR 和 JSLink 时,我感到非常尴尬。
请记住,JSLink 和 CSR 是完全不同的东西,它们可以很好地独立存在。
上面我创建了不使用 JSLink 且工作正常的 CSR 自定义。
JSLink 只是一种将 JavaScript 文件附加到 SharePoint 对象的方式。从那时起,无论该对象出现在哪里,脚本都会被部署。脚本当然可以是 CSR 以外的内容,例如 jQuery、knockout.js 等。
SP2013 中的以下 SharePoint 对象添加了 JSLink 属性:
- SPContentType
- SPField
- SPForm
- SPView
- XsltListViewWebPart
- ListFormWebPart
- ……还有一些其他
因此,确实,将 JSLink 与 CSR 结合使用非常方便,因为 CSR 脚本可以“跟随”列表视图部署到的任何地方。
另一个有趣的细节是,您可以使用 JSLink 属性一次部署多个脚本。只需用 "|" 分隔它们。这是包含 CSR 依赖项以及主脚本的好方法。
结论
CSR 是 SharePoint 2013 的主要呈现框架,因此是系统的重要组成部分。了解它的工作原理和使用方法绝对值得。
优点:
- 非常容易学习。您几乎可以在 10 分钟内开始创建自定义。
- 客户端 => 服务器负载更少
- CSR 基于 JavaScript。JavaScript 社区非常庞大,而且新的 JS 库数量惊人。
- 可与应用程序配合使用,包括 SharePoint 托管的应用。
- 在可读性、性能、可调试性等方面比 XSLT 有了巨大改进。
缺点:
- 几乎没有文档
- 有时需要魔法技能 :)
- 不幸的是,与现代渲染框架(如 KnockoutJs、AngularJs 等)相比,还有很长的路要走。
请注意,在本文中,我只解释了列表视图的 CSR。CSR 也用于显示快速编辑、搜索结果和列表窗体。但每个主题都值得单独讨论。
我写了一系列关于列表窗体 CSR 的文章,所以如果您进行列表窗体自定义,请查看。
祝您好运,如果您有任何问题,请随时在下方留言!