用AngularJS指令生成目录

问题描述 投票:2回答:5

想象一个包含标题的html文本(h1-h6)。在我的情况下,它也是以DOM的形式存在于一个html页面中。因此,使用jQuery,我可以做这样的事情 $('.text').find('h1,h2,h3,h4,h5,h6') 来提取所有的标题。

但我不想使用jQuery或其他任何重型框架。请记住,我需要以正确的顺序来显示标题,使其成为一个目录。

javascript html angularjs dom angularjs-directive
5个回答
3
投票

所以这是我最终的解决方案。ng-model部分用于在文本更新时更新标题。

.directive('tableOfContents', function(){
    return {
        restrict:'A',
        require:'?ngModel',
        link : function(scope, elm, attrs,ngModel) {
            function updateHeadlines() {
                scope.headlines=[];
                angular.forEach(elm[0].querySelectorAll('h1,h2,h3,h4,h5,h6'), function(e){
                    scope.headlines.push({ 
                        level: e.tagName[1], 
                        label: angular.element(e).text(),
                        element: e
                    });
                });
            }
            // avoid memoryleaks from dom references
            scope.$on('$destroy',function(){
                scope.headlines=[];
            });
            // scroll to one of the headlines
            scope.scrollTo=function(headline){
                headline.element.scrollIntoView();
            }
            // when the html updates whe update the headlines
            ngModel.$render = updateHeadlines;
            updateHeadlines();
        }
    }
})

使用方法。

<a ng-repeat="headline in headlines" ng-click="scrollTo(headline)">{{headline.label}}</a>
<div table-of-contents ng-model="html">{{html}}</div>

1
投票

看一下这个库 - https:/www.cssscript.comgenerating-a-table-of-contents-with-pure-javascript-toc

你可以简单地将js代码放在你的控制器中,它将把所有的头文件放在一个id为#toc的标签下。

在你的html文件中创建

<div class="col-md-3 col-xs-12">
    <aside id="toc"></aside> <!-- Content will appear here -->
</div>
<div class="col-md-9 col-xs-12 no-padding">
    <div id="doc-content">
    ... Your content is here ...
</div>

然后在你的控制器中包含这个函数。例如,你可以在onInit中调用它。

loadTOC(){


    // Definitions
    var extendObj = function (src, target) {
      for (var prop in target) {
          if (target.hasOwnProperty(prop) && target[prop]) {
              src[prop] = target[prop];
          }
      }

      return src;
    };

    var getHeaders = function (selector, scope) {
        var ret = [];
        var target = document.querySelectorAll(scope);

        Array.prototype.forEach.call(target, function (elem) {
            var elems = elem.querySelectorAll(selector);
            ret = ret.concat(Array.prototype.slice.call(elems));
        });

        return ret;
    };

    var getLevel = function (header) {
        if (typeof header !== 'string') {
            return 0;
        }

        var decs = header.match(/\d/g);
        return decs ? Math.min.apply(null, decs) : 1;
    };

    var createList = function (wrapper, count) {
        while (count--) {
            wrapper = wrapper.appendChild(
                document.createElement('ol')
            );

            if (count) {
                wrapper = wrapper.appendChild(
                    document.createElement('li')
                );
            }
        }

        return wrapper;
    };

    var jumpBack = function (currentWrapper, offset) {
        while (offset--) {
            currentWrapper = currentWrapper.parentElement;
        }

        return currentWrapper;
    };

    var setAttrs = function (overwrite, prefix) {
        return function (src, target, index) {
            var content = src.textContent;
            var pre = prefix + '-' + index;
            target.textContent = content;

            var id = overwrite ? pre : (src.id || pre);

            id = encodeURIComponent(id);

            src.id = id;
            target.href = '#' + id;
        };
    };

    var buildTOC = function (options) {
        var selector = options.selector;
        var scope = options.scope;

        var ret = document.createElement('ol');
        var wrapper = ret;
        var lastLi = null;

        var _setAttrs = setAttrs(options.overwrite, options.prefix);

        getHeaders(selector, scope).reduce(function (prev, cur, index) {
            var currentLevel = getLevel(cur.tagName);
            var offset = currentLevel - prev;

            if (offset > 0) {
                wrapper = createList(lastLi, offset);
            }

            if (offset < 0) {
                wrapper = jumpBack(wrapper, -offset * 2);
            }

            wrapper = wrapper || ret;

            var li = document.createElement('li');
            var a = document.createElement('a');

            _setAttrs(cur, a, index);

            wrapper.appendChild(li).appendChild(a);

            lastLi = li;

            return currentLevel;
        }, getLevel(selector));

        return ret;
    };

    var initTOC = function (options) {
        var defaultOpts = {
            selector: 'h1, h2, h3, h4, h5, h6',
            scope: 'body',
            overwrite: false,
            prefix: 'toc'
        };

        options = extendObj(defaultOpts, options);

        var selector = options.selector;

        if (typeof selector !== 'string') {
            throw new TypeError('selector must be a string');
        }

        if (!selector.match(/^(?:h[1-6],?\s*)+$/g)) {
            throw new TypeError('selector must contains only h1-6');
        }

        return buildTOC(options);
      };

    // Generating the TOC 
    var container = document.querySelector('#toc');

    var toc = initTOC({
        selector: 'h1, h2',
        scope: '#doc-content', // you can specify here a tag where to look at 
        overwrite: false,
        prefix: 'toc'
    });

    container.appendChild(toc);
  }

0
投票

你很幸运,应该可以使用这个函数。angular.elements 几乎和你使用jQuery的方式完全一样。

angular.element('h1') 你会发现 h1 元素。


0
投票

Angular jqLite是你在这里的选择,但不要忘记.find()仅限于通过标签名进行查找。

检查这些 SO SO 答案,如果有帮助的话。


0
投票

你可以使用以下方法找到具有".text "类的元素。

angular.element(document.querySelectorAll(".text"));
© www.soinside.com 2019 - 2024. All rights reserved.