在HTML中实现比DocBook更好用的自动节编号

本文介绍了一种使用HTML和JavaScript自动生成文档目录的方法,通过自定义的levelIndexManager类和JQuery辅助,实现了比传统<ol>标签更灵活、易用的多级标题结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在HTML中,自动编号的标签是<ol>.

<p>我喜欢吃的水果有:</p> <ol> <li>西瓜</li> <li>苹果</li> <li>梨</li> </ol>

结果如下 :

我喜欢吃的水果有:

  1. 西瓜
  2. 苹果

看起来很简单。其实不然。假设我应邀写一篇如何赚钱的文章。下面是拟好的提纲。

1. 我们能赚钱吗
能。

2. 赚钱方法简介


2.1 当劳工
勤劳致富,大力推荐。

2.2 卖血
2.2.1 卖自己的血
只要撑得住,也是推荐的。

2.2.2 卖别人的血
别人若同意,我也不反对。

2.3 编程
2.3.1 外包
听说是个赚钱的好方法,但是,你要人家的钱,人家要你的命。

2.3.2 自己承接
最好先在Google上推销自己。

3. 努力赚钱,作明日之比尔盖茨
我要养家,要糊口,要当比尔盖茨!但如果人人这么想,比尔盖茨还能成为比尔盖茨了吗?

4. 结论

赚钱真难!

我用<ol>来实现:

<ol> <li>我们能赚钱吗 <p>能。</p> </li> <li>赚钱方法简介 <ol> <li>当劳工 <p>勤劳致富,大力推荐。</p> </li> <li>卖血 <ol> <li>卖自己的血 <p>只要撑得住,也是推荐的。</p> </li> <li>卖别人的血 <p>别人若同意,我也不反对。</p> </li> </ol> </li> <li>编程 <ol> <li>外包 <p>听说是个赚钱的好方法,但是,你要人家的钱,人家要你的命。</p> </li> <li>自己承接 <p>最好先在Google上推销自己。</p> </li> </ol> </li> </ol> </li> <li>努力赚钱,作明日之比尔盖茨 <p>我要养家,要糊口,要当比尔盖茨!但如果人人这么想,比尔盖茨还能成为比尔盖茨了吗?</p> </li> <li>结论 <p>赚钱真难!</p> </li> </ol>

其效果如下:

  1. 我们能赚钱吗

    能。

  2. 赚钱方法简介
    1. 当劳工

      勤劳致富,大力推荐。

    2. 卖血
      1. 卖自己的血

        只要撑得住,也是推荐的。

      2. 卖别人的血

        别人若同意,我也不反对。

    3. 编程
      1. 外包

        听说是个赚钱的好方法,但是,你要人家的钱,人家要你的命。

      2. 自己承接

        最好先在Google上推销自己。

  3. 努力赚钱,作明日之比尔盖茨

    我要养家,要糊口,要当比尔盖茨!但如果人人这么想,比尔盖茨还能成为比尔盖茨了吗?

  4. 结论

    赚钱真难!

可以看出,无论是从书写习惯上,还是效果上看,都不能取得较理想的效果。这是为什么我们很少看到别人<ol>使用来编排文章的原因。

DocBook中有专门解决此问题之道,主要通过<sect1>、<sect2>......<sect6>来实现。

<sect1> <title>赚钱方法简介</title> <para></para> <sect2> <title>卖血</title> <para></para> <sect3> <title>卖自己的血</title> <para></para> </sect3> </sect2> </sect1>

从结构上来看,比<ol>强赚钱方法简介多了。但DocBook也有一问题:如果我们要将<sect2>一级上升,除将<sect2>的内容移出<sect1>之外,还必须将<sect2>标签改为<sect1>。如果<sect2>又包括了众多的<sect3>、<sect4>等,则需对这些节一一变更。

下面,我们来实现一个比DocBook还更好用的类似小工具。仿造DocBook的结构,先编写下面的HTML代码。

<div class="sect"> <div class="sectTitle">我们能赚钱吗</div> <p>能。</p> </div> <div class="sect"> <div class="sectTitle">赚钱方法简介</div> <div class="sect"> <div class="sectTitle">当劳工</div> <p>勤劳致富,大力推荐。</p> </div> <div class="sect"> <div class="sectTitle">卖血</div> <div class="sect"> <div class="sectTitle">卖自己的血</div> <p>只要撑得住,也是推荐的。</p> </div> <div class="sect"> <div class="sectTitle">卖别人的血</div> <p>别人若同意,我也不反对。</p> </div> </div> <div class="sect"> <div class="sectTitle">编程</div> <div class="sect"> <div class="sectTitle">外包</div> <p>听说是个赚钱的好方法,但是,你要人家的钱,人家要你的命。</p> </div> <div class="sect"> <div class="sectTitle">自己承接</div> <p>最好先在Google上推销自己。</p> </div> </div> </div> <div class="sect"> <div class="sectTitle">努力赚钱,作明日之比尔盖茨</div> <p>我要养家,要糊口,要当比尔盖茨!但如果人人这么想,比尔盖茨还能成为比尔盖茨了吗?</p> </div> <div class="sect"> <div class="sectTitle">结论</div> <p>赚钱真难!</p> </div>

这种结构,我们不必关心各段具体是几级节点。因此若需重新调整结构,只须调整物理位置即可,无须修改div的class.

我们准备使用JQuery来助力。

<script type="text/javascript" src="http://www.google.com/jsapi"></script>

因为Google可以提供JQuery调用,因此只需直接调用其就行了,不必再虽行下载JQuery。为方便使用,我在下面创建了一个对象。

<script type="text/javascript"> var levelIndexManager = { levelStack : new Array(), base : 0, offset : 0, level : 1, getIndex : function() { //empty, init if (this.levelStack.length == 0) { this.base = 0; this.offset = 0; this.level = 1; this.levelStack.push(this.base); } if (this.level == 1) { this.base++; this.levelStack[this.levelStack.length - 1] = this.base; return this.levelStack[this.levelStack.length - 1]; } else { var valueSaved = this.levelStack[this.levelStack.length - 1]; this.offset++; this.levelStack[this.levelStack.length - 1] = this.base + "." + this.offset; return valueSaved; } }, levelUp : function() { if (this.level == 1) { this.base = this.levelStack[this.levelStack.length - 1]; } else { //need to substract offset by 1 var valueSaved = this.levelStack[this.levelStack.length - 1]; var lastPos = valueSaved.lastIndexOf("."); var theBase = valueSaved.substr(0, lastPos); var theOffset = valueSaved.substring(lastPos+1); theOffset--; this.base = theBase + "." + theOffset; } this.offset = 1; this.levelStack.push(this.base + "." + this.offset); this.level++; }, levelDown : function() { if (this.level == 1) { return; } this.level--; this.levelStack.pop(); if (this.level == 1) { this.base = this.levelStack[this.levelStack.length - 1]; return; } var valueSaved = this.levelStack[this.levelStack.length - 1]; var lastPos = valueSaved.lastIndexOf("."); this.base = valueSaved.substr(0, lastPos); this.offset = valueSaved.substring(lastPos+1); } }; </script>

定义了一个名为levelIndexManager类变量,此类的接口如下:

getIndex(): 返回各级节点的标签,如“1.”、“2.3.1”。

levelUp(): 调用此方法,告知levelIndexManager我们需要设置取得下一级节点标签,levelIndexManager自动在内部设置各级节点标签,之后使用getIndex()即可返回所需标签。

levelDown(): 调用此方法,告知levelIndexManager返还上一级节点标签,之后使用getIndex()即可返回所需标签。

有时候,我们还需用到levelIndexManager的level属性,以了解当前是第几级。

为方便使用,getIndex()方法中在第一次调用时会自动检查并初始化。

levelIndexManager主要利用JavaScript数组来实现堆栈功能。

关于levelIndexManager,我们仅需了解其接口方法就行,不必拘泥于细节。

紧随着levelIndexManager的定义,编写以下代码:

<script type="text/javascript"> google.load("jquery", "1"); google.setOnLoadCallback(function(){ processChain($("body")); }); function processChain(chainPrarent) { $.each($(chainPrarent).children(".sect"), function(){ var sperator = ""; if (levelIndexManager.level == 1) { sperator = ". "; } else { sperator = " "; } $(this).children(".sectTitle").text(levelIndexManager.getIndex() + sperator + $(this).children(".sectTitle").text()); levelIndexManager.levelUp(); processChain($(this)); levelIndexManager.levelDown(); }); } </script>

调用JQuery库后,待页面加载完毕,调用processChain()函数。此函数是实现本文功能的重点。功能不复杂,对于body之下每个sect,将其sectTitle取出,调用levelIndexManager.getIndex()以获取正确的节编号后,修改sectTitle的内容。难点在于如何告诉levelIndexManager,何时需要设置下一级节编号。函数的倒数第二行递归调用processChain()函数,以处理每个sect之下的子节点。因此,这是调用levelIndexManager.levelUp()的好时机。处理完子节点后,立即调用levelIndexManager.levelDown()返回上一级节点。而对于没有子节点的,processChain()立即返回。虽然此时levelUp()及levelDown()也被调用了,但没有关系,只要它们成对被调用,只不过多进行了一次进栈及出栈的动作而已,丝毫不影响节点编号的正确设置。

至此,我们成功地在HTML中实现了比DocBook还更好用的自动编排节标签的功能,使得我们在使用HTML写文章时更加便捷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值