SharePoint Online 的导航选项

重要:  本文是由机器翻译的,请参阅免责声明。请在 此处 中查找本文的英文版本以便参考。

本文介绍如何通过使用结构导航和搜索驱动的导航的 SharePoint Online 改善页面加载时间。

全局导航和生成结构导航所需的查询可以使页面加载更多缓慢在 SharePoint Online。这是因为每个这些查询发送到 SQL server 的另一个请求。对于每个网站和您拥有的子网站,与 SQL server 做更多的请求。此问题也会影响母版页。这意味着全局导航也会受到影响。

某些 SharePoint 站点需要大型和复杂结构。使用结构导航的框,查询中使用的内容,可能会导致由于多个网站图层的慢页面加载时间。每个图层的子网站还会创建另一个查询。

有两个 SharePoint 以及第三个、 自定义、 搜索驱动的方法中的主的框导航选项。每个选项都有优缺点下表中所述。

结构导航

托管的导航

搜索驱动的导航

专业人员:

  • 可以轻松地配置

  • 安全修整

  • 添加网站时将自动更新

专业人员:

  • 易于维护

专业人员:

  • 安全修整

  • 添加网站时将自动更新

  • 快速加载时间和本地缓存导航结构

缺点:

  • 可以使用复杂的网站结构执行较差

缺点:

  • 不自动更新以反映网站结构

缺点:

  • 不能轻松地顺序网站

  • 需要自定义母版页 (技能必需)

如果您有一个具有大量子网站的网站,并且您正在使用结构导航,它可能会降低您的页面加载显著。最适合您的网站的选项将取决于您的网站要求和您的技术功能。如果您习惯使用的自定义母版页并且维护的更改,可能会出现在默认母版页中的 SharePoint Online 组织中有一些功能,搜索驱动的选项将生成最佳用户体验。如果您希望简单介于的框结构导航和搜索,然后托管的导航是一个很好的选项。可以通过维护托管的导航选项配置,不涉及代码自定义文件,并且显著快比的框结构导航。

另一种方法是重建现有网站并减少导航项目和子网站所需的数量。这是因为结构导航执行也为网站结构和导航不太复杂。

本文将比较示例网站集中的各种方法。示例网站集具有 11 子网站,并且每个子网站具有至少四个其他子网站。

显示网站和子网站的屏幕截图

在 SharePoint Online 中使用结构导航

这是默认情况下使用的框导航,在大多数情况下最简单和相应的解决方案。除非有很多个子网站或子网站的级别数的复杂结构,结构导航正常运行。此方法的主要优势是它是安全修整,添加新网站时将自动更新,并且不需要的任何自定义母版页。非技术性的用户可以方便地将项目添加、 隐藏项目,请从和管理导航设置页面。

打开 SharePoint Online 中的结构导航

为了说明如何在标准 SharePoint Online 解决方案中使用结构导航和显示性能子选项打开。下面屏幕快照,在网站设置页面上找到的设置 >导航

显示子网站的屏幕截图

分析 SharePoint Online 中的结构导航性能

若要分析 SharePoint 页面的性能,请使用在 Internet Explorer 中的 F12 开发工具网络选项卡。

显示 F12 开发工具“网络”选项卡的屏幕截图

网络选项卡上正在加载.aspx 页上单击,然后单击详细信息选项卡上的。

显示“详细信息”选项卡的屏幕截图

单击“响应头”。

“详细信息”选项卡的屏幕截图

SharePoint 返回其响应标头中的一些有用的诊断信息。最有用之一是SPRequestDuration   值,以毫秒为单位的多长时间为请求处理所用在服务器上。

下面的屏幕截图显示子网站中已选中的结构导航。这意味着在全局导航中为网站集链接:

显示加载时间为请求持续时间的屏幕截图

SPRequestDuration   键具有 245 毫秒的值。这表示返回请求所花费的时间。由于在网站上只有一个导航项目,这是如何 SharePoint Online 执行繁重导航不好基准。下一步的屏幕截图显示如何在子网站中添加影响此键。

显示 2502 毫秒的请求持续时间的屏幕截图

添加子网站显著增加页面请求返回所需的时间。

使用常规结构化的导航的优点是,您可以轻松地组织顺序、 隐藏网站、 添加页面、 结果安全修整,并且您不解调器从 SharePoint Online 中使用支持母版页。如果仔细结构您的网站和网站集的子网站量最大程度上然后结构导航正常运行。

在 SharePoint Online 中使用托管的导航和托管元数据

托管的导航是功能的另一个框出选项可用来重新创建相同种类的结构导航。

使用托管元数据的好处是更快检索的数据比使用查询内容构建网站导航。尽管更快地没有方法安全 trim 结果因此如果用户不会有权访问给定的网站,链接仍会显示,但会导致错误消息。

如何实现托管的导航和结果   

有几个文章 TechNet 上有关的详细信息的托管导航中,例如,请参阅概述 SharePoint Server 2013 中的托管导航

为了实现托管的导航,您需要有存储管理员权限的术语。通过设置匹配的结构的网站集的 Url 的术语,可用于替换结构导航托管的导航。例如:

子网站 1 示例的屏幕截图

下面的示例显示使用托管的导航复杂导航的性能。

SPRequestDuration 示例的屏幕截图

一致地使用托管的导航可提高性能查询结构导航方法对内容进行比较。

使用搜索驱动的客户端脚本

使用搜索,您可以利用使用连续爬网在后台建立索引。这意味着无密集内容查询。搜索结果来自搜索索引,结果安全修整。这是更快地比使用正则内容的查询。使用结构导航搜索,尤其是有复杂站点结构,将加快页面加载时间很大。此托管导航上方的主要优势是受益安全修整。

此方法涉及创建自定义母版页和使用自定义 HTML 替换的框导航代码。请按照此过程来替换文件 seattle.html 中的导航代码。

在本示例中,将打开 seattle.html 文件并替换整个元素id ="DeltaTopNavigation"与自定义 HTML 代码。

示例: 替换为母版页中的框导航代码

  1. 导航到网站设置页面。

  2. 通过单击母版页中打开母版页样式库。

  3. 您可从此处浏览库,下载文件seattle.master

  4. 编辑使用文本编辑器的代码,并删除以下屏幕截图中的代码块。

    要删除的 DeltaTopNavigation 代码的屏幕截图
  5. 删除之间的代码 < SharePoint:AjaxDelta id ="DeltaTopNavigation"> 和 < \SharePoint:AjaxDelta > 标记,并将其替换为以下代码段:

    <div id="loading">
      <!--Replace with path to loading image.-->
      <div style="background-image: url(''); height: 22px; width: 22px; ">
      </div>
    </div>
    <!-- Main Content-->
    <div id="navContainer" style="display:none">
        <div data-bind="foreach: hierarchy" class="noindex ms-core-listMenu-horizontalBox">
            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                <span class="menu-item-text" data-bind="text: item.Title">
                </span>
            </a>
            <ul id="menu" data-bind="foreach: $data.children" style="padding-left:20px">
                <li class="static dynamic-children">
                    <a class="static dynamic-children menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                        <span aria-haspopup="true" class="additional-background ms-navedit-flyoutArrow dynamic-children">
                            <span class="menu-item-text" data-bind="text: item.Title">
                            </span>
                        </span>
                    </a>
                    <ul id="menu" data-bind="foreach: children; visible: children.length>0" class="dynamic" >
                        <li class="dynamic">
                            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                                <span class="menu-item-text" data-bind="text: item.Title">
                                </span>
                            </a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
  6. 替换中加载的 URL 的开头,链接到网站集中的加载图像定位标记的图像。所做的更改后,重命名文件,然后将其上载到母版页样式库。这将生成新的.master 文件。

  7. 此 HTML 是从 JavaScript 代码返回的搜索结果将使用填充的基本标记。您将需要编辑以下代码以更改var root = “site collection URL的值,如下面的代码段所示:

    var root = “https://spperformance.sharepoint.com/sites/NavigationBySearch”;

    整个 JavaScript 文件如下所示:

    //Models and Namespaces
    var SPOCustom = SPOCustom || {};
    SPOCustom.Models = SPOCustom.Models || {}
    SPOCustom.Models.NavigationNode = function () {
    
        this.Url = ko.observable("");
        this.Title = ko.observable("");
        this.Parent = ko.observable("");
    
    };
    
    var root = "https://spperformance.sharepoint.com/sites/NavigationBySearch";
    var baseUrl = root + "/_api/search/query?querytext=";
    var query = baseUrl + "'contentClass=\"STS_Web\"+path:" + root + "'&trimduplicates=false&rowlimit=300";
    
    var baseRequest = {
        url: "",
        type: ""
    };
    
    
    //Parses a local object from JSON search result.
    function getNavigationFromDto(dto) {
        var item = new SPOCustom.Models.NavigationNode();
        if (dto != undefined) {
    
            var webTemplate = getSearchResultsValue(dto.Cells.results, 'WebTemplate');
    
            if (webTemplate != "APP") {
                item.Title(getSearchResultsValue(dto.Cells.results, 'Title')); //Key = Title
                item.Url(getSearchResultsValue(dto.Cells.results, 'Path')); //Key = Path
                item.Parent(getSearchResultsValue(dto.Cells.results, 'ParentLink')); //Key = ParentLink
            }
    
        }
        return item;
    }
    
    function getSearchResultsValue(results, key) {
    
        for (i = 0; i < results.length; i++) {
            if (results[i].Key == key) {
                return results[i].Value;
            }
        }
        return null;
    }
    
    //Parse a local object from the serialized cache.
    function getNavigationFromCache(dto) {
        var item = new SPOCustom.Models.NavigationNode();
    
        if (dto != undefined) {
    
            item.Title(dto.Title);
            item.Url(dto.Url);
            item.Parent(dto.Parent);
        }
    
        return item;
    }
    
    /* create a new OData request for JSON response */
    function getRequest(endpoint) {
        var request = baseRequest;
        request.type = "GET";
        request.url = endpoint;
        request.headers = { ACCEPT: "application/json;odata=verbose" };
        return request;
    };
    
    /* Navigation Module*/
    function NavigationViewModel() {
        "use strict";
        var self = this;
        self.nodes = ko.observableArray([]);
        self.hierarchy = ko.observableArray([]);;
        self.loadNavigatioNodes = function () {
            //Check local storage for cached navigation datasource.
            var fromStorage = localStorage["nodesCache"];
            if (false) {
                var cachedNodes = JSON.parse(localStorage["nodesCache"]);
    
                if (cachedNodes && timeStamp) {
                    //Check for cache expiration. Currently set to 3 hrs.
                    var now = new Date();
                    var diff = now.getTime() - timeStamp;
                    if (Math.round(diff / (1000 * 60 * 60)) < 3) {
    
                        //return from cache.
                        var cacheResults = [];
                        $.each(cachedNodes, function (i, item) {
                            var nodeitem = getNavigationFromCache(item, true);
                            cacheResults.push(nodeitem);
                        });
    
                        self.buildHierarchy(cacheResults);
                        self.toggleView();
                        addEventsToElements();
                        return;
                    }
                }
            }
            //No cache hit, REST call required.
            self.queryRemoteInterface();
        };
    
        //Executes a REST call and builds the navigation hierarchy.
        self.queryRemoteInterface = function () {
            var oDataRequest = getRequest(query);
            $.ajax(oDataRequest).done(function (data) {
                var results = [];
                $.each(data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results, function (i, item) {
    
                    if (i == 0) {
                        //Add root element.
                        var rootItem = new SPOCustom.Models.NavigationNode();
                        rootItem.Title("Root");
                        rootItem.Url(root);
                        rootItem.Parent(null);
                        results.push(rootItem);
                    }
                    var navItem = getNavigationFromDto(item);
                    results.push(navItem);
                });
                //Add to local cache
                localStorage["nodesCache"] = ko.toJSON(results);
    
                localStorage["nodesCachedAt"] = new Date().getTime();
                self.nodes(results);
                if (self.nodes().length > 0) {
                    var unsortedArray = self.nodes();
                    var sortedArray = unsortedArray.sort(self.sortObjectsInArray);
    
                    self.buildHierarchy(sortedArray);
                    self.toggleView();
                    addEventsToElements();
                }
            }).fail(function () {
                //Handle error here!!
                $("#loading").hide();
                $("#error").show();
            });
        };
        self.toggleView = function () {
            var navContainer = document.getElementById("navContainer");
            ko.applyBindings(self, navContainer);
            $("#loading").hide();
            $("#navContainer").show();
    
        };
        //Uses linq.js to build the navigation tree.
        self.buildHierarchy = function (enumerable) {
            self.hierarchy(Enumerable.From(enumerable).ByHierarchy(function (d) {
                return d.Parent() == null;
            }, function (parent, child) {
                if (parent.Url() == null || child.Parent() == null)
                    return false;
                return parent.Url().toUpperCase() == child.Parent().toUpperCase();
            }).ToArray());
    
            self.sortChildren(self.hierarchy()[0]);
        };
    
    
        self.sortChildren = function (parent) {
    
            // sjip processing if no children
            if (!parent || !parent.children || parent.children.length === 0) {
                return;
            }
    
            parent.children = parent.children.sort(self.sortObjectsInArray2);
    
            for (var i = 0; i < parent.children.length; i++) {
                var elem = parent.children[i];
    
                if (elem.children && elem.children.length > 0) {
                    self.sortChildren(elem);
                }
            }
        };
    
        // ByHierarchy method breaks the sorting in chrome and firefix 
        // we need to resort  as ascending
        self.sortObjectsInArray2 = function (a, b) {
            if (a.item.Title() > b.item.Title())
                return 1;
            if (a.item.Title() < b.item.Title())
                return -1;
            return 0;
        };
    
    
        self.sortObjectsInArray = function (a, b) {
            if (a.Title() > b.Title())
                return -1;
            if (a.Title() < b.Title())
                return 1;
            return 0;
        }
    }
    
    //Loads the navigation on load and binds the event handlers for mouse interaction.
    function InitCustomNav() {
        var viewModel = new NavigationViewModel();
        viewModel.loadNavigatioNodes();
    }
    
    function addEventsToElements() {
        //events.
        $("li.dynamic-children").mouseover(function () {
            var position = $(this).position();
            $(this).find("ul").css({ width: 125, left: position.left + 10, top: 50 });
    
        })
            .mouseout(function () {
                $(this).find("ul").css({ width: 0, left: -99999, top: 0 });
            });
    }
    
    _spBodyOnLoadFunctionNames.push("InitCustomNav");
    

    要汇总如上 jQuery $(document).ready函数中创建的viewModel对象,然后loadNavigationNodes()函数对该对象的代码称为。此函数或者加载 HTML5 本地存储的客户端浏览器中存储以前生成的导航层次结构或其呼叫函数queryRemoteInterface()。

    QueryRemoteInterface()生成getRequest()函数使用脚本更早版本中定义的查询参数的请求,并从服务器,则返回数据。此数据是实际上表示数据传输对象与各种属性为网站集内的所有网站数组。此数据是然后分析到以前定义的SPO.Models.NavigationNode对象 Knockout.js 用于创建可观察的属性,使用数据绑定到前面定义的 HTML 值。对象然后放到结果数组中。此数组到使用挖空 JSON 分析和存储在本地浏览器存储以在将来的页面加载提高性能。

  8. 接下来,结果将分配给self.nodes和层次结构构建利用使用 linq.js 分配给数组self.heirarchy的输出的对象。此数组为绑定到 HTML 的对象。这是toggleView()函数中通过将自我对象传递给ko.applyBinding()函数。然后,这会导致层次结构数组绑定到以下 HTML:

    <div data-bind=”foreach: hierarchy” class=”noindex ms-core-listMenu-horizontalBox”>

    最后, mouseenter和mouseexit事件处理程序添加到其addEventsToElements()函数中完成的处理子网站的下拉菜单的顶级导航。

    可以在屏幕截图下方看到导航的结果:

    导航结果的屏幕截图

    在我们的复杂导航示例全新页面加载不在服务器花费的时间本地缓存显示具有已剪切向下从准则结构导航,以获取为托管的导航方法类似的结果。

    SPRequestDuration 301 的屏幕截图

    这种方法的主要好处之一是,通过使用 HTML5 本地存储,导航存储在本地用户的下次他们加载页面。

我们从使用结构导航; 搜索 API 获取主要性能改进然而,它将某些技术的功能,以便执行和自定义此功能。示例实施工作结束后,在网站进行排序的框的结构导航; 相同的方式按字母顺序。如果您希望此顺序偏差,它会更复杂的开发和维护。此外,这种方法要求您偏离支持母版页。如果不保留自定义母版页,您的网站将会错过任何了解的更新和改进 Microsoft 对母版页。

上面的代码具有以下依赖项:

LinqJS 的当前版本不包含在上面的代码中使用 ByHierarchy 方法,并将中断导航代码。若要修复此错误,下面的方法向文件中添加 Linq.js 行前"采取恢复: 函数 ()"。

ByHierarchy: function(firstLevel, connectBy, orderBy, ascending, parent) {
     ascending = ascending == undefined ? true : ascending;
     var orderMethod = ascending == true ? 'OrderBy' : 'OrderByDescending';
     var source = this;
     firstLevel = Utils.CreateLambda(firstLevel);
     connectBy = Utils.CreateLambda(connectBy);
     orderBy = Utils.CreateLambda(orderBy);
    
     //Initiate or increase level
     var level = parent === undefined ? 1 : parent.level + 1;

    return new Enumerable(function() {
         var enumerator;
         var index = 0;

        var createLevel = function() {
                 var obj = {
                     item: enumerator.Current(),
                     level : level
                 };
                 obj.children = Enumerable.From(source).ByHierarchy(firstLevel, connectBy, orderBy, ascending, obj);
                 if (orderBy !== undefined) {
                     obj.children = obj.children[orderMethod](function(d) {
                         return orderBy(d.item); //unwrap the actual item for sort to work
                     });
                 }
                 obj.children = obj.children.ToArray();
                 Enumerable.From(obj.children).ForEach(function(child) {
                     child.getParent = function() {
                         return obj;
                     };
                 });
                 return obj;
             };

        return new IEnumerator(

        function() {
             enumerator = source.GetEnumerator();
         }, function() {
             while (enumerator.MoveNext()) {
                 var returnArr;
                 if (!parent) {
                     if (firstLevel(enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }

                } else {
                     if (connectBy(parent.item, enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }
                 }
             }
             return false;
         }, function() {
             Utils.Dispose(enumerator);
         })
     });
 },

注意: 机器翻译免责声明:本文是由无人工介入的计算机系统翻译的。Microsoft 提供机器翻译是为了帮助非英语国家/地区用户方便阅读有关 Microsoft 产品、服务和技术的内容。由于机器翻译的原因,本文可能包含词汇、语法或文法方面的错误。

扩展你的技能
了解培训
抢先获得新功能
加入 Office 预览体验计划

此信息是否有帮助?

谢谢您的反馈!

谢谢你的反馈! 可能需要转接到 Office 支持专员。

×